svn commit: r203229 - in projects/capabilities8/sys: kern sys
Robert Watson
rwatson at FreeBSD.org
Sat Jan 30 19:35:39 UTC 2010
Author: rwatson
Date: Sat Jan 30 19:35:38 2010
New Revision: 203229
URL: http://svn.freebsd.org/changeset/base/203229
Log:
Merge c173524 from the p4 TrustedBSD capabilities branch to capabilities8:
namei() / lookup() changes, take 2.
Submitted by: Jonathan Anderson <jonathan.anderson at cl.cam.ac.uk>
Modified:
projects/capabilities8/sys/kern/kern_descrip.c
projects/capabilities8/sys/kern/sys_capability.c
projects/capabilities8/sys/kern/vfs_lookup.c
projects/capabilities8/sys/kern/vfs_syscalls.c
projects/capabilities8/sys/sys/capability.h
projects/capabilities8/sys/sys/file.h
projects/capabilities8/sys/sys/filedesc.h
projects/capabilities8/sys/sys/namei.h
Modified: projects/capabilities8/sys/kern/kern_descrip.c
==============================================================================
--- projects/capabilities8/sys/kern/kern_descrip.c Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/kern/kern_descrip.c Sat Jan 30 19:35:38 2010 (r203229)
@@ -1544,30 +1544,44 @@ fdavail(struct thread *td, int n)
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 @@ _falloc(struct thread *td, struct file *
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 @@ _falloc(struct thread *td, struct file *
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 @@ fget_unlocked(struct filedesc *fdp, int
#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 @@ _fget(struct thread *td, int fd, struct
}
#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 @@ _fget(struct thread *td, int fd, struct
* 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 @@ int
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 @@ fget_mmap(struct thread *td, int fd, cap
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 @@ int
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 @@ fgetcap(struct thread *td, int fd, struc
* 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 @@ int
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 @@ fgetvp_read(struct thread *td, int fd, c
struct vnode **vpp)
{
- return (_fgetvp(td, fd, FREAD, rights, vpp));
+ return (_fgetvp(td, fd, FREAD, rights, NULL, vpp));
}
#ifdef notyet
@@ -2414,7 +2445,7 @@ fgetvp_write(struct thread *td, int fd,
struct vnode **vpp)
{
- return (_fgetvp(td, fd, FWRITE, rights, vpp));
+ return (_fgetvp(td, fd, FWRITE, rights, NULL, vpp));
}
#endif
@@ -2439,7 +2470,7 @@ fgetsock(struct thread *td, int fd, cap_
*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;
Modified: projects/capabilities8/sys/kern/sys_capability.c
==============================================================================
--- projects/capabilities8/sys/kern/sys_capability.c Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/kern/sys_capability.c Sat Jan 30 19:35:38 2010 (r203229)
@@ -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 @@ static int
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);
}
Modified: projects/capabilities8/sys/kern/vfs_lookup.c
==============================================================================
--- projects/capabilities8/sys/kern/vfs_lookup.c Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/kern/vfs_lookup.c Sat Jan 30 19:35:38 2010 (r203229)
@@ -37,6 +37,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_capabilities.h"
#include "opt_kdb.h"
#include "opt_kdtrace.h"
#include "opt_ktrace.h"
@@ -139,16 +140,6 @@ namei(struct nameidata *ndp)
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 @@ namei(struct nameidata *ndp)
ktrnamei(cnp->cn_pnbuf);
}
#endif
+
/*
* Get starting point for the translation.
*/
@@ -214,7 +206,18 @@ namei(struct nameidata *ndp)
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 @@ namei(struct nameidata *ndp)
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 @@ namei(struct nameidata *ndp)
/*
* 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 @@ namei(struct nameidata *ndp)
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 @@ lookup(struct nameidata *ndp)
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 @@ lookup(struct nameidata *ndp)
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 @@ dirloop:
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 @@ dirloop:
}
/*
- * 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 @@ dirloop:
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 @@ nextname:
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.
*/
Modified: projects/capabilities8/sys/kern/vfs_syscalls.c
==============================================================================
--- projects/capabilities8/sys/kern/vfs_syscalls.c Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/kern/vfs_syscalls.c Sat Jan 30 19:35:38 2010 (r203229)
@@ -159,42 +159,6 @@ getvnode_cap(struct filedesc *fdp, int f
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 @@ kern_openat(struct thread *td, int fd, c
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 @@ kern_openat(struct thread *td, int fd, c
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 @@ kern_openat(struct thread *td, int fd, c
* 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 @@ kern_openat(struct thread *td, int fd, c
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 @@ kern_openat(struct thread *td, int fd, c
* 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 @@ kern_openat(struct thread *td, int fd, c
* 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 @@ kern_openat(struct thread *td, int fd, c
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 @@ kern_accessat(struct thread *td, int fd,
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 @@ kern_accessat(struct thread *td, int fd,
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 @@ out1:
td->td_ucred = cred;
crfree(tmpcred);
}
-#ifdef CAPABILITIES
- if (base)
- vput(base);
-#endif
return (error);
}
@@ -3058,22 +2967,13 @@ kern_fchmodat(struct thread *td, int fd,
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);
Modified: projects/capabilities8/sys/sys/capability.h
==============================================================================
--- projects/capabilities8/sys/sys/capability.h Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/sys/capability.h Sat Jan 30 19:35:38 2010 (r203229)
@@ -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.
*/
Modified: projects/capabilities8/sys/sys/file.h
==============================================================================
--- projects/capabilities8/sys/sys/file.h Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/sys/file.h Sat Jan 30 19:35:38 2010 (r203229)
@@ -206,6 +206,8 @@ fo_close_t soo_close;
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,
Modified: projects/capabilities8/sys/sys/filedesc.h
==============================================================================
--- projects/capabilities8/sys/sys/filedesc.h Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/sys/filedesc.h Sat Jan 30 19:35:38 2010 (r203229)
@@ -112,8 +112,8 @@ int closef(struct file *fp, struct threa
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);
Modified: projects/capabilities8/sys/sys/namei.h
==============================================================================
--- projects/capabilities8/sys/sys/namei.h Sat Jan 30 19:33:45 2010 (r203228)
+++ projects/capabilities8/sys/sys/namei.h Sat Jan 30 19:35:38 2010 (r203229)
@@ -63,6 +63,7 @@ struct nameidata {
*/
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 @@ struct nameidata {
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 @@ struct nameidata {
* 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 @@ NDINIT_ALL(struct nameidata *ndp,
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 @@ NDINIT_ALL(struct nameidata *ndp,
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 svn-src-projects
mailing list