Index: sys/kern/imgact_elf.c =================================================================== --- sys/kern/imgact_elf.c +++ sys/kern/imgact_elf.c @@ -944,7 +944,6 @@ KASSERT(phdr->p_type == PT_INTERP, ("%s: p_type %u != PT_INTERP", __func__, phdr->p_type)); - ASSERT_VOP_LOCKED(imgp->vp, __func__); td = curthread; @@ -957,12 +956,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); @@ -1044,9 +1041,24 @@ u_long maxalign, mapsz, maxv, maxv1; uint32_t fctl0; int32_t osrel; - bool free_interp; + bool free_interp, locked; 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); + locked = false; + + free_interp = false; hdr = (const Elf_Ehdr *)imgp->image_header; /* @@ -1056,8 +1068,10 @@ * if particular brand doesn't support it. */ if (__elfN(check_header)(hdr) != 0 || - (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)) - return (-1); + (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)) { + error = -1; + goto ret; + } /* * From here on down, we return an errno, not -1, as we've @@ -1068,12 +1082,14 @@ (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"); - return (ENOEXEC); + error = ENOEXEC; + goto ret; } phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); if (!aligned(phdr, Elf_Addr)) { uprintf("Unaligned program headers\n"); - return (ENOEXEC); + error = ENOEXEC; + goto ret; } n = error = 0; @@ -1082,7 +1098,6 @@ fctl0 = 0; entry = proghdr = 0; interp = NULL; - free_interp = false; td = curthread; maxalign = PAGE_SIZE; mapsz = 0; @@ -1165,19 +1180,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 @@ -1226,6 +1228,7 @@ } vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + locked = true; if (error != 0) goto ret; @@ -1260,6 +1263,7 @@ if (interp != NULL) { VOP_UNLOCK(imgp->vp, 0); + locked = false; if ((map->flags & MAP_ASLR) != 0) { /* Assume that interpeter fits into 1/4 of AS */ maxv1 = maxv / 2 + addr / 2; @@ -1270,6 +1274,7 @@ error = __elfN(load_interp)(imgp, brand_info, interp, &addr, &imgp->entry_addr); vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + locked = true; if (error != 0) goto ret; } else @@ -1300,6 +1305,8 @@ ret: if (free_interp) free(interp, M_TEMP); + if (!locked) + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); return (error); } @@ -2555,14 +2562,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");