Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -658,6 +658,9 @@ bool first; int error, i; + KASSERT(VOP_ISLOCKED(imgp->vp), + ("%s: vp %p is not locked", __func__, imgp->vp)); + base_addr = 0; first = true; @@ -924,8 +927,6 @@ KASSERT(phdr->p_type == PT_INTERP, ("%s: p_type %u != PT_INTERP", __func__, phdr->p_type)); - KASSERT(VOP_ISLOCKED(imgp->vp), - ("%s: vp %p is not locked", __func__, imgp->vp)); td = curthread; @@ -938,12 +939,10 @@ interp_name_len = phdr->p_filesz; if (phdr->p_offset > PAGE_SIZE || interp_name_len > PAGE_SIZE - phdr->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->p_offset, - UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, + UIO_SYSSPACE, IO_RANGELOCKED, td->td_ucred, NOCRED, NULL, td); if (error != 0) { free(interp, M_TEMP); @@ -1028,6 +1027,19 @@ bool free_interp; int error, i, n; + /* + * Avoid a possible deadlock if the current address space is destroyed + * and that address space maps the locked vnode. In the common case, + * the locked vnode's v_usecount is decremented but remains greater + * than zero. Consequently, the vnode lock is not needed by vrele(). + * However, in cases where the vnode lock is external, such as nullfs, + * v_usecount may become zero. + * + * The VV_TEXT flag prevents modifications to the executable while + * the vnode is unlocked. + */ + VOP_UNLOCK(imgp->vp, 0); + hdr = (const Elf_Ehdr *)imgp->image_header; /* @@ -1037,8 +1049,10 @@ * if particular brand doesn't support it. */ if (__elfN(check_header)(hdr) != 0 || - (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)) + (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)) { + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); return (-1); + } /* * From here on down, we return an errno, not -1, as we've @@ -1049,11 +1063,13 @@ (u_int)hdr->e_phentsize * hdr->e_phnum > PAGE_SIZE - hdr->e_phoff) { /* Only support headers in first page for now */ uprintf("Program headers not in the first page\n"); + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); return (ENOEXEC); } phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); if (!aligned(phdr, Elf_Addr)) { uprintf("Unaligned program headers\n"); + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); return (ENOEXEC); } @@ -1146,19 +1162,6 @@ } /* - * Avoid a possible deadlock if the current address space is destroyed - * and that address space maps the locked vnode. In the common case, - * the locked vnode's v_usecount is decremented but remains greater - * than zero. Consequently, the vnode lock is not needed by vrele(). - * However, in cases where the vnode lock is external, such as nullfs, - * v_usecount may become zero. - * - * The VV_TEXT flag prevents modifications to the executable while - * the vnode is unlocked. - */ - VOP_UNLOCK(imgp->vp, 0); - - /* * Decide whether to enable randomization of user mappings. * First, reset user preferences for the setid binaries. * Then, account for the support of the randomization by the @@ -1191,9 +1194,11 @@ } error = exec_new_vmspace(imgp, sv); + if (error != 0) + goto ret; + vmspace = imgp->proc->p_vmspace; map = &vmspace->vm_map; - imgp->proc->p_sysent = sv; maxv = vm_map_max(map) - lim_max(td, RLIMIT_STACK); @@ -1207,10 +1212,8 @@ } vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); - if (error != 0) - goto ret; - error = __elfN(load_sections)(imgp, hdr, phdr, et_dyn_addr, NULL); + VOP_UNLOCK(imgp->vp, 0); if (error != 0) goto ret; @@ -1240,7 +1243,6 @@ imgp->entry_addr = entry; if (interp != NULL) { - 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; @@ -1250,7 +1252,6 @@ } error = __elfN(load_interp)(imgp, brand_info, interp, &addr, &imgp->entry_addr); - vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); if (error != 0) goto ret; } else @@ -1281,6 +1282,7 @@ ret: if (free_interp) free(interp, M_TEMP); + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); return (error); } @@ -2536,14 +2538,11 @@ /* We need some limit, might as well use PAGE_SIZE. */ if (pnote == NULL || pnote->p_filesz > PAGE_SIZE) return (FALSE); - ASSERT_VOP_LOCKED(imgp->vp, "parse_notes"); if (pnote->p_offset > PAGE_SIZE || pnote->p_filesz > PAGE_SIZE - pnote->p_offset) { - VOP_UNLOCK(imgp->vp, 0); buf = malloc(pnote->p_filesz, M_TEMP, M_WAITOK); - vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); error = vn_rdwr(UIO_READ, imgp->vp, buf, pnote->p_filesz, - pnote->p_offset, UIO_SYSSPACE, IO_NODELOCKED, + pnote->p_offset, UIO_SYSSPACE, IO_RANGELOCKED, curthread->td_ucred, NOCRED, NULL, curthread); if (error != 0) { uprintf("i/o error PT_NOTE\n");