diff options
Diffstat (limited to 'sys/kern/sys_capability.c')
-rw-r--r-- | sys/kern/sys_capability.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index a19e881..8216bea 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -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 */ + |