From owner-p4-projects@FreeBSD.ORG Fri Jan 22 17:38:06 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 96DE01065698; Fri, 22 Jan 2010 17:38:06 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5AE00106568B for ; Fri, 22 Jan 2010 17:38:06 +0000 (UTC) (envelope-from jona@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 469A08FC08 for ; Fri, 22 Jan 2010 17:38:06 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o0MHc6EN088406 for ; Fri, 22 Jan 2010 17:38:06 GMT (envelope-from jona@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o0MHc6xe088404 for perforce@freebsd.org; Fri, 22 Jan 2010 17:38:06 GMT (envelope-from jona@FreeBSD.org) Date: Fri, 22 Jan 2010 17:38:06 GMT Message-Id: <201001221738.o0MHc6xe088404@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jona@FreeBSD.org using -f From: Jonathan Anderson To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 173524 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Jan 2010 17:38:06 -0000 http://p4web.freebsd.org/chv.cgi?CH=173524 Change 173524 by jona@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 -__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 #include @@ -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 __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; }