Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -945,6 +945,80 @@ return (0); } +static int +__elfN(load_interp)(struct image_params *imgp, const Elf_Brandinfo *brand_info, + const char *interp, u_long maxv, u_long *addrp) +{ + struct vmspace *vmspace; + const char *newinterp; + char *path; + vm_map_t map; + u_long addr, maxv1; + int error; + + vmspace = imgp->proc->p_vmspace; + map = &vmspace->vm_map; + + if (interp != NULL && brand_info->interp_newpath != NULL) + newinterp = brand_info->interp_newpath; + else + newinterp = NULL; + + /* + * We load the dynamic linker where a userland call to mmap(0, ...) + * would put it. The rationale behind this 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(curthread, + RLIMIT_DATA)); + if ((map->flags & MAP_ASLR) != 0) { + maxv1 = maxv / 2 + addr / 2; + MPASS(maxv1 >= addr); /* No overflow */ + map->anon_loc = __CONCAT(rnd_, __elfN(base))(map, addr, maxv1, + MAXPAGESIZES > 1 ? pagesizes[1] : pagesizes[0]); + } else { + map->anon_loc = addr; + } + + VOP_UNLOCK(imgp->vp, 0); + if ((map->flags & MAP_ASLR) != 0) { + /* Assume that interpeter fits into 1/4 of AS */ + maxv1 = maxv / 2 + addr / 2; + MPASS(maxv1 >= addr); /* No overflow */ + addr = __CONCAT(rnd_, __elfN(base))(map, addr, + maxv1, PAGE_SIZE); + } + if (brand_info->emul_path != NULL && + brand_info->emul_path[0] != '\0') { + path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + snprintf(path, MAXPATHLEN, "%s%s", + brand_info->emul_path, interp); + error = __elfN(load_file)(imgp->proc, path, &addr, + &imgp->entry_addr); + free(path, M_TEMP); + if (error == 0) + goto done; + } + if (newinterp != NULL && (brand_info->interp_path == NULL || + strcmp(interp, brand_info->interp_path) == 0)) { + error = __elfN(load_file)(imgp->proc, newinterp, &addr, + &imgp->entry_addr); + if (error == 0) + goto done; + } + error = __elfN(load_file)(imgp->proc, interp, &addr, + &imgp->entry_addr); +done: + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) { + uprintf("ELF interpreter %s not found, error %d\n", + interp, error); + } + + *addrp = addr; + return (error); +} + /* * Impossible et_dyn_addr initial value indicating that the real base * must be calculated later with some randomization applied. @@ -960,17 +1034,16 @@ Elf_Auxargs *elf_auxargs; struct vmspace *vmspace; vm_map_t map; - const char *newinterp; - char *interp, *path; + char *interp; Elf_Brandinfo *brand_info; struct sysentvec *sv; vm_prot_t prot; u_long addr, baddr, et_dyn_addr, entry, proghdr; - u_long maxalign, mapsz, maxv, maxv1; + u_long maxalign, mapsz, maxv; uint32_t fctl0; int32_t osrel; bool free_interp; - int error, i, n, have_interp; + int error, i, n; hdr = (const Elf_Ehdr *)imgp->image_header; @@ -1006,7 +1079,7 @@ osrel = 0; fctl0 = 0; entry = proghdr = 0; - newinterp = interp = NULL; + interp = NULL; free_interp = false; td = curthread; maxalign = PAGE_SIZE; @@ -1074,8 +1147,6 @@ et_dyn_addr = ET_DYN_LOAD_ADDR; } } - if (interp != NULL && brand_info->interp_newpath != NULL) - newinterp = brand_info->interp_newpath; /* * Avoid a possible deadlock if the current address space is destroyed @@ -1180,64 +1251,13 @@ entry = (u_long)hdr->e_entry + et_dyn_addr; - /* - * We load the dynamic linker where a userland call - * to mmap(0, ...) would put it. The rationale behind this - * 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, - RLIMIT_DATA)); - if ((map->flags & MAP_ASLR) != 0) { - maxv1 = maxv / 2 + addr / 2; - MPASS(maxv1 >= addr); /* No overflow */ - map->anon_loc = __CONCAT(rnd_, __elfN(base))(map, addr, maxv1, - MAXPAGESIZES > 1 ? pagesizes[1] : pagesizes[0]); - } else { - map->anon_loc = addr; - } - imgp->entry_addr = entry; if (interp != NULL) { - have_interp = FALSE; - VOP_UNLOCK(imgp->vp, 0); - if ((map->flags & MAP_ASLR) != 0) { - /* Assume that interpeter fits into 1/4 of AS */ - maxv1 = maxv / 2 + addr / 2; - MPASS(maxv1 >= addr); /* No overflow */ - addr = __CONCAT(rnd_, __elfN(base))(map, addr, - maxv1, PAGE_SIZE); - } - if (brand_info->emul_path != NULL && - brand_info->emul_path[0] != '\0') { - path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - snprintf(path, MAXPATHLEN, "%s%s", - brand_info->emul_path, interp); - error = __elfN(load_file)(imgp->proc, path, &addr, - &imgp->entry_addr); - free(path, M_TEMP); - if (error == 0) - have_interp = TRUE; - } - if (!have_interp && newinterp != NULL && - (brand_info->interp_path == NULL || - strcmp(interp, brand_info->interp_path) == 0)) { - error = __elfN(load_file)(imgp->proc, newinterp, &addr, - &imgp->entry_addr); - if (error == 0) - have_interp = TRUE; - } - if (!have_interp) { - error = __elfN(load_file)(imgp->proc, interp, &addr, - &imgp->entry_addr); - } - vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); - if (error != 0) { - uprintf("ELF interpreter %s not found, error %d\n", - interp, error); + error = __elfN(load_interp)(imgp, brand_info, interp, maxv, + &addr); + if (error != 0) goto ret; - } } else addr = et_dyn_addr;