summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_lookup.c
diff options
context:
space:
mode:
authorjonathan <jonathan@FreeBSD.org>2011-08-13 09:21:16 +0000
committerjonathan <jonathan@FreeBSD.org>2011-08-13 09:21:16 +0000
commitf63d2e920584a3d403a07e765a61eeac57210332 (patch)
tree3334bf0dc037565dbb28b66bfe83c6d9e8823738 /sys/kern/vfs_lookup.c
parent0ba1fe7d116a032383d49c9a252a5f09682c76f0 (diff)
downloadFreeBSD-src-f63d2e920584a3d403a07e765a61eeac57210332.zip
FreeBSD-src-f63d2e920584a3d403a07e765a61eeac57210332.tar.gz
Allow Capsicum capabilities to delegate constrained
access to file system subtrees to sandboxed processes. - Use of absolute paths and '..' are limited in capability mode. - Use of absolute paths and '..' are limited when looking up relative to a capability. - When a name lookup is performed, identify what operation is to be performed (such as CAP_MKDIR) as well as check for CAP_LOOKUP. With these constraints, openat() and friends are now safe in capability mode, and can then be used by code such as the capability-mode runtime linker. Approved by: re (bz), mentor (rwatson) Sponsored by: Google Inc
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