From 28a7f60741b8e92fb0fc05e1febd362b6d0eaef9 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 8 Jul 2012 00:51:38 +0000 Subject: [PATCH] Unbreak handling of descriptors opened with O_EXEC by fexecve(2). While here return EBADF for descriptors opened for writing (previously it was ETXTBSY). Add fgetvp_exec function which performs appropriate checks. PR: kern/169651 In collaboration with: kib Approved by: trasz (mentor) MFC after: 1 week --- sys/kern/kern_descrip.c | 13 ++++++++++--- sys/kern/kern_exec.c | 4 +++- sys/sys/file.h | 2 ++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d16746ad703e..a4b7580b3666 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -2340,11 +2340,11 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, /* * FREAD and FWRITE failure return EBADF as per POSIX. - * - * Only one flag, or 0, may be specified. */ if ((flags == FREAD && (fp->f_flag & FREAD) == 0) || - (flags == FWRITE && (fp->f_flag & FWRITE) == 0)) { + (flags == FWRITE && (fp->f_flag & FWRITE) == 0) || + (flags == (FREAD | FEXEC) && + (((fp->f_flag & flags) == 0) || ((fp->f_flag & FWRITE) != 0)))) { fdrop(fp, td); return (EBADF); } @@ -2444,6 +2444,13 @@ fgetvp_read(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) return (_fgetvp(td, fd, FREAD, rights, NULL, vpp)); } +int +fgetvp_exec(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) +{ + + return (_fgetvp(td, fd, FREAD | FEXEC, rights, NULL, vpp)); +} + #ifdef notyet int fgetvp_write(struct thread *td, int fd, cap_rights_t rights, diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 414a826e74b8..90f7311b8209 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -443,8 +443,10 @@ do_execve(td, args, mac_p) /* * Some might argue that CAP_READ and/or CAP_MMAP should also * be required here; such arguments will be entertained. + * + * Descriptors opened only with O_EXEC or O_RDONLY are allowed. */ - error = fgetvp_read(td, args->fd, CAP_FEXECVE, &binvp); + error = fgetvp_exec(td, args->fd, CAP_FEXECVE, &binvp); if (error) goto exec_fail; vfslocked = VFS_LOCK_GIANT(binvp->v_mount); diff --git a/sys/sys/file.h b/sys/sys/file.h index c4c6dbfc7a39..dc49895fa089 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -238,6 +238,8 @@ fo_chown_t invfo_chown; void finit(struct file *, u_int, short, void *, struct fileops *); int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp); +int fgetvp_exec(struct thread *td, int fd, cap_rights_t rights, + struct vnode **vpp); int fgetvp_rights(struct thread *td, int fd, cap_rights_t need, cap_rights_t *have, struct vnode **vpp); int fgetvp_read(struct thread *td, int fd, cap_rights_t rights,