Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F165211439
D57294.id178825.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D57294.id178825.diff
View Options
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -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,8 +95,8 @@
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);
-static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr,
+ 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,
vm_ooffset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz,
@@ -103,7 +105,7 @@
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 @@
}
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 @@
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,
@@ -780,19 +782,20 @@
* the entry point for the loaded file.
*/
static int
-__elfN(load_file)(struct proc *p, const char *file, u_long *addr,
- u_long *entry)
+__elfN(load_file)(struct thread *td, const char *file, u_long *addr,
+ u_long *entry)
{
struct {
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;
@@ -802,7 +805,7 @@
* XXXJA: This check can go away once we are sufficiently confident
* that the checks in namei() are correct.
*/
- if (IN_CAPABILITY_MODE(curthread))
+ if (IN_CAPABILITY_MODE(td))
return (ECAPMODE);
#endif
@@ -814,7 +817,8 @@
/*
* Initialize part of the common data
*/
- imgp->proc = p;
+ imgp->td = td;
+ imgp->proc = td->td_proc;
imgp->attr = attr;
NDINIT(nd, LOOKUP, ISOPEN | FOLLOW | LOCKSHARED | LOCKLEAF,
@@ -851,24 +855,35 @@
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);
if (error != 0)
goto fail;
- if (p->p_sysent->sv_protect != NULL)
- p->p_sysent->sv_protect(imgp, SVP_INTERP);
+ if (imgp->proc->p_sysent->sv_protect != NULL)
+ imgp->proc->p_sysent->sv_protect(imgp, SVP_INTERP);
*addr = base_addr;
*entry = (unsigned long)hdr->e_entry + rbase;
@@ -882,6 +897,7 @@
VOP_UNSET_TEXT_CHECKED(nd->ni_vp);
vput(nd->ni_vp);
}
+ free(m_phdrs, M_TEMP);
free(tempdata, M_TEMP);
return (error);
@@ -1008,7 +1024,6 @@
__elfN(get_interp)(struct image_params *imgp, const Elf_Phdr *phdr,
char **interpp, bool *free_interpp)
{
- struct thread *td;
char *interp;
int error, interp_name_len;
@@ -1016,8 +1031,6 @@
("%s: p_type %u != PT_INTERP", __func__, phdr->p_type));
ASSERT_VOP_LOCKED(imgp->vp, __func__);
- td = curthread;
-
/* Path to interpreter */
if (phdr->p_filesz < 2 || phdr->p_filesz > MAXPATHLEN) {
uprintf("Invalid PT_INTERP\n");
@@ -1045,8 +1058,8 @@
error = vn_rdwr(UIO_READ, imgp->vp, interp,
interp_name_len, phdr->p_offset,
- UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
- NOCRED, NULL, td);
+ UIO_SYSSPACE, IO_NODELOCKED, imgp->td->td_ucred,
+ NOCRED, NULL, imgp->td);
if (error != 0) {
free(interp, M_TEMP);
uprintf("i/o error PT_INTERP %d\n", error);
@@ -1079,13 +1092,13 @@
if (brand_info->interp_newpath != NULL &&
(brand_info->interp_path == NULL ||
strcmp(interp, brand_info->interp_path) == 0)) {
- error = __elfN(load_file)(imgp->proc,
+ error = __elfN(load_file)(imgp->td,
brand_info->interp_newpath, addr, entry);
if (error == 0)
return (0);
}
- error = __elfN(load_file)(imgp->proc, interp, addr, entry);
+ error = __elfN(load_file)(imgp->td, interp, addr, entry);
if (error == 0)
return (0);
@@ -1102,7 +1115,6 @@
static int
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
{
- struct thread *td;
const Elf_Ehdr *hdr;
const Elf_Phdr *phdr;
Elf_Auxargs *elf_auxargs;
@@ -1111,6 +1123,7 @@
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;
@@ -1135,16 +1148,6 @@
* 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;
@@ -1152,7 +1155,33 @@
entry = proghdr = 0;
interp = NULL;
free_interp = false;
- td = curthread;
+ 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
@@ -1234,7 +1263,7 @@
}
}
- 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]);
@@ -1329,7 +1358,7 @@
map = &vmspace->vm_map;
maxv = sv->sv_usrstack;
if ((imgp->map_flags & MAP_ASLR_STACK) == 0)
- maxv -= lim_max(td, RLIMIT_STACK);
+ maxv -= lim_max(imgp->td, RLIMIT_STACK);
if (error == 0 && mapsz >= maxv - vm_map_min(map)) {
uprintf("Excessive mapping size\n");
error = ENOEXEC;
@@ -1339,7 +1368,7 @@
KASSERT((map->flags & MAP_ASLR) != 0,
("ET_DYN_ADDR_RAND but !MAP_ASLR"));
error = __CONCAT(rnd_, __elfN(base))(map,
- vm_map_min(map) + mapsz + lim_max(td, RLIMIT_DATA),
+ vm_map_min(map) + mapsz + lim_max(imgp->td, RLIMIT_DATA),
/* reserve half of the address space to interpreter */
maxv / 2, maxalign, &imgp->et_dyn_addr);
}
@@ -1362,7 +1391,7 @@
* calculation is that it leaves room for the heap to grow to
* its maximum allowed size.
*/
- addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(td,
+ addr = round_page((vm_offset_t)vmspace->vm_daddr + lim_max(imgp->td,
RLIMIT_DATA));
if ((map->flags & MAP_ASLR) != 0) {
maxv1 = maxv / 2 + addr / 2;
@@ -1438,6 +1467,7 @@
ASSERT_VOP_LOCKED(imgp->vp, "skipped relock");
if (free_interp)
free(interp, M_TEMP);
+ free(m_phdrs, M_TEMP);
return (error);
}
@@ -2809,7 +2839,7 @@
}
error = vn_rdwr(UIO_READ, imgp->vp, buf, pnote->p_filesz,
pnote->p_offset, UIO_SYSSPACE, IO_NODELOCKED,
- curthread->td_ucred, NOCRED, NULL, curthread);
+ imgp->td->td_ucred, NOCRED, NULL, imgp->td);
if (error != 0) {
uprintf("i/o error PT_NOTE\n");
goto retf;
@@ -2918,17 +2948,16 @@
* 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;
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -448,6 +448,7 @@
*/
bzero(imgp, sizeof(*imgp));
imgp->proc = p;
+ imgp->td = td;
imgp->attr = &attr;
imgp->args = args;
oldcred = p->p_ucred;
diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h
--- a/sys/sys/imgact.h
+++ b/sys/sys/imgact.h
@@ -57,6 +57,7 @@
struct image_params {
struct proc *proc; /* our process */
+ struct thread *td;
struct label *execlabel; /* optional exec label */
struct vnode *vp; /* pointer to vnode of file to exec */
struct vm_object *object; /* The vm object for this vp */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Aug 7, 8:49 PM (1 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36195544
Default Alt Text
D57294.id178825.diff (10 KB)
Attached To
Mode
D57294: imgact_elf: read program headers if not contained in the first page
Attached
Detach File
Event Timeline
Log In to Comment