aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2020-02-02 16:34:57 +0000
committerKyle Evans <kevans@FreeBSD.org>2020-02-02 16:34:57 +0000
commit6a5abb1ee5351d36de3b8589f8bf23fd2dfbb6da (patch)
treedb300f6040643046bb920b04cfb37a8576cec10d /sys
parentc887ac83245115c57c0b8df29ce5048122a88418 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c12
-rw-r--r--sys/fs/devfs/devfs_vnops.c4
-rw-r--r--sys/fs/fuse/fuse_vnops.c4
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c3
-rw-r--r--sys/fs/smbfs/smbfs_vnops.c3
-rw-r--r--sys/fs/tmpfs/tmpfs_vnops.c2
-rw-r--r--sys/kern/vfs_cache.c6
-rw-r--r--sys/kern/vfs_lookup.c19
-rw-r--r--sys/kern/vfs_subr.c12
-rw-r--r--sys/sys/fcntl.h2
-rw-r--r--sys/sys/namei.h3
-rw-r--r--sys/sys/vnode.h2
12 files changed, 54 insertions, 18 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
index 1c2856a224b34..26cce46bc92ea 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
@@ -1543,10 +1543,14 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct componentname *cnp,
* Check accessibility of directory.
*/
if (!cached) {
- error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr);
- if (error != 0) {
- ZFS_EXIT(zfsvfs);
- return (error);
+ if ((cnp->cn_flags & NOEXECCHECK) != 0) {
+ cnp->cn_flags &= ~NOEXECCHECK;
+ } else {
+ error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr);
+ if (error != 0) {
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
}
}
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 8f60bfc414c32..05b30a0630239 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -946,8 +946,8 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)
if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT))
return (EIO);
- error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td);
- if (error)
+ error = vn_dir_check_exec(dvp, cnp);
+ if (error != 0)
return (error);
if (cnp->cn_namelen == 1 && *pname == '.') {
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index f1b0fcbe7bdf3..05431a7706572 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -1006,7 +1006,9 @@ fuse_vnop_lookup(struct vop_lookup_args *ap)
if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP))
return EROFS;
- if ((err = fuse_internal_access(dvp, VEXEC, td, cred)))
+ if ((cnp->cn_flags & NOEXECCHECK) != 0)
+ cnp->cn_flags &= ~NOEXECCHECK;
+ else if ((err = fuse_internal_access(dvp, VEXEC, td, cred)))
return err;
if (flags & ISDOTDOT) {
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 63b1ab76975b9..9c929e9af3b5a 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1195,7 +1195,8 @@ nfs_lookup(struct vop_lookup_args *ap)
}
NFSUNLOCKNODE(np);
- if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0)
+ error = vn_dir_check_exec(dvp, cnp);
+ if (error != 0)
return (error);
error = cache_lookup(dvp, vpp, cnp, &nctime, &ncticks);
if (error > 0 && error != ENOENT)
diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c
index 3a0c207f685c0..026fab8d000c9 100644
--- a/sys/fs/smbfs/smbfs_vnops.c
+++ b/sys/fs/smbfs/smbfs_vnops.c
@@ -1199,7 +1199,8 @@ smbfs_lookup(ap)
islastcn = flags & ISLASTCN;
if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP))
return EROFS;
- if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0)
+ error = vn_dir_check_exec(dvp, cnp);
+ if (error != 0)
return error;
smp = VFSTOSMBFS(mp);
dnp = VTOSMB(dvp);
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 570c33c33491a..088258918d14e 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -90,7 +90,7 @@ tmpfs_lookup1(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
*vpp = NULLVP;
/* Check accessibility of requested node as a first step. */
- error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_thread);
+ error = vn_dir_check_exec(dvp, cnp);
if (error != 0)
goto out;
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index fecf749578e3b..f0026e1be18e9 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -2141,9 +2141,7 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
int error;
struct vnode **vpp = ap->a_vpp;
struct componentname *cnp = ap->a_cnp;
- struct ucred *cred = cnp->cn_cred;
int flags = cnp->cn_flags;
- struct thread *td = cnp->cn_thread;
*vpp = NULL;
dvp = ap->a_dvp;
@@ -2155,8 +2153,8 @@ vfs_cache_lookup(struct vop_lookup_args *ap)
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
return (EROFS);
- error = VOP_ACCESS(dvp, VEXEC, cred, td);
- if (error)
+ error = vn_dir_check_exec(dvp, cnp);
+ if (error != 0)
return (error);
error = cache_lookup(dvp, vpp, cnp, NULL, NULL);
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 265fd724d0f96..9e55c1426455d 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -308,6 +308,7 @@ namei(struct nameidata *ndp)
struct vnode *dp; /* the directory we are searching */
struct iovec aiov; /* uio for reading symbolic links */
struct componentname *cnp;
+ struct file *dfp;
struct thread *td;
struct proc *p;
cap_rights_t rights;
@@ -445,10 +446,22 @@ namei(struct nameidata *ndp)
AUDIT_ARG_ATFD1(ndp->ni_dirfd);
if (cnp->cn_flags & AUDITVNODE2)
AUDIT_ARG_ATFD2(ndp->ni_dirfd);
- error = fgetvp_rights(td, ndp->ni_dirfd,
- &rights, &ndp->ni_filecaps, &dp);
- if (error == EINVAL)
+ /*
+ * Effectively inlined fgetvp_rights, because we need to
+ * inspect the file as well as grabbing the vnode.
+ */
+ error = fget_cap_locked(fdp, ndp->ni_dirfd, &rights,
+ &dfp, &ndp->ni_filecaps);
+ if (error != 0 || dfp->f_ops == &badfileops ||
+ dfp->f_vnode == NULL) {
error = ENOTDIR;
+ } else {
+ dp = dfp->f_vnode;
+ vrefact(dp);
+
+ if ((dfp->f_flag & FSEARCH) != 0)
+ cnp->cn_flags |= NOEXECCHECK;
+ }
#ifdef CAPABILITIES
/*
* If file descriptor doesn't have all rights,
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 6f9d37d03ccd6..f9f1f0a541c63 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -6377,3 +6377,15 @@ __mnt_vnode_markerfree_lazy(struct vnode **mvp, struct mount *mp)
mtx_unlock(&mp->mnt_listmtx);
mnt_vnode_markerfree_lazy(mvp, mp);
}
+
+int
+vn_dir_check_exec(struct vnode *vp, struct componentname *cnp)
+{
+
+ if ((cnp->cn_flags & NOEXECCHECK) != 0) {
+ cnp->cn_flags &= ~NOEXECCHECK;
+ return (0);
+ }
+
+ return (VOP_ACCESS(vp, VEXEC, cnp->cn_cred, cnp->cn_thread));
+}
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index 55ba4220afefe..0febbcec5cd5b 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -119,9 +119,11 @@ typedef __pid_t pid_t;
#if __POSIX_VISIBLE >= 200809
#define O_DIRECTORY 0x00020000 /* Fail if not directory */
#define O_EXEC 0x00040000 /* Open for execute only */
+#define O_SEARCH O_EXEC
#endif
#ifdef _KERNEL
#define FEXEC O_EXEC
+#define FSEARCH O_SEARCH
#endif
#if __POSIX_VISIBLE >= 200809
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index bd5198bd936f5..602d7eff28b23 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -161,7 +161,8 @@ struct nameidata {
#define AUDITVNODE2 0x08000000 /* audit the looked up vnode information */
#define TRAILINGSLASH 0x10000000 /* path ended in a slash */
#define NOCAPCHECK 0x20000000 /* do not perform capability checks */
-#define PARAMASK 0x3ffffe00 /* mask of parameter descriptors */
+#define NOEXECCHECK 0x40000000 /* do not perform exec check on dir */
+#define PARAMASK 0x7ffffe00 /* mask of parameter descriptors */
/*
* Namei results flags
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 809427d00d15d..19c4930263db0 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -953,6 +953,8 @@ int vn_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
void vn_fsid(struct vnode *vp, struct vattr *va);
+int vn_dir_check_exec(struct vnode *vp, struct componentname *cnp);
+
#define VOP_UNLOCK_FLAGS(vp, flags) ({ \
struct vnode *_vp = (vp); \
int _flags = (flags); \