diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1150,6 +1150,31 @@ uap->mode)); } +static int +openflags(int flags, int *errorp) +{ + /* + * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags + * may be specified. On the other hand, for O_PATH any mode + * except O_EXEC is ignored. + */ + *errorp = 0; + if ((flags & O_PATH) != 0) { + flags &= ~O_ACCMODE; + } else if ((flags & O_EXEC) != 0) { + if (flags & O_ACCMODE) { + *errorp = EINVAL; + return (-1); + } + } else if ((flags & O_ACCMODE) == O_ACCMODE) { + *errorp = EINVAL; + return (-1); + } else { + flags = FFLAGS(flags); + } + return (flags); +} + /* * If fpp != NULL, opened file is not installed into the file * descriptor table, instead it is returned in *fpp. This is @@ -1179,21 +1204,9 @@ cap_rights_init_one(&rights, CAP_LOOKUP); flags_to_rights(flags, &rights); - /* - * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags - * may be specified. On the other hand, for O_PATH any mode - * except O_EXEC is ignored. - */ - if ((flags & O_PATH) != 0) { - flags &= ~O_ACCMODE; - } else if ((flags & O_EXEC) != 0) { - if (flags & O_ACCMODE) - return (EINVAL); - } else if ((flags & O_ACCMODE) == O_ACCMODE) { - return (EINVAL); - } else { - flags = FFLAGS(flags); - } + flags = openflags(flags, &error); + if (error != 0) + return (error); /* * Allocate a file structure. The descriptor to reference it @@ -4653,21 +4666,20 @@ struct vnode *vp; struct fhandle fhp; struct file *fp; - int fmode, error; - int indx; + int error, indx; bool named_attr; error = priv_check(td, PRIV_VFS_FHOPEN); if (error != 0) return (error); + indx = -1; - fmode = FFLAGS(flags); - /* why not allow a non-read/write open for our lockd? */ - if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT)) - return (EINVAL); + flags = openflags(flags, &error); + if (error != 0) + return (error); error = copyin(u_fhp, &fhp, sizeof(fhp)); if (error != 0) - return(error); + return (error); /* find the mount point */ mp = vfs_busyfs(&fhp.fh_fsid); if (mp == NULL) @@ -4685,8 +4697,8 @@ */ named_attr = (vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0; - if ((named_attr && (fmode & O_NAMEDATTR) == 0) || - (!named_attr && (fmode & O_NAMEDATTR) != 0)) { + if ((named_attr && (flags & O_NAMEDATTR) == 0) || + (!named_attr && (flags & O_NAMEDATTR) != 0)) { vput(vp); return (ENOATTR); } @@ -4704,7 +4716,7 @@ #ifdef INVARIANTS td->td_dupfd = -1; #endif - error = vn_open_vnode(vp, fmode, td->td_ucred, td, fp); + error = vn_open_vnode(vp, flags, td->td_ucred, td, fp); if (error != 0) { KASSERT(fp->f_ops == &badfileops, ("VOP_OPEN in fhopen() set f_ops")); @@ -4718,15 +4730,15 @@ td->td_dupfd = 0; #endif fp->f_vnode = vp; - finit_vnode(fp, fmode, NULL, &vnops); + finit_vnode(fp, flags, NULL, &vnops); VOP_UNLOCK(vp); - if ((fmode & O_TRUNC) != 0) { + if ((flags & O_TRUNC) != 0) { error = fo_truncate(fp, 0, td->td_ucred, td); if (error != 0) goto bad; } - error = finstall(td, fp, &indx, fmode, NULL); + error = finstall(td, fp, &indx, flags, NULL); bad: fdrop(fp, td); td->td_retval[0] = indx; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -432,6 +432,9 @@ accmode_t accmode; int error; + KASSERT((fmode & O_PATH) == 0 || (fmode & O_ACCMODE) == 0, + ("%s: O_PATH and O_ACCMODE are mutually exclusive", __func__)); + if (vp->v_type == VLNK) { if ((fmode & O_PATH) == 0 || (fmode & FEXEC) != 0) return (EMLINK);