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
This commit is contained in:
parent
f8dd68c912
commit
af098ed8e7
@ -116,3 +116,125 @@ cap_getmode(struct thread *td, struct cap_getmode_args *uap)
|
||||
}
|
||||
|
||||
#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 */
|
||||
|
||||
|
@ -38,10 +38,50 @@
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/file.h>
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
Loading…
Reference in New Issue
Block a user