imgact_elf: read program headers if not contained in the first page
PR: 295629 Reviewed by: markj Tested by: Alex S <iwtcex@gmail.com> Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D57294
This commit is contained in:
+62
-29
@@ -84,6 +84,8 @@
|
||||
#define ELF_NOTE_ROUNDSIZE 4
|
||||
#define OLD_EI_BRAND 8
|
||||
|
||||
#define ELF_OFFPAGE_PHNUM 128
|
||||
|
||||
/*
|
||||
* ELF_ABI_NAME is a string name of the ELF ABI. ELF_ABI_ID is used
|
||||
* to build variable names.
|
||||
@@ -93,7 +95,7 @@
|
||||
|
||||
static int __elfN(check_header)(const Elf_Ehdr *hdr);
|
||||
static const Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp,
|
||||
const char *interp, int32_t *osrel, uint32_t *fctl0);
|
||||
const Elf_Phdr *phdr, const char *interp, int32_t *osrel, uint32_t *fctl0);
|
||||
static int __elfN(load_file)(struct thread *td, const char *file, u_long *addr,
|
||||
u_long *entry);
|
||||
static int __elfN(load_section)(const struct image_params *imgp,
|
||||
@@ -103,7 +105,7 @@ static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp);
|
||||
static bool __elfN(freebsd_trans_osrel)(const Elf_Note *note,
|
||||
int32_t *osrel);
|
||||
static bool kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
static bool __elfN(check_note)(struct image_params *imgp,
|
||||
static bool __elfN(check_note)(struct image_params *imgp, const Elf_Phdr *phdr,
|
||||
const Elf_Brandnote *checknote, int32_t *osrel, bool *has_fctl0,
|
||||
uint32_t *fctl0);
|
||||
static vm_prot_t __elfN(trans_prot)(Elf_Word);
|
||||
@@ -339,8 +341,8 @@ __elfN(brand_inuse)(const Elf_Brandinfo *entry)
|
||||
}
|
||||
|
||||
static const Elf_Brandinfo *
|
||||
__elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
|
||||
int32_t *osrel, uint32_t *fctl0)
|
||||
__elfN(get_brandinfo)(struct image_params *imgp, const Elf_Phdr *phdr,
|
||||
const char *interp, int32_t *osrel, uint32_t *fctl0)
|
||||
{
|
||||
const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
|
||||
const Elf_Brandinfo *bi, *bi_m;
|
||||
@@ -369,8 +371,8 @@ __elfN(get_brandinfo)(struct image_params *imgp, const char *interp,
|
||||
has_fctl0 = false;
|
||||
*fctl0 = 0;
|
||||
*osrel = 0;
|
||||
ret = __elfN(check_note)(imgp, bi->brand_note, osrel,
|
||||
&has_fctl0, fctl0);
|
||||
ret = __elfN(check_note)(imgp, phdr, bi->brand_note,
|
||||
osrel, &has_fctl0, fctl0);
|
||||
/* Give brand a chance to veto check_note's guess */
|
||||
if (ret && bi->header_supported) {
|
||||
ret = bi->header_supported(imgp, osrel,
|
||||
@@ -787,12 +789,13 @@ __elfN(load_file)(struct thread *td, const char *file, u_long *addr,
|
||||
struct nameidata nd;
|
||||
struct vattr attr;
|
||||
struct image_params image_params;
|
||||
} *tempdata;
|
||||
} *tempdata = NULL;
|
||||
const Elf_Ehdr *hdr = NULL;
|
||||
const Elf_Phdr *phdr = NULL;
|
||||
struct nameidata *nd;
|
||||
struct vattr *attr;
|
||||
struct image_params *imgp;
|
||||
void *m_phdrs = NULL;
|
||||
u_long rbase;
|
||||
u_long base_addr = 0;
|
||||
int error;
|
||||
@@ -852,16 +855,27 @@ __elfN(load_file)(struct thread *td, const char *file, u_long *addr,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Only support headers that fit within first page for now */
|
||||
if (!__elfN(phdr_in_zero_page)(hdr)) {
|
||||
if (!aligned(imgp->image_header + hdr->e_phoff, Elf_Addr)) {
|
||||
error = ENOEXEC;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
|
||||
if (!aligned(phdr, Elf_Addr)) {
|
||||
error = ENOEXEC;
|
||||
goto fail;
|
||||
if (__elfN(phdr_in_zero_page)(hdr)) {
|
||||
phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
|
||||
} else {
|
||||
if (hdr->e_phnum > ELF_OFFPAGE_PHNUM) {
|
||||
error = ENOEXEC;
|
||||
goto fail;
|
||||
}
|
||||
VOP_UNLOCK(imgp->vp);
|
||||
phdr = m_phdrs = malloc(hdr->e_phnum * sizeof(Elf_Phdr),
|
||||
M_TEMP, M_WAITOK | M_ZERO);
|
||||
vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
|
||||
error = vn_rdwr(UIO_READ, imgp->vp, m_phdrs,
|
||||
hdr->e_phnum * sizeof(Elf_Phdr), hdr->e_phoff,
|
||||
UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred,
|
||||
NOCRED, NULL, imgp->td);
|
||||
if (error != 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = __elfN(load_sections)(imgp, hdr, phdr, rbase, &base_addr);
|
||||
@@ -883,6 +897,7 @@ __elfN(load_file)(struct thread *td, const char *file, u_long *addr,
|
||||
VOP_UNSET_TEXT_CHECKED(nd->ni_vp);
|
||||
vput(nd->ni_vp);
|
||||
}
|
||||
free(m_phdrs, M_TEMP);
|
||||
free(tempdata, M_TEMP);
|
||||
|
||||
return (error);
|
||||
@@ -1108,6 +1123,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
|
||||
char *interp;
|
||||
const Elf_Brandinfo *brand_info;
|
||||
struct sysentvec *sv;
|
||||
void *m_phdrs;
|
||||
u_long addr, baddr, entry, proghdr;
|
||||
u_long maxalign, maxsalign, mapsz, maxv, maxv1, anon_loc;
|
||||
uint32_t fctl0;
|
||||
@@ -1132,16 +1148,6 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
|
||||
* detected an ELF file.
|
||||
*/
|
||||
|
||||
if (!__elfN(phdr_in_zero_page)(hdr)) {
|
||||
uprintf("Program headers not in the first page\n");
|
||||
return (ENOEXEC);
|
||||
}
|
||||
phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
|
||||
if (!aligned(phdr, Elf_Addr)) {
|
||||
uprintf("Unaligned program headers\n");
|
||||
return (ENOEXEC);
|
||||
}
|
||||
|
||||
n = error = 0;
|
||||
baddr = 0;
|
||||
osrel = 0;
|
||||
@@ -1149,6 +1155,33 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
|
||||
entry = proghdr = 0;
|
||||
interp = NULL;
|
||||
free_interp = false;
|
||||
m_phdrs = NULL;
|
||||
|
||||
if (!aligned(imgp->image_header + hdr->e_phoff, Elf_Addr)) {
|
||||
uprintf("Unaligned program headers\n");
|
||||
return (ENOEXEC);
|
||||
}
|
||||
if (hdr->e_phoff + hdr->e_phnum * hdr->e_phentsize < hdr->e_phoff) {
|
||||
uprintf("PHDRS wrap\n");
|
||||
return (ENOEXEC);
|
||||
}
|
||||
if (__elfN(phdr_in_zero_page)(hdr)) {
|
||||
phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
|
||||
} else if (hdr->e_phnum > ELF_OFFPAGE_PHNUM) {
|
||||
uprintf("Too many program headers\n");
|
||||
return (ENOEXEC);
|
||||
} else {
|
||||
VOP_UNLOCK(imgp->vp);
|
||||
phdr = m_phdrs = malloc(hdr->e_phnum * sizeof(Elf_Phdr),
|
||||
M_TEMP, M_WAITOK | M_ZERO);
|
||||
vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
|
||||
error = vn_rdwr(UIO_READ, imgp->vp, m_phdrs,
|
||||
hdr->e_phnum * sizeof(Elf_Phdr), hdr->e_phoff,
|
||||
UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred,
|
||||
NOCRED, NULL, imgp->td);
|
||||
if (error != 0)
|
||||
goto ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Somewhat arbitrary, limit accepted max alignment for the
|
||||
@@ -1230,7 +1263,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
|
||||
}
|
||||
}
|
||||
|
||||
brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel, &fctl0);
|
||||
brand_info = __elfN(get_brandinfo)(imgp, phdr, interp, &osrel, &fctl0);
|
||||
if (brand_info == NULL) {
|
||||
uprintf("ELF binary type \"%u\" not known.\n",
|
||||
hdr->e_ident[EI_OSABI]);
|
||||
@@ -1434,6 +1467,7 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
|
||||
ASSERT_VOP_LOCKED(imgp->vp, "skipped relock");
|
||||
if (free_interp)
|
||||
free(interp, M_TEMP);
|
||||
free(m_phdrs, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@@ -2914,17 +2948,16 @@ note_fctl_cb(const Elf_Note *note, void *arg0, bool *res)
|
||||
* as for headers.
|
||||
*/
|
||||
static bool
|
||||
__elfN(check_note)(struct image_params *imgp, const Elf_Brandnote *brandnote,
|
||||
int32_t *osrel, bool *has_fctl0, uint32_t *fctl0)
|
||||
__elfN(check_note)(struct image_params *imgp, const Elf_Phdr *phdr,
|
||||
const Elf_Brandnote *brandnote, int32_t *osrel, bool *has_fctl0,
|
||||
uint32_t *fctl0)
|
||||
{
|
||||
const Elf_Phdr *phdr;
|
||||
const Elf_Ehdr *hdr;
|
||||
struct brandnote_cb_arg b_arg;
|
||||
struct fctl_cb_arg f_arg;
|
||||
int i, j;
|
||||
|
||||
hdr = (const Elf_Ehdr *)imgp->image_header;
|
||||
phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
|
||||
b_arg.brandnote = brandnote;
|
||||
b_arg.osrel = osrel;
|
||||
f_arg.has_fctl0 = has_fctl0;
|
||||
|
||||
Reference in New Issue
Block a user