summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/vfs_lookup.c')
-rw-r--r--sys/kern/vfs_lookup.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index ae8982f..a145017 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -180,6 +180,18 @@ namei(struct nameidata *ndp)
if (!error && *cnp->cn_pnbuf == '\0')
error = ENOENT;
+#ifdef CAPABILITY_MODE
+ /*
+ * In capability mode, lookups must be "strictly relative" (i.e.
+ * not an absolute path, and not containing '..' components) to
+ * a real file descriptor, not the pseudo-descriptor AT_FDCWD.
+ */
+ if (IN_CAPABILITY_MODE(td)) {
+ ndp->ni_strictrelative = 1;
+ if (ndp->ni_dirfd == AT_FDCWD)
+ error = ECAPMODE;
+ }
+#endif
if (error) {
uma_zfree(namei_zone, cnp->cn_pnbuf);
#ifdef DIAGNOSTIC
@@ -214,12 +226,20 @@ namei(struct nameidata *ndp)
AUDIT_ARG_ATFD1(ndp->ni_dirfd);
if (cnp->cn_flags & AUDITVNODE2)
AUDIT_ARG_ATFD2(ndp->ni_dirfd);
-#ifdef CAPABILITY_MODE
- KASSERT(!IN_CAPABILITY_MODE(td),
- ("%s: reached %s:%d in capability mode",
- __func__, __FILE__, __LINE__));
+ error = fgetvp_rights(td, ndp->ni_dirfd,
+ ndp->ni_rightsneeded | CAP_LOOKUP,
+ &(ndp->ni_baserights), &dp);
+#ifdef CAPABILITIES
+ /*
+ * Lookups relative to a capability must also be
+ * strictly relative.
+ *
+ * Note that a capability with rights CAP_MASK_VALID
+ * is treated exactly like a regular file descriptor.
+ */
+ if (ndp->ni_baserights != CAP_MASK_VALID)
+ ndp->ni_strictrelative = 1;
#endif
- error = fgetvp(td, ndp->ni_dirfd, 0, &dp);
}
if (error != 0 || dp != NULL) {
FILEDESC_SUNLOCK(fdp);
@@ -261,6 +281,8 @@ namei(struct nameidata *ndp)
if (*(cnp->cn_nameptr) == '/') {
vrele(dp);
VFS_UNLOCK_GIANT(vfslocked);
+ if (ndp->ni_strictrelative != 0)
+ return (ENOTCAPABLE);
while (*(cnp->cn_nameptr) == '/') {
cnp->cn_nameptr++;
ndp->ni_pathlen--;
@@ -604,7 +626,10 @@ dirloop:
}
/*
- * Handle "..": four special cases.
+ * Handle "..": five special cases.
+ * 0. If doing a capability lookup, return ENOTCAPABLE (this is a
+ * fairly conservative design choice, but it's the only one that we
+ * are satisfied guarantees the property we're looking for).
* 1. Return an error if this is the last component of
* the name and the operation is DELETE or RENAME.
* 2. If at root directory (e.g. after chroot)
@@ -618,6 +643,10 @@ dirloop:
* the jail or chroot, don't let them out.
*/
if (cnp->cn_flags & ISDOTDOT) {
+ if (ndp->ni_strictrelative != 0) {
+ error = ENOTCAPABLE;
+ goto bad;
+ }
if ((cnp->cn_flags & ISLASTCN) != 0 &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
error = EINVAL;
OpenPOWER on IntegriCloud