Page MenuHomeFreeBSD

D23247.id67657.diff
No OneTemporary

D23247.id67657.diff

Index: contrib/netbsd-tests/lib/libc/c063/t_o_search.c
===================================================================
--- contrib/netbsd-tests/lib/libc/c063/t_o_search.c
+++ contrib/netbsd-tests/lib/libc/c063/t_o_search.c
@@ -33,9 +33,10 @@
#include <atf-c.h>
-#include <sys/param.h>
+#include <sys/types.h>
#include <sys/stat.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -50,7 +51,7 @@
* until a decision is reached about the semantics of O_SEARCH and a
* non-broken implementation is available.
*/
-#if (O_MASK & O_SEARCH) != 0
+#if defined(__FreeBSD__) || (O_MASK & O_SEARCH) != 0
#define USE_O_SEARCH
#endif
@@ -257,11 +258,79 @@
int fd;
ATF_REQUIRE(mkdir(DIR, 0755) == 0);
+#ifndef __FreeBSD__
ATF_REQUIRE((dfd = open(FILE, O_CREAT|O_RDWR|O_SEARCH, 0644)) != -1);
+#else
+ ATF_REQUIRE((dfd = open(FILE, O_CREAT|O_SEARCH, 0644)) != -1);
+#endif
ATF_REQUIRE((fd = openat(dfd, BASEFILE, O_RDWR, 0)) == -1);
ATF_REQUIRE(errno == ENOTDIR);
}
+#ifdef USE_O_SEARCH
+ATF_TC(o_search_nord);
+ATF_TC_HEAD(o_search_nord, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "See that openat succeeds with no read permission");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(o_search_nord, tc)
+{
+ int dfd, fd;
+
+ ATF_REQUIRE(mkdir(DIR, 0755) == 0);
+ ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
+ ATF_REQUIRE(close(fd) == 0);
+
+ ATF_REQUIRE(chmod(DIR, 0100) == 0);
+ ATF_REQUIRE((dfd = open(DIR, O_SEARCH, 0)) != -1);
+
+ ATF_REQUIRE(faccessat(dfd, BASEFILE, W_OK, 0) != -1);
+
+ ATF_REQUIRE(close(dfd) == 0);
+}
+
+ATF_TC(o_search_getdents);
+ATF_TC_HEAD(o_search_getdents, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "See that O_SEARCH forbids getdents");
+}
+ATF_TC_BODY(o_search_getdents, tc)
+{
+ char buf[1024];
+ int dfd;
+
+ ATF_REQUIRE(mkdir(DIR, 0755) == 0);
+ ATF_REQUIRE((dfd = open(DIR, O_SEARCH, 0)) != -1);
+ ATF_REQUIRE(getdents(dfd, buf, sizeof(buf)) < 0);
+ ATF_REQUIRE(close(dfd) == 0);
+}
+
+ATF_TC(o_search_revokex);
+ATF_TC_HEAD(o_search_revokex, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "See that *at behaves after chmod -x");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(o_search_revokex, tc)
+{
+ int dfd, fd;
+ struct stat sb;
+
+ ATF_REQUIRE(mkdir(DIR, 0755) == 0);
+ ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1);
+ ATF_REQUIRE(close(fd) == 0);
+
+ ATF_REQUIRE((dfd = open(DIR, O_SEARCH, 0)) != -1);
+
+ /* Drop permissions. The kernel must still not check the exec bit. */
+ ATF_REQUIRE(chmod(DIR, 0000) == 0);
+ ATF_REQUIRE(fstatat(dfd, BASEFILE, &sb, 0) == 0);
+
+ ATF_REQUIRE(close(dfd) == 0);
+}
+#endif /* USE_O_SEARCH */
+
ATF_TP_ADD_TCS(tp)
{
@@ -276,6 +345,11 @@
ATF_TP_ADD_TC(tp, o_search_unpriv_flag2);
#endif
ATF_TP_ADD_TC(tp, o_search_notdir);
+#ifdef USE_O_SEARCH
+ ATF_TP_ADD_TC(tp, o_search_nord);
+ ATF_TP_ADD_TC(tp, o_search_getdents);
+ ATF_TP_ADD_TC(tp, o_search_revokex);
+#endif
return atf_no_error();
}
Index: lib/libc/sys/open.2
===================================================================
--- lib/libc/sys/open.2
+++ lib/libc/sys/open.2
@@ -28,7 +28,7 @@
.\" @(#)open.2 8.2 (Berkeley) 11/16/93
.\" $FreeBSD$
.\"
-.Dd September 28, 2019
+.Dd January 31, 2020
.Dt OPEN 2
.Os
.Sh NAME
@@ -166,6 +166,7 @@
O_WRONLY open for writing only
O_RDWR open for reading and writing
O_EXEC open for execute only
+O_SEARCH open for search only, an alias for O_EXEC
O_NONBLOCK do not block on open
O_APPEND append on each write
O_CREAT create file if it does not exist
@@ -326,6 +327,19 @@
allows arbitrary prefix that ends up at the topping directory,
after which all further resolved components must be under it.
.Pp
+When
+.Fa fd
+is opened with
+.Dv O_SEARCH ,
+execute permissions are checked at open time.
+The
+.Fa fd
+may not be used for any read operations like
+.Xr getdirentries 2 .
+The primary use for this descriptor will be as the lookup descriptor for the
+.Fn *at
+family of functions.
+.Pp
If successful,
.Fn open
returns a non-negative integer, termed a file descriptor.
@@ -518,9 +532,12 @@
of
.Dv O_RDONLY ,
.Dv O_WRONLY ,
-.Dv O_RDWR
+or
+.Dv O_RDWR ,
and
-.Dv O_EXEC .
+.Dv O_EXEC
+or
+.Dv O_SEARCH .
.It Bq Er EBADF
The
.Fa path
Index: lib/libc/tests/c063/Makefile
===================================================================
--- lib/libc/tests/c063/Makefile
+++ lib/libc/tests/c063/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-#TODO: t_o_search
-
NETBSD_ATF_TESTS_C= faccessat_test
NETBSD_ATF_TESTS_C+= fchmodat_test
NETBSD_ATF_TESTS_C+= fchownat_test
@@ -11,6 +9,7 @@
NETBSD_ATF_TESTS_C+= mkdirat_test
NETBSD_ATF_TESTS_C+= mkfifoat_test
NETBSD_ATF_TESTS_C+= mknodat_test
+NETBSD_ATF_TESTS_C+= o_search_test
NETBSD_ATF_TESTS_C+= openat_test
NETBSD_ATF_TESTS_C+= readlinkat_test
NETBSD_ATF_TESTS_C+= renameat_test
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
@@ -1470,7 +1470,7 @@
/* ARGSUSED */
static int
zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct componentname *cnp,
- int nameiop, cred_t *cr, kthread_t *td, int flags)
+ int nameiop, cred_t *cr, kthread_t *td, int flags, boolean_t cached)
{
znode_t *zdp = VTOZ(dvp);
znode_t *zp;
@@ -1542,9 +1542,16 @@
/*
* Check accessibility of directory.
*/
- if (error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr)) {
- ZFS_EXIT(zfsvfs);
- return (error);
+ if (!cached) {
+ 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);
+ }
+ }
}
if (zfsvfs->z_utf8 && u8_validate(nm, strlen(nm),
@@ -4894,12 +4901,7 @@
}
static int
-zfs_freebsd_lookup(ap)
- struct vop_lookup_args /* {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- } */ *ap;
+zfs_freebsd_lookup(struct vop_lookup_args *ap, boolean_t cached)
{
struct componentname *cnp = ap->a_cnp;
char nm[NAME_MAX + 1];
@@ -4908,7 +4910,14 @@
strlcpy(nm, cnp->cn_nameptr, MIN(cnp->cn_namelen + 1, sizeof(nm)));
return (zfs_lookup(ap->a_dvp, nm, ap->a_vpp, cnp, cnp->cn_nameiop,
- cnp->cn_cred, cnp->cn_thread, 0));
+ cnp->cn_cred, cnp->cn_thread, 0, cached));
+}
+
+static int
+zfs_freebsd_cachedlookup(struct vop_cachedlookup_args *ap)
+{
+
+ return (zfs_freebsd_lookup((struct vop_lookup_args *)ap, B_TRUE));
}
static int
@@ -4925,7 +4934,7 @@
if (zfsvfs->z_use_namecache)
return (vfs_cache_lookup(ap));
else
- return (zfs_freebsd_lookup(ap));
+ return (zfs_freebsd_lookup(ap, B_FALSE));
}
static int
@@ -5507,7 +5516,7 @@
ZFS_ENTER(zfsvfs);
error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td,
- LOOKUP_XATTR);
+ LOOKUP_XATTR, B_FALSE);
if (error != 0) {
ZFS_EXIT(zfsvfs);
return (error);
@@ -5576,7 +5585,7 @@
ZFS_ENTER(zfsvfs);
error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td,
- LOOKUP_XATTR);
+ LOOKUP_XATTR, B_FALSE);
if (error != 0) {
ZFS_EXIT(zfsvfs);
return (error);
@@ -5644,7 +5653,7 @@
ZFS_ENTER(zfsvfs);
error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td,
- LOOKUP_XATTR | CREATE_XATTR_DIR);
+ LOOKUP_XATTR | CREATE_XATTR_DIR, B_FALSE);
if (error != 0) {
ZFS_EXIT(zfsvfs);
return (error);
@@ -5721,7 +5730,7 @@
*sizep = 0;
error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td,
- LOOKUP_XATTR);
+ LOOKUP_XATTR, B_FALSE);
if (error != 0) {
ZFS_EXIT(zfsvfs);
/*
@@ -5982,7 +5991,7 @@
.vop_access = zfs_freebsd_access,
.vop_allocate = VOP_EINVAL,
.vop_lookup = zfs_cache_lookup,
- .vop_cachedlookup = zfs_freebsd_lookup,
+ .vop_cachedlookup = zfs_freebsd_cachedlookup,
.vop_getattr = zfs_freebsd_getattr,
.vop_setattr = zfs_freebsd_setattr,
.vop_create = zfs_freebsd_create,
Index: sys/fs/devfs/devfs_vnops.c
===================================================================
--- sys/fs/devfs/devfs_vnops.c
+++ sys/fs/devfs/devfs_vnops.c
@@ -946,8 +946,8 @@
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 == '.') {
Index: sys/fs/fuse/fuse_vnops.c
===================================================================
--- sys/fs/fuse/fuse_vnops.c
+++ sys/fs/fuse/fuse_vnops.c
@@ -1006,7 +1006,9 @@
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) {
Index: sys/fs/nfsclient/nfs_clvnops.c
===================================================================
--- sys/fs/nfsclient/nfs_clvnops.c
+++ sys/fs/nfsclient/nfs_clvnops.c
@@ -1195,7 +1195,8 @@
}
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)
Index: sys/fs/pseudofs/pseudofs_vnops.c
===================================================================
--- sys/fs/pseudofs/pseudofs_vnops.c
+++ sys/fs/pseudofs/pseudofs_vnops.c
@@ -466,10 +466,6 @@
PFS_RETURN (ENOTDIR);
KASSERT_PN_IS_DIR(pd);
- error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread);
- if (error)
- PFS_RETURN (error);
-
/*
* Don't support DELETE or RENAME. CREATE is supported so
* that O_CREAT will work, but the lookup will still fail if
Index: sys/fs/smbfs/smbfs_vnops.c
===================================================================
--- sys/fs/smbfs/smbfs_vnops.c
+++ sys/fs/smbfs/smbfs_vnops.c
@@ -1199,7 +1199,8 @@
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);
Index: sys/fs/tmpfs/tmpfs_vnops.c
===================================================================
--- sys/fs/tmpfs/tmpfs_vnops.c
+++ sys/fs/tmpfs/tmpfs_vnops.c
@@ -90,7 +90,7 @@
*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;
Index: sys/kern/vfs_cache.c
===================================================================
--- sys/kern/vfs_cache.c
+++ sys/kern/vfs_cache.c
@@ -2141,9 +2141,7 @@
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 @@
(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);
Index: sys/kern/vfs_lookup.c
===================================================================
--- sys/kern/vfs_lookup.c
+++ sys/kern/vfs_lookup.c
@@ -308,6 +308,7 @@
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 @@
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,
Index: sys/kern/vfs_subr.c
===================================================================
--- sys/kern/vfs_subr.c
+++ sys/kern/vfs_subr.c
@@ -6383,3 +6383,15 @@
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));
+}
Index: sys/sys/fcntl.h
===================================================================
--- sys/sys/fcntl.h
+++ sys/sys/fcntl.h
@@ -119,9 +119,11 @@
#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
Index: sys/sys/namei.h
===================================================================
--- sys/sys/namei.h
+++ sys/sys/namei.h
@@ -161,7 +161,8 @@
#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
Index: sys/sys/vnode.h
===================================================================
--- sys/sys/vnode.h
+++ sys/sys/vnode.h
@@ -956,6 +956,8 @@
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); \

File Metadata

Mime Type
text/plain
Expires
Tue, Jun 16, 7:51 PM (14 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34001928
Default Alt Text
D23247.id67657.diff (14 KB)

Event Timeline