Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -88,7 +88,7 @@ static int __elfN(check_header)(const Elf_Ehdr *hdr); static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp, - const char *interp, int interp_name_len, int32_t *osrel, uint32_t *fctl0); + const char *interp, int32_t *osrel, uint32_t *fctl0); static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr, u_long *entry); static int __elfN(load_section)(struct image_params *imgp, vm_ooffset_t offset, @@ -272,13 +272,18 @@ static Elf_Brandinfo * __elfN(get_brandinfo)(struct image_params *imgp, const char *interp, - int interp_name_len, int32_t *osrel, uint32_t *fctl0) + int32_t *osrel, uint32_t *fctl0) { const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; Elf_Brandinfo *bi, *bi_m; boolean_t ret; - int i; + int i, interp_name_len; + if (interp != NULL) + interp_name_len = strlen(interp); + else + interp_name_len = 0; + /* * We support four types of branding -- (1) the ELF EI_OSABI field * that SCO added to the ELF spec, (2) FreeBSD 3.x's traditional string @@ -889,6 +894,61 @@ return (0); } +static int +__elfN(get_interp)(struct image_params *imgp, const Elf_Ehdr *hdr, + const Elf_Phdr *phdr, char **interpp, bool *free_interpp) +{ + struct thread *td; + char *interp; + int error, i, interp_name_len; + + td = curthread; + + for (i = 0; i < hdr->e_phnum; i++) { + if (phdr[i].p_type != PT_INTERP) + continue; + + /* Path to interpreter */ + if (phdr[i].p_filesz < 2 || phdr[i].p_filesz > MAXPATHLEN) { + uprintf("Invalid PT_INTERP\n"); + return (ENOEXEC); + } + + interp_name_len = phdr[i].p_filesz; + if (phdr[i].p_offset > PAGE_SIZE || + interp_name_len > PAGE_SIZE - phdr[i].p_offset) { + VOP_UNLOCK(imgp->vp, 0); + interp = malloc(interp_name_len + 1, M_TEMP, M_WAITOK); + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + error = vn_rdwr(UIO_READ, imgp->vp, interp, + interp_name_len, phdr[i].p_offset, + UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, + NOCRED, NULL, td); + if (error != 0) { + free(interp, M_TEMP); + uprintf("i/o error PT_INTERP %d\n", error); + return (error); + } + interp[interp_name_len] = '\0'; + *free_interpp = true; + } else { + interp = __DECONST(char *, imgp->image_header) + + phdr[i].p_offset; + if (interp[interp_name_len - 1] != '\0') { + uprintf("Invalid PT_INTERP\n"); + return (ENOEXEC); + } + *free_interpp = false; + } + *interpp = interp; + return (0); + } + + *interpp = NULL; + *free_interpp = false; + return (0); +} + /* * Impossible et_dyn_addr initial value indicating that the real base * must be calculated later with some randomization applied. @@ -905,7 +965,7 @@ struct vmspace *vmspace; vm_map_t map; const char *newinterp; - char *interp, *interp_buf, *path; + char *interp, *path; Elf_Brandinfo *brand_info; struct sysentvec *sv; vm_prot_t prot; @@ -913,7 +973,8 @@ u_long maxalign, mapsz, maxv, maxv1; uint32_t fctl0; int32_t osrel; - int error, i, n, interp_name_len, have_interp; + bool free_interp; + int error, i, n, have_interp; hdr = (const Elf_Ehdr *)imgp->image_header; @@ -949,9 +1010,7 @@ osrel = 0; fctl0 = 0; entry = proghdr = 0; - interp_name_len = 0; newinterp = NULL; - interp = interp_buf = NULL; td = curthread; maxalign = PAGE_SIZE; mapsz = 0; @@ -966,47 +1025,6 @@ mapsz += phdr[i].p_memsz; n++; break; - case PT_INTERP: - /* Path to interpreter */ - if (phdr[i].p_filesz < 2 || - phdr[i].p_filesz > MAXPATHLEN) { - uprintf("Invalid PT_INTERP\n"); - error = ENOEXEC; - goto ret; - } - if (interp != NULL) { - uprintf("Multiple PT_INTERP headers\n"); - error = ENOEXEC; - goto ret; - } - interp_name_len = phdr[i].p_filesz; - if (phdr[i].p_offset > PAGE_SIZE || - interp_name_len > PAGE_SIZE - phdr[i].p_offset) { - VOP_UNLOCK(imgp->vp, 0); - interp_buf = malloc(interp_name_len + 1, M_TEMP, - M_WAITOK); - vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); - error = vn_rdwr(UIO_READ, imgp->vp, interp_buf, - interp_name_len, phdr[i].p_offset, - UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, - NOCRED, NULL, td); - if (error != 0) { - uprintf("i/o error PT_INTERP %d\n", - error); - goto ret; - } - interp_buf[interp_name_len] = '\0'; - interp = interp_buf; - } else { - interp = __DECONST(char *, imgp->image_header) + - phdr[i].p_offset; - if (interp[interp_name_len - 1] != '\0') { - uprintf("Invalid PT_INTERP\n"); - error = ENOEXEC; - goto ret; - } - } - break; case PT_GNU_STACK: if (__elfN(nxstack)) imgp->stack_prot = @@ -1016,8 +1034,11 @@ } } - brand_info = __elfN(get_brandinfo)(imgp, interp, interp_name_len, - &osrel, &fctl0); + error = __elfN(get_interp)(imgp, hdr, phdr, &interp, &free_interp); + if (error != 0) + goto ret; + + brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel, &fctl0); if (brand_info == NULL) { uprintf("ELF binary type \"%u\" not known.\n", hdr->e_ident[EI_OSABI]); @@ -1238,7 +1259,8 @@ imgp->proc->p_elf_flags = hdr->e_flags; ret: - free(interp_buf, M_TEMP); + if (free_interp) + free(interp, M_TEMP); return (error); }