From owner-svn-src-all@FreeBSD.ORG Mon Jul 4 14:40:33 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 001C7106564A; Mon, 4 Jul 2011 14:40:32 +0000 (UTC) (envelope-from jonathan@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id E39D98FC18; Mon, 4 Jul 2011 14:40:32 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p64EeWRl022887; Mon, 4 Jul 2011 14:40:32 GMT (envelope-from jonathan@svn.freebsd.org) Received: (from jonathan@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p64EeWx6022884; Mon, 4 Jul 2011 14:40:32 GMT (envelope-from jonathan@svn.freebsd.org) Message-Id: <201107041440.p64EeWx6022884@svn.freebsd.org> From: Jonathan Anderson Date: Mon, 4 Jul 2011 14:40:32 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r223762 - in head/sys: kern sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jul 2011 14:40:33 -0000 Author: jonathan Date: Mon Jul 4 14:40:32 2011 New Revision: 223762 URL: http://svn.freebsd.org/changeset/base/223762 Log: Add kernel functions to unwrap capabilities. cap_funwrap() and cap_funwrap_mmap() unwrap capabilities, exposing the underlying object. Attempting to unwrap a capability with an inadequate rights mask (e.g. calling cap_funwrap(fp, CAP_WRITE | CAP_MMAP, &result) on a capability whose rights mask is CAP_READ | CAP_MMAP) will result in ENOTCAPABLE. Unwrapping a non-capability is effectively a no-op. These functions will be used by Capsicum-aware versions of _fget(), etc. Approved by: mentor (rwatson), re (Capsicum blanket) Sponsored by: Google Inc Modified: head/sys/kern/sys_capability.c head/sys/sys/capability.h Modified: head/sys/kern/sys_capability.c ============================================================================== --- head/sys/kern/sys_capability.c Mon Jul 4 13:55:55 2011 (r223761) +++ head/sys/kern/sys_capability.c Mon Jul 4 14:40:32 2011 (r223762) @@ -116,3 +116,125 @@ cap_getmode(struct thread *td, struct ca } #endif /* CAPABILITY_MODE */ + +#ifdef CAPABILITIES + +/* + * struct capability describes a capability, and is hung off of its struct + * file f_data field. cap_file and cap_rightss are static once hooked up, as + * neither the object it references nor the rights it encapsulates are + * permitted to change. cap_filelist may change when other capabilites are + * added or removed from the same file, and is currently protected by the + * pool mutex for the object file descriptor. + */ +struct capability { + struct file *cap_object; /* Underlying object's file. */ + struct file *cap_file; /* Back-pointer to cap's file. */ + cap_rights_t cap_rights; /* Mask of rights on object. */ + LIST_ENTRY(capability) cap_filelist; /* Object's cap list. */ +}; + +/* + * Test whether a capability grants the requested rights. + */ +static int +cap_check(struct capability *c, cap_rights_t rights) +{ + + if ((c->cap_rights | rights) != c->cap_rights) + return (ENOTCAPABLE); + return (0); +} + +/* + * Given a file descriptor, test it against a capability rights mask and then + * return the file descriptor on which to actually perform the requested + * operation. As long as the reference to fp_cap remains valid, the returned + * pointer in *fp will remain valid, so no extra reference management is + * required, and the caller should fdrop() fp_cap as normal when done with + * both. + */ +int +cap_funwrap(struct file *fp_cap, cap_rights_t rights, struct file **fpp) +{ + struct capability *c; + int error; + + if (fp_cap->f_type != DTYPE_CAPABILITY) { + *fpp = fp_cap; + return (0); + } + c = fp_cap->f_data; + error = cap_check(c, rights); + if (error) + return (error); + *fpp = c->cap_object; + return (0); +} + +/* + * Slightly different routine for memory mapping file descriptors: unwrap the + * capability and check CAP_MMAP, but also return a bitmask representing the + * maximum mapping rights the capability allows on the object. + */ +int +cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, u_char *maxprotp, + struct file **fpp) +{ + struct capability *c; + u_char maxprot; + int error; + + if (fp_cap->f_type != DTYPE_CAPABILITY) { + *fpp = fp_cap; + *maxprotp = VM_PROT_ALL; + return (0); + } + c = fp_cap->f_data; + error = cap_check(c, rights | CAP_MMAP); + if (error) + return (error); + *fpp = c->cap_object; + maxprot = 0; + if (c->cap_rights & CAP_READ) + maxprot |= VM_PROT_READ; + if (c->cap_rights & CAP_WRITE) + maxprot |= VM_PROT_WRITE; + if (c->cap_rights & CAP_MAPEXEC) + maxprot |= VM_PROT_EXECUTE; + *maxprotp = maxprot; + return (0); +} + +#else /* !CAPABILITIES */ + +/* + * Stub Capability functions for when options CAPABILITIES isn't compiled + * into the kernel. + */ +int +cap_funwrap(struct file *fp_cap, cap_rights_t rights, struct file **fpp) +{ + + KASSERT(fp_cap->f_type != DTYPE_CAPABILITY, + ("cap_funwrap: saw capability")); + + *fpp = fp_cap; + return (0); +} + +int +cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, u_char *maxprotp, + struct file **fpp) +{ + + KASSERT(fp_cap->f_type != DTYPE_CAPABILITY, + ("cap_funwrap_mmap: saw capability")); + + *fpp = fp_cap; + *maxprotp = VM_PROT_ALL; + return (0); +} + +#endif /* CAPABILITIES */ + Modified: head/sys/sys/capability.h ============================================================================== --- head/sys/sys/capability.h Mon Jul 4 13:55:55 2011 (r223761) +++ head/sys/sys/capability.h Mon Jul 4 14:40:32 2011 (r223762) @@ -38,10 +38,50 @@ #include #include +#include + +/* + * Possible rights on capabilities. + * + * Notes: + * Some system calls don't require a capability in order to perform an + * operation on an fd. These include: close, dup, dup2. + * + * sendfile is authorized using CAP_READ on the file and CAP_WRITE on the + * socket. + * + * mmap() and aio*() system calls will need special attention as they may + * involve reads or writes depending a great deal on context. + */ +#define CAP_READ 0x0000000000000001ULL /* read/recv */ +#define CAP_WRITE 0x0000000000000002ULL /* write/send */ +#define CAP_MMAP 0x0000000000000004ULL /* mmap */ +#define CAP_MAPEXEC 0x0000000000000008ULL /* mmap(2) as exec */ +#define CAP_MASK_VALID 0x000000000000000fULL + #ifdef _KERNEL #define IN_CAPABILITY_MODE(td) (td->td_ucred->cr_flags & CRED_FLAG_CAPMODE) +/* + * Unwrap a capability if its rights mask is a superset of 'rights'. + * + * Unwrapping a non-capability is effectively a no-op; the value of fp_cap + * is simply copied into fpp. + */ +int cap_funwrap(struct file *fp_cap, cap_rights_t rights, + struct file **fpp); +int cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, + u_char *maxprotp, struct file **fpp); + +/* + * For the purposes of procstat(1) and similar tools, allow kern_descrip.c to + * extract the rights from a capability. However, this should not be used by + * kernel code generally, instead cap_funwrap() should be used in order to + * keep all access control in one place. + */ +cap_rights_t cap_rights(struct file *fp_cap); + #else /* !_KERNEL */ __BEGIN_DECLS