diff --git a/lib/libc/sys/open.2 b/lib/libc/sys/open.2 --- a/lib/libc/sys/open.2 +++ b/lib/libc/sys/open.2 @@ -334,9 +334,6 @@ .It Xr close 2 .It Xr fstat 2 .It Xr fexecve 2 -requires that -.Dv O_EXEC -was also specified at open time .It Dv SCM_RIGHTS can be passed over a .Xr unix 4 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 @@ -434,6 +434,7 @@ int error, i, orig_osrel; uint32_t orig_fctl0; Elf_Brandinfo *orig_brandinfo; + struct file *fp; size_t freepath_size; static const char fexecv_proc_title[] = "(fexecv)"; @@ -530,19 +531,31 @@ } } else { AUDIT_ARG_FD(args->fd); - /* - * Descriptors opened only with O_EXEC or O_RDONLY are allowed. - */ - error = fgetvp_exec(td, args->fd, &cap_fexecve_rights, - &newtextvp); - if (error) + error = getvnode_path(td, args->fd, &cap_fexecve_rights, &fp); + if (error != 0) goto exec_fail; + if (fp->f_ops != &path_fileops) { + /* + * Descriptors opened only with O_EXEC or + * O_RDONLY are allowed. + */ + if ((fp->f_flag & (FREAD | FEXEC)) == 0 || + ((fp->f_flag & FWRITE) != 0)) + error = EBADF; + if (error != 0) { + fdrop(fp, td); + goto exec_fail; + } + } + newtextvp = fp->f_vnode; if (vn_fullpath(newtextvp, &imgp->execpath, &imgp->freepath) != 0) imgp->execpath = args->fname; vn_lock(newtextvp, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(newtextvp); imgp->vp = newtextvp; + vref(newtextvp); + fdrop(fp, td); } /* @@ -881,7 +894,7 @@ /* * Store the vp for use in kern.proc.pathname. This vnode was - * referenced by namei() or fgetvp_exec(). + * referenced by namei() or by fexecve variant of fname handling. */ oldtextvp = p->p_textvp; p->p_textvp = newtextvp;