PERFORCE change 173524 for review

Jonathan Anderson jona at FreeBSD.org
Fri Jan 22 17:38:06 UTC 2010


http://p4web.freebsd.org/chv.cgi?CH=173524

Change 173524 by jona at jona-capsicum-kent64 on 2010/01/22 17:37:50

	namei() / lookup() changes, take 2

Affected files ...

.. //depot/projects/trustedbsd/capabilities/src/sys/kern/kern_descrip.c#32 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#28 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/kern/vfs_lookup.c#14 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/kern/vfs_syscalls.c#25 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#28 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/sys/file.h#16 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/sys/filedesc.h#6 edit
.. //depot/projects/trustedbsd/capabilities/src/sys/sys/namei.h#7 edit

Differences ...

==== //depot/projects/trustedbsd/capabilities/src/sys/kern/kern_descrip.c#32 (text+ko) ====

@@ -1544,30 +1544,44 @@
 int
 falloc(struct thread *td, struct file **resultfp, int *resultfd)
 {
-	return _falloc(td, resultfp, resultfd, 1);
+	struct file *fp;
+	int error;
+
+	error = falloc_noinstall(td, &fp);
+	if (error) return (error);		/* no reference held on error */
+
+	error = finstall(td, fp, resultfd);
+	if (error) {
+		fdrop(fp, td);			/* one reference (fp only) */
+		return (error);
+	}
+
+	if (resultfp) *resultfp = fp;		/* copy out result */
+	else fdrop(fp, td);			/* release local reference */
+
+	return (0);
 }
 
 /*
- * Create a new open file structure and, optionally, allocate a file decriptor
- * for the process that refers to it.
+ * Create a new open file structure without allocating a file decriptor.
  */
 int
-_falloc(struct thread *td, struct file **resultfp, int *resultfd,
-        int addfd)
+falloc_noinstall(struct thread *td, struct file **resultfp)
 {
-	struct proc *p = td->td_proc;
 	struct file *fp;
-	int error, i = -1;
+	int error;
 	int maxuserfiles = maxfiles - (maxfiles / 20);
 	static struct timeval lastfail;
 	static int curfail;
 
 	/*
-	 * Cowardly refuse to create a referenceless file: if we're not adding
-	 * the file to the process descriptor array, then the calling code
+	 * Cowardly refuse to create a referenceless file; the calling code
 	 * MUST expect a pointer to be returned.
 	 */
-	if (!addfd && !resultfp) return (error = EINVAL);
+	if (!resultfp)
+		return (error = EINVAL);
+
+	atomic_add_int(&openfiles, 1);
 
 	fp = uma_zalloc(file_zone, M_WAITOK | M_ZERO);
 	if ((openfiles >= maxuserfiles &&
@@ -1580,18 +1594,8 @@
 		uma_zfree(file_zone, fp);
 		return (ENFILE);
 	}
-	if (addfd)
-		atomic_add_int(&openfiles, 1);
 
-	/*
-	 * If addfd:
-	 * If the process has file descriptor zero open, add the new file
-	 * descriptor to the list of open files at that point, otherwise
-	 * put it at the front of the list of open files.
-	 */
-	refcount_init(&fp->f_count, (addfd > 0));
-	if (resultfp)
-		fhold(fp);
+	refcount_init(&fp->f_count, 1);
 	fp->f_cred = crhold(td->td_ucred);
 	fp->f_ops = &badfileops;
 	fp->f_data = NULL;
@@ -1599,23 +1603,33 @@
 	LIST_INIT(&fp->f_caps);
 	fp->f_capcount = 0;
 
-	if (addfd) {
-		FILEDESC_XLOCK(p->p_fd);
-		if ((error = fdalloc(td, 0, &i))) {
-			FILEDESC_XUNLOCK(p->p_fd);
-			fdrop(fp, td);
-			if (resultfp)
-				fdrop(fp, td);
-			return (error);
-		}
-		p->p_fd->fd_ofiles[i] = fp;
-		FILEDESC_XUNLOCK(p->p_fd);
+	*resultfp = fp;
+
+	return (0);
+}
+
+
+/*
+ * Install a file in the file descriptor table.
+ */
+int
+finstall(struct thread *td, struct file *fp, int *fd)
+{
+	struct filedesc *fdp = td->td_proc->p_fd;
+	int error;
+
+	FILEDESC_XLOCK(fdp);
+
+	if ((error = fdalloc(td, 0, fd))) {
+		FILEDESC_XUNLOCK(fdp);
+		return (error);
 	}
 
-	if (resultfp)
-		*resultfp = fp;
-	if (resultfd)
-		*resultfd = i;
+	fhold(fp);
+	fdp->fd_ofiles[*fd] = fp;
+
+	FILEDESC_XUNLOCK(fdp);
+
 	return (0);
 }
 
@@ -2247,7 +2261,8 @@
 #define	FGET_GETCAP	0x00000001
 static __inline int
 _fget(struct thread *td, int fd, struct file **fpp, int flags,
-    cap_rights_t rights, u_char *maxprotp, int fget_flags)
+    cap_rights_t needrights, cap_rights_t *haverights,
+    u_char *maxprotp, int fget_flags)
 {
 	struct filedesc *fdp;
 	struct file *fp;
@@ -2270,6 +2285,14 @@
 	}
 
 #ifdef CAPABILITIES
+	/* If this is a capability, what rights does it have? */
+	if (haverights) {
+		if (fp->f_type == DTYPE_CAPABILITY)
+			*haverights = cap_rights(fp);
+		else
+			*haverights = -1;
+	}
+
 	/*
 	 * If a capability has been requested, return the capability
 	 * directly.  Otherwise, check capability rights, extract the
@@ -2286,10 +2309,10 @@
 		 * capability and find the underlying object.
 		 */
 		if (maxprotp != NULL)
-			error = cap_fextract_mmap(fp, rights, maxprotp,
+			error = cap_fextract_mmap(fp, needrights, maxprotp,
 			    &fp_fromcap);
 		else
-			error = cap_fextract(fp, rights, &fp_fromcap);
+			error = cap_fextract(fp, needrights, &fp_fromcap);
 		if (error) {
 			fdrop(fp, td);
 			return (error);
@@ -2328,7 +2351,7 @@
 fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
 {
 
-	return(_fget(td, fd, fpp, 0, rights, NULL, 0));
+	return(_fget(td, fd, fpp, 0, rights, NULL, NULL, 0));
 }
 
 int
@@ -2336,21 +2359,21 @@
     struct file **fpp)
 {
 
-	return (_fget(td, fd, fpp, 0, rights, maxprotp, 0));
+	return (_fget(td, fd, fpp, 0, rights, NULL, maxprotp, 0));
 }
 
 int
 fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
 {
 
-	return(_fget(td, fd, fpp, FREAD, rights, NULL, 0));
+	return(_fget(td, fd, fpp, FREAD, rights, NULL, NULL, 0));
 }
 
 int
 fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
 {
 
-	return(_fget(td, fd, fpp, FWRITE, rights, NULL, 0));
+	return(_fget(td, fd, fpp, FWRITE, rights, NULL, NULL, 0));
 }
 
 /*
@@ -2362,7 +2385,7 @@
 fgetcap(struct thread *td, int fd, struct file **fpp)
 {
 
-	return (_fget(td, fd, fpp, 0, 0, NULL, FGET_GETCAP));
+	return (_fget(td, fd, fpp, 0, 0, NULL, NULL, FGET_GETCAP));
 }
 
 /*
@@ -2373,14 +2396,15 @@
  * XXX: what about the unused flags ?
  */
 static __inline int
-_fgetvp(struct thread *td, int fd, int flags, cap_rights_t rights,
-    struct vnode **vpp)
+_fgetvp(struct thread *td, int fd, int flags,
+    cap_rights_t needrights, cap_rights_t *haverights, struct vnode **vpp)
 {
 	struct file *fp;
 	int error;
 
 	*vpp = NULL;
-	if ((error = _fget(td, fd, &fp, flags, rights, NULL, 0)) != 0)
+	if ((error = _fget(td, fd, &fp, flags, needrights, haverights, NULL, 0))
+	     != 0)
 		return (error);
 	if (fp->f_vnode == NULL) {
 		error = EINVAL;
@@ -2397,7 +2421,14 @@
 fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp)
 {
 
-	return (_fgetvp(td, fd, 0, rights, vpp));
+	return (_fgetvp(td, fd, 0, rights, NULL, vpp));
+}
+
+int
+fgetvp_rights(struct thread *td, int fd, cap_rights_t need, cap_rights_t *have,
+    struct vnode **vpp)
+{
+	return (_fgetvp(td, fd, 0, need, have, vpp));
 }
 
 int
@@ -2405,7 +2436,7 @@
     struct vnode **vpp)
 {
 
-	return (_fgetvp(td, fd, FREAD, rights, vpp));
+	return (_fgetvp(td, fd, FREAD, rights, NULL, vpp));
 }
 
 #ifdef notyet
@@ -2414,7 +2445,7 @@
     struct vnode **vpp)
 {
 
-	return (_fgetvp(td, fd, FWRITE, rights, vpp));
+	return (_fgetvp(td, fd, FWRITE, rights, NULL, vpp));
 }
 #endif
 
@@ -2439,7 +2470,7 @@
 	*spp = NULL;
 	if (fflagp != NULL)
 		*fflagp = 0;
-	if ((error = _fget(td, fd, &fp, 0, rights, NULL, 0)) != 0)
+	if ((error = _fget(td, fd, &fp, 0, rights, NULL, NULL, 0)) != 0)
 		return (error);
 	if (fp->f_type != DTYPE_SOCKET) {
 		error = ENOTSOCK;

==== //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#28 (text+ko) ====

@@ -50,7 +50,7 @@
 #include "opt_capabilities.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$P4: //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#27 $");
+__FBSDID("$P4: //depot/projects/trustedbsd/capabilities/src/sys/kern/sys_capability.c#28 $");
 
 #include <sys/param.h>
 #include <sys/capability.h>
@@ -153,8 +153,11 @@
 cap_check(struct capability *c, cap_rights_t rights)
 {
 
-	if ((c->cap_rights | rights) != c->cap_rights)
+	if ((c->cap_rights | rights) != c->cap_rights) {
+		printf("ENOTCAPABLE: %016x < %016x\n",
+		       (unsigned int) c->cap_rights, (unsigned int) rights);
 		return (ENOTCAPABLE);
+	}
 	return (0);
 }
 

==== //depot/projects/trustedbsd/capabilities/src/sys/kern/vfs_lookup.c#14 (text+ko) ====

@@ -37,6 +37,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/kern/vfs_lookup.c,v 1.133 2009/11/10 11:50:37 kib Exp $");
 
+#include "opt_capabilities.h"
 #include "opt_kdb.h"
 #include "opt_kdtrace.h"
 #include "opt_ktrace.h"
@@ -139,16 +140,6 @@
 	struct proc *p = td->td_proc;
 	int vfslocked;
 
-#ifdef KDB
-	if ((td->td_ucred->cr_flags & CRED_FLAG_CAPMODE)
-	    && (ndp->ni_dirfd == AT_FDCWD))
-	{
-		printf("namei: pid %d proc %s performed namei in capability "
-		    "mode (and it's not *at())\n", p->p_pid, p->p_comm);
-		kdb_backtrace();
-	}
-#endif
-
 	KASSERT((cnp->cn_flags & MPSAFE) != 0 || mtx_owned(&Giant) != 0,
 	    ("NOT MPSAFE and Giant not held"));
 	ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred;
@@ -206,6 +197,7 @@
 		ktrnamei(cnp->cn_pnbuf);
 	}
 #endif
+
 	/*
 	 * Get starting point for the translation.
 	 */
@@ -214,7 +206,18 @@
 	ndp->ni_topdir = fdp->fd_jdir;
 
 	dp = NULL;
+#ifdef CAPABILITIES
+	/*
+	 * in capability mode, lookups must be performed relative to a real file
+	 * descriptor, not the pseudo-descriptor AT_FDCWD
+	 */
+	if (IN_CAPABILITY_MODE(td) && (ndp->ni_dirfd == AT_FDCWD)) {
+		error = EOPNOTSUPP;
+	} else {
+#else /* !CAPABILITIES */
+	/* this optimisation doesn't apply if we have capabilities */
 	if (cnp->cn_pnbuf[0] != '/') {
+#endif
 		if (ndp->ni_startdir != NULL) {
 			dp = ndp->ni_startdir;
 			error = 0;
@@ -223,26 +226,39 @@
 				AUDIT_ARG_ATFD1(ndp->ni_dirfd);
 			if (cnp->cn_flags & AUDITVNODE2)
 				AUDIT_ARG_ATFD2(ndp->ni_dirfd);
-			error = fgetvp(td, ndp->ni_dirfd, CAP_LOOKUP, &dp);
+			error = fgetvp_rights(td, ndp->ni_dirfd,
+			                      ndp->ni_rightsneeded | CAP_LOOKUP,
+			                      &(ndp->ni_baserights), &dp);
+
+#ifdef CAPABILITIES
+			/*
+			 * only set ni_basedir if base was a capability or we are
+			 * in capability mode
+			 */
+			if ((ndp->ni_baserights != -1) || (IN_CAPABILITY_MODE(td)))
+				ndp->ni_basedir = dp;
+#endif
 		}
-		if (error != 0 || dp != NULL) {
-			FILEDESC_SUNLOCK(fdp);
-			if (error == 0 && dp->v_type != VDIR) {
-				vfslocked = VFS_LOCK_GIANT(dp->v_mount);
-				vrele(dp);
-				VFS_UNLOCK_GIANT(vfslocked);
-				error = ENOTDIR;
-			}
+	}
+	if (error != 0 || dp != NULL) {
+		FILEDESC_SUNLOCK(fdp);
+		if (error == 0 && dp->v_type != VDIR) {
+			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
+			vrele(dp);
+			VFS_UNLOCK_GIANT(vfslocked);
+			error = ENOTDIR;
 		}
-		if (error) {
-			uma_zfree(namei_zone, cnp->cn_pnbuf);
+	}
+
+	if (error) {
+		uma_zfree(namei_zone, cnp->cn_pnbuf);
 #ifdef DIAGNOSTIC
-			cnp->cn_pnbuf = NULL;
-			cnp->cn_nameptr = NULL;
+		cnp->cn_pnbuf = NULL;
+		cnp->cn_nameptr = NULL;
 #endif
-			return (error);
-		}
+		return (error);
 	}
+
 	if (dp == NULL) {
 		dp = fdp->fd_cdir;
 		VREF(dp);
@@ -260,6 +276,8 @@
 		/*
 		 * Check if root directory should replace current directory.
 		 * Done at start of translation and after symbolic link.
+		 * This is illegal if looking up relative to a capability unless
+		 * that capability is for '/' and has CAP_ABSOLUTEPATH.
 		 */
 		cnp->cn_nameptr = cnp->cn_pnbuf;
 		if (*(cnp->cn_nameptr) == '/') {
@@ -269,6 +287,21 @@
 				cnp->cn_nameptr++;
 				ndp->ni_pathlen--;
 			}
+#ifdef CAPABILITIES
+			if (ndp->ni_basedir)
+				printf("ABSOLUTE namei(); "
+				       "basedir: %016lx, rootdir: %016lx"
+				       ", baserights: %016lx\n",
+				       (unsigned long) ndp->ni_basedir,
+				       (unsigned long) ndp->ni_rootdir,
+				       (unsigned long) ndp->ni_baserights);
+
+			if (ndp->ni_basedir
+			    && !((ndp->ni_basedir == ndp->ni_rootdir)
+			         && (ndp->ni_baserights & CAP_ABSOLUTEPATH)))
+				return (ENOTCAPABLE);
+#endif
+
 			dp = ndp->ni_rootdir;
 			vfslocked = VFS_LOCK_GIANT(dp->v_mount);
 			VREF(dp);
@@ -480,8 +513,7 @@
 	int dvfslocked;			/* VFS Giant state for parent */
 	int tvfslocked;
 	int lkflags_save;
-	int insidebasedir = 0;		/* we're under the *at() base */
-	
+
 	/*
 	 * Setup: break out flag bits into variables.
 	 */
@@ -508,10 +540,6 @@
 	else
 		cnp->cn_lkflags = LK_EXCLUSIVE;
 
-	/* we do not allow absolute lookups in capability mode */
-	if(ndp->ni_basedir && (ndp->ni_startdir == ndp->ni_rootdir))
-		return (error = EPERM);
-
 	dp = ndp->ni_startdir;
 	ndp->ni_startdir = NULLVP;
 	vn_lock(dp,
@@ -580,11 +608,6 @@
 		goto bad;
 	}
 
-
-	/* Check to see if we're at the *at directory */
-	if(dp == ndp->ni_basedir) insidebasedir = 1;
-
-
 	/*
 	 * Check for degenerate name (e.g. / or "")
 	 * which is a way of talking about a directory,
@@ -619,17 +642,18 @@
 	}
 
 	/*
-	 * Handle "..": four special cases.
+	 * Handle "..": five special cases.
 	 * 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)
+	 * 2. If at the base of a capability *at call, return ENOTCAPABLE.
+	 * 3. If at root directory (e.g. after chroot)
 	 *    or at absolute root directory
 	 *    then ignore it so can't get out.
-	 * 3. If this vnode is the root of a mounted
+	 * 4. If this vnode is the root of a mounted
 	 *    filesystem, then replace it with the
 	 *    vnode which was mounted on so we take the
 	 *    .. in the other filesystem.
-	 * 4. If the vnode is the top directory of
+	 * 5. If the vnode is the top directory of
 	 *    the jail or chroot, don't let them out.
 	 */
 	if (cnp->cn_flags & ISDOTDOT) {
@@ -639,13 +663,17 @@
 			goto bad;
 		}
 		for (;;) {
-			/* attempting to wander out of the *at root */
-			if(dp == ndp->ni_basedir)
-			{
-				error = EPERM;
+#ifdef CAPABILITIES
+			/*
+			 * Attempting to wander out of the *at root; whether or
+			 * not this is allowed is a capability option on the
+			 * '/' capability.
+			 */
+			if (dp == ndp->ni_basedir) {
+				error = ENOTCAPABLE;
 				goto bad;
 			}
-
+#endif
 			for (pr = cnp->cn_cred->cr_prison; pr != NULL;
 			     pr = pr->pr_parent)
 				if (dp == pr->pr_root)
@@ -906,16 +934,6 @@
 		VOP_UNLOCK(dp, 0);
 success:
 	/*
-	 * If we're in capability mode and the syscall was *at(), ensure
-	 * that the *at() base was part of the path
-	 */
-	if(ndp->ni_basedir && !insidebasedir)
-	{
-		error = EPERM;
-		goto bad;
-	}
-
-	/*
 	 * Because of lookup_shared we may have the vnode shared locked, but
 	 * the caller may want it to be exclusively locked.
 	 */

==== //depot/projects/trustedbsd/capabilities/src/sys/kern/vfs_syscalls.c#25 (text+ko) ====

@@ -159,42 +159,6 @@
 	return (0);
 }
 
-#ifdef CAPABILITIES
-/*-
- * Get the "base" vnode defined by a user file descriptor.
- *
- * Several *at() system calls are now supported in capability mode.  This
- * function finds out what their "*at base" vnode, which is needed by
- * namei(), should be:
- *
- * 1. In non-capability (and thus unconstrained) mode, *base = NULL.
- * 2. In capability mode, base is the vnode given by the fd parameter,
- *    subject to the condition that the supplied 'rights' parameter (OR'ed
- *    with CAP_LOOKUP and CAP_ATBASE) is satisfied. The vnode is returned
- *    with a shared lock.
- */
-int
-fgetbase(struct thread *td, int fd, cap_rights_t rights, struct vnode **base)
-{
-
-	if (!(td->td_ucred->cr_flags & CRED_FLAG_CAPMODE))
-		*base = NULL;
-	else {
-		int error;
-
-		error = fgetvp(td, fd, rights | CAP_LOOKUP | CAP_ATBASE, base);
-		if (error)
-			return (error);
-
-		if ((error = vn_lock(*base, LK_SHARED))) {
-			vrele(*base);
-			return (error);
-		}
-	}
-	return (0);
-}
-#endif
-
 /*
  * Sync each mounted filesystem.
  */
@@ -1128,7 +1092,7 @@
 	struct proc *p = td->td_proc;
 	struct filedesc *fdp = p->p_fd;
 	struct file *fp;
-	struct vnode *vp, *base = NULL;
+	struct vnode *vp;
 	struct vattr vat;
 	struct mount *mp;
 	int cmode;
@@ -1137,7 +1101,7 @@
 	struct flock lf;
 	struct nameidata nd;
 	int vfslocked;
-	cap_rights_t baserights = -1;
+	cap_rights_t baserights = CAP_ATBASE;
 
 	AUDIT_ARG_FFLAGS(flags);
 	AUDIT_ARG_MODE(mode);
@@ -1147,6 +1111,7 @@
 	 * be specified.
 	 */
 	if (flags & O_EXEC) {
+		baserights |= CAP_FEXECVE;
 		if (flags & O_ACCMODE)
 			return (EINVAL);
 	} else if ((flags & O_ACCMODE) == O_ACCMODE)
@@ -1155,65 +1120,24 @@
 		flags = FFLAGS(flags);
 
 #ifdef CAPABILITIES
-	/* get capability info of base FD */
-	if (fd >= 0) {
-		struct file *f;
-		const cap_rights_t LOOKUP_RIGHTS = CAP_LOOKUP | CAP_ATBASE;
-
-		FILEDESC_SLOCK(fdp);
-
-		error = fgetcap(td, fd, &f);
-		if (error == 0) {
-			/* FD is a capability; get rights and unwrap */
-			struct file *real_fp = NULL;
-
-			baserights = cap_rights(f);
-			error = cap_fextract(f, LOOKUP_RIGHTS, &real_fp);
-
-			/* hold the underlying file, not the capability */
-			if (error == 0)
-				fhold(real_fp);
-			fdrop(f, td);
-
-			f = real_fp;
-		} else if (error == EINVAL)
-			/* not a capability; get the real file pointer */
-			error = fget(td, fd, LOOKUP_RIGHTS, &f);
-
-		/* if in capability mode, get base vnode (for namei) */
-		if (!error && (td->td_ucred->cr_flags & CRED_FLAG_CAPMODE)) {
-			base = f->f_vnode;
-			vref(base);
-		}
-
-		/* don't need to hold the base any more */
-		if (f != NULL)
-			fdrop(f, td);
-
-		if (error) {
-			FILEDESC_SUNLOCK(fdp);
-			return (error);
-		} else
-			FILEDESC_SUNLOCK(fdp);
-	}
+	if (flags & FREAD)	baserights |= CAP_READ;
+	if (flags & FWRITE)	baserights |= CAP_WRITE;
 #endif
 
 	/*
-	 * allocate the file descriptor, but only add it to the descriptor
-	 * array if fd isn't a capability (in which case we'll add the
-	 * capability instead, later)
+	 * allocate the file descriptor, but don't install a descriptor yet
 	 */
-	error = _falloc(td, &nfp, &indx, (baserights == -1));
+	error = falloc_noinstall(td, &nfp);
 	if (error)
 		return (error);
 
-	/* An extra reference on `nfp' has been held for us by _falloc(). */
+	/* An extra reference on `nfp' has been held for us by falloc(). */
 	fp = nfp;
 	/* Set the flags early so the finit in devfs can pick them up. */
 	fp->f_flag = flags & FMASK;
 	cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
-	NDINIT_ATBASE(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg,
-	              path, fd, base, td);
+	NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg,
+	              path, fd, baserights, td);
 	td->td_dupfd = -1;		/* XXX check for fdopen */
 	error = vn_open(&nd, &flags, cmode, fp);
 	if (error) {
@@ -1229,8 +1153,12 @@
 		 * handle special fdopen() case.  bleh.  dupfdopen() is
 		 * responsible for dropping the old contents of ofiles[indx]
 		 * if it succeeds.
+		 *
+		 * Don't do this for relative (capability) lookups; we don't
+		 * understand exactly what would happen, and we don't think that
+		 * it ever should.
 		 */
-		if ((error == ENODEV || error == ENXIO) &&
+		if (!nd.ni_basedir && (error == ENODEV || error == ENXIO) &&
 		    td->td_dupfd >= 0 &&		/* XXX from fdopen */
 		    (error =
 			dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0)
@@ -1240,10 +1168,6 @@
 		 * Clean up the descriptor, but only if another thread hadn't
 		 * replaced or closed it.
 		 */
-#ifdef CAPABILITIES
-		if (base)
-			vrele(base);
-#endif
 		fdclose(fdp, fp, indx, td);
 		fdrop(fp, td);
 
@@ -1304,34 +1228,29 @@
 
 success:
 #ifdef CAPABILITIES
-	if (baserights != -1) {
+	if (nd.ni_baserights != -1) {
 		/* wrap the result in a capability */
 		struct file *cap;
 
-		error = kern_capwrap(td, fp, baserights, &cap, &indx);
+		error = kern_capwrap(td, fp, nd.ni_baserights, &cap, &indx);
 		if (error)
 			goto bad_unlocked;
 	}
+	else
 #endif
+	if ((error = finstall(td, fp, &indx)) != 0)
+		goto bad_unlocked;
 
 	/*
 	 * Release our private reference, leaving the one associated with
 	 * the descriptor table intact.
 	 */
-#ifdef CAPABILITIES
-	if (base)
-		vrele(base);
-#endif
 	fdrop(fp, td);
 	td->td_retval[0] = indx;
 	return (0);
 bad:
 	VFS_UNLOCK_GIANT(vfslocked);
-#ifdef CAPABILITIES
 bad_unlocked:
-	if (base)
-		vrele(base);
-#endif
 	fdclose(fdp, fp, indx, td);
 	fdrop(fp, td);
 	return (error);
@@ -2264,7 +2183,7 @@
     int flags, int mode)
 {
 	struct ucred *cred, *tmpcred;
-	struct vnode *vp, *base = NULL;
+	struct vnode *vp;
 	struct nameidata nd;
 	int vfslocked;
 	int error;
@@ -2284,14 +2203,8 @@
 		cred = tmpcred = td->td_ucred;
 	AUDIT_ARG_VALUE(mode);
 
-#ifdef CAPABILITIES
-	/* get *at base vnode for namei() */
-	if ((error = fgetbase(td, fd, CAP_FSTAT, &base)))
-		return (error);
-#endif
-
-	NDINIT_ATBASE(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | MPSAFE |
-	    AUDITVNODE1, pathseg, path, fd, base, td);
+	NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | MPSAFE |
+	    AUDITVNODE1, pathseg, path, fd, CAP_FSTAT, td);
 	if ((error = namei(&nd)) != 0)
 		goto out1;
 	vfslocked = NDHASGIANT(&nd);
@@ -2306,10 +2219,6 @@
 		td->td_ucred = cred;
 		crfree(tmpcred);
 	}
-#ifdef CAPABILITIES
-	if (base)
-		vput(base);
-#endif
 	return (error);
 }
 
@@ -3058,22 +2967,13 @@
 	struct nameidata nd;
 	int vfslocked;
 	int follow;
-	struct vnode *base = NULL;
 
 	AUDIT_ARG_MODE(mode);
 	follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
-#ifdef CAPABILITIES
-	if ((error = fgetbase(td, fd, CAP_FCHMOD, &base)))
-		return (error);
-#endif
 
-	NDINIT_ATBASE(&nd, LOOKUP,  follow | MPSAFE | AUDITVNODE1, pathseg,
-	    path, fd, base, td);
+	NDINIT_ATRIGHTS(&nd, LOOKUP,  follow | MPSAFE | AUDITVNODE1, pathseg,
+	    path, fd, CAP_FCHMOD, td);
 	error = namei(&nd);
-#ifdef CAPABILITIES
-	if (base)
-		vput(base);
-#endif
 	if (error)
 		return (error);
 

==== //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#28 (text+ko) ====

@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $P4: //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#27 $
+ * $P4: //depot/projects/trustedbsd/capabilities/src/sys/sys/capability.h#28 $
  */
 
 /*
@@ -97,7 +97,8 @@
 #define	CAP_FCHDIR		0x0002000000000000ULL	/* fchdir(2) */
 #define	CAP_FSCK		0x0004000000000000ULL	/* sysctl_ffs_fsck */
 #define	CAP_ATBASE		0x0008000000000000ULL	/* openat(2), etc. */
-#define	CAP_MASK_VALID		0x000fffffffffffffULL
+#define CAP_ABSOLUTEPATH	0x0010000000000000ULL	/* abs. lookup from '/' */
+#define	CAP_MASK_VALID		0x001fffffffffffffULL
 
 /*
  * Notes:
@@ -141,6 +142,9 @@
 struct file;
 struct thread;
 
+#define IN_CAPABILITY_MODE(td) (td->td_ucred->cr_flags & CRED_FLAG_CAPMODE)
+
+
 /*
  * Create a capability to wrap a file object.
  */

==== //depot/projects/trustedbsd/capabilities/src/sys/sys/file.h#16 (text+ko) ====

@@ -206,6 +206,8 @@
 void finit(struct file *, u_int, short, void *, struct fileops *);
 int fgetvp(struct thread *td, int fd, cap_rights_t rights,
     struct vnode **vpp);
+int fgetvp_rights(struct thread *td, int fd, cap_rights_t need, cap_rights_t *have,
+    struct vnode **vpp);
 int fgetvp_read(struct thread *td, int fd, cap_rights_t rights,
     struct vnode **vpp);
 int fgetvp_write(struct thread *td, int fd, cap_rights_t rights,

==== //depot/projects/trustedbsd/capabilities/src/sys/sys/filedesc.h#6 (text+ko) ====

@@ -112,8 +112,8 @@
 int	dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd,
 	    int mode, int error);
 int	falloc(struct thread *td, struct file **resultfp, int *resultfd);
-int	_falloc(struct thread *td, struct file **resultfp, int *resultfd,
-	        int addfd);
+int	falloc_noinstall(struct thread *td, struct file **resultfp);
+int	finstall(struct thread *td, struct file *fp, int *resultfp);
 int	fdalloc(struct thread *td, int minfd, int *result);
 int	fdavail(struct thread *td, int n);
 int	fdcheckstd(struct thread *td);

==== //depot/projects/trustedbsd/capabilities/src/sys/sys/namei.h#7 (text+ko) ====

@@ -63,6 +63,7 @@
 	 */
 	const	char *ni_dirp;		/* pathname pointer */
 	enum	uio_seg ni_segflg;	/* location of pathname */
+	cap_rights_t ni_rightsneeded;	/* rights required to look up vnode */
 	/*
 	 * Arguments to lookup.
 	 */
@@ -72,6 +73,10 @@
 	int	ni_dirfd;		/* starting directory for *at functions */
 	struct	vnode *ni_basedir;	/* root for capability-mode *at */
 	/*
+	 * Results: returned from namei
+	 */
+	cap_rights_t ni_baserights;	/* rights that the *at base has (or -1) */
+	/*
 	 * Results: returned from/manipulated by lookup
 	 */
 	struct	vnode *ni_vp;		/* vnode of result */
@@ -152,13 +157,13 @@
  * Initialization of a nameidata structure.
  */
 #define	NDINIT(ndp, op, flags, segflg, namep, td)			\
-	NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, NULL, NULL, td)
+	NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, NULL, NULL, 0, td)
 #define	NDINIT_AT(ndp, op, flags, segflg, namep, dirfd, td)	\
-	NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, NULL, td)
-#define	NDINIT_ATBASE(ndp, op, flags, segflg, namep, dirfd, base, td)	\
-	NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, base, td)
+	NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, NULL, 0, td)
+#define	NDINIT_ATRIGHTS(ndp, op, flags, segflg, namep, dirfd, rights, td)	\
+	NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, NULL, rights, td)
 #define	NDINIT_ATVP(ndp, op, flags, segflg, namep, vp, td)	\
-	NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, vp, NULL, td)
+	NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, vp, NULL, 0, td)
 
 static __inline void
 NDINIT_ALL(struct nameidata *ndp,
@@ -168,6 +173,7 @@
 	int dirfd,
 	struct vnode *startdir,
 	struct vnode *basedir,
+	cap_rights_t rights,
 	struct thread *td)
 {
 	ndp->ni_cnd.cn_nameiop = op;
@@ -177,6 +183,8 @@
 	ndp->ni_dirfd = dirfd;
 	ndp->ni_startdir = startdir;
 	ndp->ni_basedir = basedir;
+	ndp->ni_rightsneeded = rights;
+	ndp->ni_baserights = -1;
 	ndp->ni_cnd.cn_thread = td;
 }
 


More information about the p4-projects mailing list