1219129Srwatson/*- 2219129Srwatson * Copyright (c) 2008-2011 Robert N. M. Watson 3219129Srwatson * Copyright (c) 2010-2011 Jonathan Anderson 4247602Spjd * Copyright (c) 2012 FreeBSD Foundation 5219129Srwatson * All rights reserved. 6219129Srwatson * 7219129Srwatson * This software was developed at the University of Cambridge Computer 8219129Srwatson * Laboratory with support from a grant from Google, Inc. 9219129Srwatson * 10247602Spjd * Portions of this software were developed by Pawel Jakub Dawidek under 11247602Spjd * sponsorship from the FreeBSD Foundation. 12247602Spjd * 13219129Srwatson * Redistribution and use in source and binary forms, with or without 14219129Srwatson * modification, are permitted provided that the following conditions 15219129Srwatson * are met: 16219129Srwatson * 1. Redistributions of source code must retain the above copyright 17219129Srwatson * notice, this list of conditions and the following disclaimer. 18219129Srwatson * 2. Redistributions in binary form must reproduce the above copyright 19219129Srwatson * notice, this list of conditions and the following disclaimer in the 20219129Srwatson * documentation and/or other materials provided with the distribution. 21219129Srwatson * 22219129Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23219129Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24219129Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25219129Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26219129Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27219129Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28219129Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29219129Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30219129Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31219129Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32219129Srwatson * SUCH DAMAGE. 33219129Srwatson */ 34219129Srwatson 35219129Srwatson/* 36219129Srwatson * FreeBSD kernel capability facility. 37219129Srwatson * 38224839Srwatson * Two kernel features are implemented here: capability mode, a sandboxed mode 39224839Srwatson * of execution for processes, and capabilities, a refinement on file 40224839Srwatson * descriptors that allows fine-grained control over operations on the file 41224839Srwatson * descriptor. Collectively, these allow processes to run in the style of a 42224839Srwatson * historic "capability system" in which they can use only resources 43224839Srwatson * explicitly delegated to them. This model is enforced by restricting access 44224839Srwatson * to global namespaces in capability mode. 45219129Srwatson * 46224839Srwatson * Capabilities wrap other file descriptor types, binding them to a constant 47224839Srwatson * rights mask set when the capability is created. New capabilities may be 48224839Srwatson * derived from existing capabilities, but only if they have the same or a 49224839Srwatson * strict subset of the rights on the original capability. 50224839Srwatson * 51224839Srwatson * System calls permitted in capability mode are defined in capabilities.conf; 52224839Srwatson * calls must be carefully audited for safety to ensure that they don't allow 53224839Srwatson * escape from a sandbox. Some calls permit only a subset of operations in 54224839Srwatson * capability mode -- for example, shm_open(2) is limited to creating 55224839Srwatson * anonymous, rather than named, POSIX shared memory objects. 56219129Srwatson */ 57219129Srwatson 58236858Spjd#include <sys/cdefs.h> 59236858Spjd__FBSDID("$FreeBSD$"); 60236858Spjd 61223668Sjonathan#include "opt_capsicum.h" 62226269Sdes#include "opt_ktrace.h" 63219129Srwatson 64219129Srwatson#include <sys/param.h> 65219129Srwatson#include <sys/capability.h> 66219129Srwatson#include <sys/file.h> 67219129Srwatson#include <sys/filedesc.h> 68219129Srwatson#include <sys/kernel.h> 69247602Spjd#include <sys/limits.h> 70219129Srwatson#include <sys/lock.h> 71219129Srwatson#include <sys/mutex.h> 72219129Srwatson#include <sys/proc.h> 73254481Spjd#include <sys/syscallsubr.h> 74219129Srwatson#include <sys/sysproto.h> 75219129Srwatson#include <sys/sysctl.h> 76219129Srwatson#include <sys/systm.h> 77219129Srwatson#include <sys/ucred.h> 78226269Sdes#include <sys/uio.h> 79226269Sdes#include <sys/ktrace.h> 80219129Srwatson 81219129Srwatson#include <security/audit/audit.h> 82219129Srwatson 83219129Srwatson#include <vm/uma.h> 84219129Srwatson#include <vm/vm.h> 85219129Srwatson 86223668Sjonathan#ifdef CAPABILITY_MODE 87219129Srwatson 88224840SrwatsonFEATURE(security_capability_mode, "Capsicum Capability Mode"); 89219258Snetchild 90219129Srwatson/* 91219129Srwatson * System call to enter capability mode for the process. 92219129Srwatson */ 93219129Srwatsonint 94225617Skmacysys_cap_enter(struct thread *td, struct cap_enter_args *uap) 95219129Srwatson{ 96219129Srwatson struct ucred *newcred, *oldcred; 97219129Srwatson struct proc *p; 98219129Srwatson 99219129Srwatson if (IN_CAPABILITY_MODE(td)) 100219129Srwatson return (0); 101219129Srwatson 102219129Srwatson newcred = crget(); 103219129Srwatson p = td->td_proc; 104219129Srwatson PROC_LOCK(p); 105219129Srwatson oldcred = p->p_ucred; 106219129Srwatson crcopy(newcred, oldcred); 107219129Srwatson newcred->cr_flags |= CRED_FLAG_CAPMODE; 108219129Srwatson p->p_ucred = newcred; 109219129Srwatson PROC_UNLOCK(p); 110219129Srwatson crfree(oldcred); 111219129Srwatson return (0); 112219129Srwatson} 113219129Srwatson 114219129Srwatson/* 115219129Srwatson * System call to query whether the process is in capability mode. 116219129Srwatson */ 117219129Srwatsonint 118225617Skmacysys_cap_getmode(struct thread *td, struct cap_getmode_args *uap) 119219129Srwatson{ 120219129Srwatson u_int i; 121219129Srwatson 122246908Spjd i = IN_CAPABILITY_MODE(td) ? 1 : 0; 123219129Srwatson return (copyout(&i, uap->modep, sizeof(i))); 124219129Srwatson} 125219129Srwatson 126223668Sjonathan#else /* !CAPABILITY_MODE */ 127219129Srwatson 128219129Srwatsonint 129225617Skmacysys_cap_enter(struct thread *td, struct cap_enter_args *uap) 130219129Srwatson{ 131219129Srwatson 132219129Srwatson return (ENOSYS); 133219129Srwatson} 134219129Srwatson 135219129Srwatsonint 136225617Skmacysys_cap_getmode(struct thread *td, struct cap_getmode_args *uap) 137219129Srwatson{ 138219129Srwatson 139219129Srwatson return (ENOSYS); 140219129Srwatson} 141219129Srwatson 142223668Sjonathan#endif /* CAPABILITY_MODE */ 143223762Sjonathan 144223762Sjonathan#ifdef CAPABILITIES 145223762Sjonathan 146224840SrwatsonFEATURE(security_capabilities, "Capsicum Capabilities"); 147224840Srwatson 148250944SpjdMALLOC_DECLARE(M_FILECAPS); 149250944Spjd 150247602Spjdstatic inline int 151255219Spjd_cap_check(const cap_rights_t *havep, const cap_rights_t *needp, 152255219Spjd enum ktr_cap_fail_type type) 153247602Spjd{ 154255219Spjd int i; 155223762Sjonathan 156255219Spjd for (i = 0; i < nitems(havep->cr_rights); i++) { 157255219Spjd if (!cap_rights_contains(havep, needp)) { 158247602Spjd#ifdef KTRACE 159255219Spjd if (KTRPOINT(curthread, KTR_CAPFAIL)) 160255219Spjd ktrcapfail(type, needp, havep); 161247602Spjd#endif 162255219Spjd return (ENOTCAPABLE); 163255219Spjd } 164247602Spjd } 165247602Spjd return (0); 166247602Spjd} 167247602Spjd 168223762Sjonathan/* 169247602Spjd * Test whether a capability grants the requested rights. 170224056Sjonathan */ 171247602Spjdint 172255219Spjdcap_check(const cap_rights_t *havep, const cap_rights_t *needp) 173224056Sjonathan{ 174224056Sjonathan 175255219Spjd return (_cap_check(havep, needp, CAPFAIL_NOTCAPABLE)); 176224056Sjonathan} 177224056Sjonathan 178224056Sjonathan/* 179247602Spjd * Convert capability rights into VM access flags. 180223762Sjonathan */ 181247602Spjdu_char 182255219Spjdcap_rights_to_vmprot(cap_rights_t *havep) 183223762Sjonathan{ 184247602Spjd u_char maxprot; 185223762Sjonathan 186247602Spjd maxprot = VM_PROT_NONE; 187255219Spjd if (cap_rights_is_set(havep, CAP_MMAP_R)) 188247602Spjd maxprot |= VM_PROT_READ; 189255219Spjd if (cap_rights_is_set(havep, CAP_MMAP_W)) 190247602Spjd maxprot |= VM_PROT_WRITE; 191255219Spjd if (cap_rights_is_set(havep, CAP_MMAP_X)) 192247602Spjd maxprot |= VM_PROT_EXECUTE; 193247602Spjd 194247602Spjd return (maxprot); 195223762Sjonathan} 196223762Sjonathan 197223762Sjonathan/* 198224056Sjonathan * Extract rights from a capability for monitoring purposes -- not for use in 199224056Sjonathan * any other way, as we want to keep all capability permission evaluation in 200224056Sjonathan * this one file. 201224056Sjonathan */ 202273137Smjg 203255219Spjdcap_rights_t * 204273137Smjgcap_rights_fde(struct filedescent *fde) 205273137Smjg{ 206273137Smjg 207273137Smjg return (&fde->fde_rights); 208273137Smjg} 209273137Smjg 210273137Smjgcap_rights_t * 211247602Spjdcap_rights(struct filedesc *fdp, int fd) 212224056Sjonathan{ 213224056Sjonathan 214273137Smjg return (cap_rights_fde(&fdp->fd_ofiles[fd])); 215224056Sjonathan} 216224056Sjonathan 217224056Sjonathan/* 218247602Spjd * System call to limit rights of the given capability. 219224066Sjonathan */ 220224066Sjonathanint 221247602Spjdsys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) 222224066Sjonathan{ 223247602Spjd struct filedesc *fdp; 224247602Spjd cap_rights_t rights; 225255219Spjd int error, fd, version; 226224066Sjonathan 227255219Spjd cap_rights_init(&rights); 228255219Spjd 229255219Spjd error = copyin(uap->rightsp, &rights, sizeof(rights.cr_rights[0])); 230255219Spjd if (error != 0) 231255219Spjd return (error); 232255219Spjd version = CAPVER(&rights); 233255219Spjd if (version != CAP_RIGHTS_VERSION_00) 234255219Spjd return (EINVAL); 235255219Spjd 236255219Spjd error = copyin(uap->rightsp, &rights, 237255219Spjd sizeof(rights.cr_rights[0]) * CAPARSIZE(&rights)); 238255219Spjd if (error != 0) 239255219Spjd return (error); 240255219Spjd /* Check for race. */ 241255219Spjd if (CAPVER(&rights) != version) 242255219Spjd return (EINVAL); 243255219Spjd 244255219Spjd if (!cap_rights_is_valid(&rights)) 245255219Spjd return (EINVAL); 246255219Spjd 247255219Spjd if (version != CAP_RIGHTS_VERSION) { 248255219Spjd rights.cr_rights[0] &= ~(0x3ULL << 62); 249255219Spjd rights.cr_rights[0] |= ((uint64_t)CAP_RIGHTS_VERSION << 62); 250255219Spjd } 251255219Spjd#ifdef KTRACE 252255219Spjd if (KTRPOINT(td, KTR_STRUCT)) 253255219Spjd ktrcaprights(&rights); 254255219Spjd#endif 255255219Spjd 256247602Spjd fd = uap->fd; 257247602Spjd 258224066Sjonathan AUDIT_ARG_FD(fd); 259255219Spjd AUDIT_ARG_RIGHTS(&rights); 260247602Spjd 261247602Spjd fdp = td->td_proc->p_fd; 262247602Spjd FILEDESC_XLOCK(fdp); 263247602Spjd if (fget_locked(fdp, fd) == NULL) { 264247602Spjd FILEDESC_XUNLOCK(fdp); 265247602Spjd return (EBADF); 266247602Spjd } 267255219Spjd error = _cap_check(cap_rights(fdp, fd), &rights, CAPFAIL_INCREASE); 268247602Spjd if (error == 0) { 269247602Spjd fdp->fd_ofiles[fd].fde_rights = rights; 270255219Spjd if (!cap_rights_is_set(&rights, CAP_IOCTL)) { 271250944Spjd free(fdp->fd_ofiles[fd].fde_ioctls, M_FILECAPS); 272247602Spjd fdp->fd_ofiles[fd].fde_ioctls = NULL; 273247602Spjd fdp->fd_ofiles[fd].fde_nioctls = 0; 274247602Spjd } 275255219Spjd if (!cap_rights_is_set(&rights, CAP_FCNTL)) 276247602Spjd fdp->fd_ofiles[fd].fde_fcntls = 0; 277247602Spjd } 278247602Spjd FILEDESC_XUNLOCK(fdp); 279232860Spho return (error); 280224066Sjonathan} 281224066Sjonathan 282224066Sjonathan/* 283224066Sjonathan * System call to query the rights mask associated with a capability. 284224066Sjonathan */ 285224066Sjonathanint 286255219Spjdsys___cap_rights_get(struct thread *td, struct __cap_rights_get_args *uap) 287224066Sjonathan{ 288247602Spjd struct filedesc *fdp; 289247602Spjd cap_rights_t rights; 290255219Spjd int error, fd, i, n; 291224066Sjonathan 292255219Spjd if (uap->version != CAP_RIGHTS_VERSION_00) 293255219Spjd return (EINVAL); 294255219Spjd 295247602Spjd fd = uap->fd; 296247602Spjd 297247602Spjd AUDIT_ARG_FD(fd); 298247602Spjd 299247602Spjd fdp = td->td_proc->p_fd; 300247602Spjd FILEDESC_SLOCK(fdp); 301247602Spjd if (fget_locked(fdp, fd) == NULL) { 302247602Spjd FILEDESC_SUNLOCK(fdp); 303247602Spjd return (EBADF); 304247602Spjd } 305255219Spjd rights = *cap_rights(fdp, fd); 306247602Spjd FILEDESC_SUNLOCK(fdp); 307255219Spjd n = uap->version + 2; 308255219Spjd if (uap->version != CAPVER(&rights)) { 309255219Spjd /* 310255219Spjd * For older versions we need to check if the descriptor 311255219Spjd * doesn't contain rights not understood by the caller. 312255219Spjd * If it does, we have to return an error. 313255219Spjd */ 314255219Spjd for (i = n; i < CAPARSIZE(&rights); i++) { 315255219Spjd if ((rights.cr_rights[i] & ~(0x7FULL << 57)) != 0) 316255219Spjd return (EINVAL); 317255219Spjd } 318255219Spjd } 319255219Spjd error = copyout(&rights, uap->rightsp, sizeof(rights.cr_rights[0]) * n); 320255219Spjd#ifdef KTRACE 321255219Spjd if (error == 0 && KTRPOINT(td, KTR_STRUCT)) 322255219Spjd ktrcaprights(&rights); 323255219Spjd#endif 324255219Spjd return (error); 325224066Sjonathan} 326224066Sjonathan 327224066Sjonathan/* 328247602Spjd * Test whether a capability grants the given ioctl command. 329247602Spjd * If descriptor doesn't have CAP_IOCTL, then ioctls list is empty and 330247602Spjd * ENOTCAPABLE will be returned. 331224056Sjonathan */ 332224056Sjonathanint 333247602Spjdcap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd) 334224056Sjonathan{ 335247602Spjd u_long *cmds; 336247602Spjd ssize_t ncmds; 337247602Spjd long i; 338224056Sjonathan 339247602Spjd FILEDESC_LOCK_ASSERT(fdp); 340247602Spjd KASSERT(fd >= 0 && fd < fdp->fd_nfiles, 341247602Spjd ("%s: invalid fd=%d", __func__, fd)); 342224056Sjonathan 343247602Spjd ncmds = fdp->fd_ofiles[fd].fde_nioctls; 344247602Spjd if (ncmds == -1) 345247602Spjd return (0); 346247602Spjd 347247602Spjd cmds = fdp->fd_ofiles[fd].fde_ioctls; 348247602Spjd for (i = 0; i < ncmds; i++) { 349247602Spjd if (cmds[i] == cmd) 350247602Spjd return (0); 351224056Sjonathan } 352224056Sjonathan 353247602Spjd return (ENOTCAPABLE); 354224056Sjonathan} 355224056Sjonathan 356224056Sjonathan/* 357247602Spjd * Check if the current ioctls list can be replaced by the new one. 358223762Sjonathan */ 359247602Spjdstatic int 360247602Spjdcap_ioctl_limit_check(struct filedesc *fdp, int fd, const u_long *cmds, 361247602Spjd size_t ncmds) 362223762Sjonathan{ 363247602Spjd u_long *ocmds; 364247602Spjd ssize_t oncmds; 365247602Spjd u_long i; 366247602Spjd long j; 367223762Sjonathan 368247602Spjd oncmds = fdp->fd_ofiles[fd].fde_nioctls; 369247602Spjd if (oncmds == -1) 370223762Sjonathan return (0); 371247602Spjd if (oncmds < (ssize_t)ncmds) 372247602Spjd return (ENOTCAPABLE); 373247602Spjd 374247602Spjd ocmds = fdp->fd_ofiles[fd].fde_ioctls; 375247602Spjd for (i = 0; i < ncmds; i++) { 376247602Spjd for (j = 0; j < oncmds; j++) { 377247602Spjd if (cmds[i] == ocmds[j]) 378247602Spjd break; 379247602Spjd } 380247602Spjd if (j == oncmds) 381247602Spjd return (ENOTCAPABLE); 382223762Sjonathan } 383247602Spjd 384223762Sjonathan return (0); 385223762Sjonathan} 386223762Sjonathan 387223762Sjonathanint 388254481Spjdkern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds) 389223762Sjonathan{ 390247602Spjd struct filedesc *fdp; 391254481Spjd u_long *ocmds; 392254481Spjd int error; 393223762Sjonathan 394247602Spjd AUDIT_ARG_FD(fd); 395247602Spjd 396247602Spjd fdp = td->td_proc->p_fd; 397247602Spjd FILEDESC_XLOCK(fdp); 398247602Spjd 399247602Spjd if (fget_locked(fdp, fd) == NULL) { 400247602Spjd error = EBADF; 401247602Spjd goto out; 402247602Spjd } 403247602Spjd 404247602Spjd error = cap_ioctl_limit_check(fdp, fd, cmds, ncmds); 405247602Spjd if (error != 0) 406247602Spjd goto out; 407247602Spjd 408247602Spjd ocmds = fdp->fd_ofiles[fd].fde_ioctls; 409247602Spjd fdp->fd_ofiles[fd].fde_ioctls = cmds; 410247602Spjd fdp->fd_ofiles[fd].fde_nioctls = ncmds; 411247602Spjd 412247602Spjd cmds = ocmds; 413247602Spjd error = 0; 414247602Spjdout: 415247602Spjd FILEDESC_XUNLOCK(fdp); 416250944Spjd free(cmds, M_FILECAPS); 417247602Spjd return (error); 418223762Sjonathan} 419223762Sjonathan 420247602Spjdint 421254481Spjdsys_cap_ioctls_limit(struct thread *td, struct cap_ioctls_limit_args *uap) 422254481Spjd{ 423254481Spjd u_long *cmds; 424254481Spjd size_t ncmds; 425254481Spjd int error; 426254481Spjd 427254481Spjd ncmds = uap->ncmds; 428254481Spjd 429254481Spjd if (ncmds > 256) /* XXX: Is 256 sane? */ 430254481Spjd return (EINVAL); 431254481Spjd 432254481Spjd if (ncmds == 0) { 433254481Spjd cmds = NULL; 434254481Spjd } else { 435254481Spjd cmds = malloc(sizeof(cmds[0]) * ncmds, M_FILECAPS, M_WAITOK); 436254481Spjd error = copyin(uap->cmds, cmds, sizeof(cmds[0]) * ncmds); 437254481Spjd if (error != 0) { 438254481Spjd free(cmds, M_FILECAPS); 439254481Spjd return (error); 440254481Spjd } 441254481Spjd } 442254481Spjd 443254481Spjd return (kern_cap_ioctls_limit(td, uap->fd, cmds, ncmds)); 444254481Spjd} 445254481Spjd 446254481Spjdint 447247602Spjdsys_cap_ioctls_get(struct thread *td, struct cap_ioctls_get_args *uap) 448224056Sjonathan{ 449247602Spjd struct filedesc *fdp; 450247602Spjd struct filedescent *fdep; 451247602Spjd u_long *cmds; 452247602Spjd size_t maxcmds; 453247602Spjd int error, fd; 454224056Sjonathan 455247602Spjd fd = uap->fd; 456247602Spjd cmds = uap->cmds; 457247602Spjd maxcmds = uap->maxcmds; 458224056Sjonathan 459247602Spjd AUDIT_ARG_FD(fd); 460247602Spjd 461247602Spjd fdp = td->td_proc->p_fd; 462247602Spjd FILEDESC_SLOCK(fdp); 463247602Spjd 464247602Spjd if (fget_locked(fdp, fd) == NULL) { 465247602Spjd error = EBADF; 466247602Spjd goto out; 467247602Spjd } 468247602Spjd 469247602Spjd /* 470247602Spjd * If all ioctls are allowed (fde_nioctls == -1 && fde_ioctls == NULL) 471247602Spjd * the only sane thing we can do is to not populate the given array and 472247602Spjd * return CAP_IOCTLS_ALL. 473247602Spjd */ 474247602Spjd 475247602Spjd fdep = &fdp->fd_ofiles[fd]; 476247602Spjd if (cmds != NULL && fdep->fde_ioctls != NULL) { 477247602Spjd error = copyout(fdep->fde_ioctls, cmds, 478247602Spjd sizeof(cmds[0]) * MIN(fdep->fde_nioctls, maxcmds)); 479247602Spjd if (error != 0) 480247602Spjd goto out; 481247602Spjd } 482247602Spjd if (fdep->fde_nioctls == -1) 483247602Spjd td->td_retval[0] = CAP_IOCTLS_ALL; 484247602Spjd else 485247602Spjd td->td_retval[0] = fdep->fde_nioctls; 486247602Spjd 487247602Spjd error = 0; 488247602Spjdout: 489247602Spjd FILEDESC_SUNLOCK(fdp); 490247602Spjd return (error); 491224056Sjonathan} 492224056Sjonathan 493224056Sjonathan/* 494247602Spjd * Test whether a capability grants the given fcntl command. 495224056Sjonathan */ 496247602Spjdint 497273137Smjgcap_fcntl_check_fde(struct filedescent *fde, int cmd) 498224056Sjonathan{ 499247602Spjd uint32_t fcntlcap; 500224056Sjonathan 501247602Spjd fcntlcap = (1 << cmd); 502247602Spjd KASSERT((CAP_FCNTL_ALL & fcntlcap) != 0, 503247602Spjd ("Unsupported fcntl=%d.", cmd)); 504224056Sjonathan 505273137Smjg if ((fde->fde_fcntls & fcntlcap) != 0) 506247602Spjd return (0); 507247602Spjd 508247602Spjd return (ENOTCAPABLE); 509224056Sjonathan} 510224056Sjonathan 511247602Spjdint 512273137Smjgcap_fcntl_check(struct filedesc *fdp, int fd, int cmd) 513273137Smjg{ 514273137Smjg 515273137Smjg KASSERT(fd >= 0 && fd < fdp->fd_nfiles, 516273137Smjg ("%s: invalid fd=%d", __func__, fd)); 517273137Smjg 518273137Smjg return (cap_fcntl_check_fde(&fdp->fd_ofiles[fd], cmd)); 519273137Smjg} 520273137Smjg 521273137Smjgint 522247602Spjdsys_cap_fcntls_limit(struct thread *td, struct cap_fcntls_limit_args *uap) 523224056Sjonathan{ 524247602Spjd struct filedesc *fdp; 525247602Spjd uint32_t fcntlrights; 526247602Spjd int fd; 527224056Sjonathan 528247602Spjd fd = uap->fd; 529247602Spjd fcntlrights = uap->fcntlrights; 530224056Sjonathan 531247602Spjd AUDIT_ARG_FD(fd); 532247602Spjd AUDIT_ARG_FCNTL_RIGHTS(fcntlrights); 533224056Sjonathan 534247602Spjd if ((fcntlrights & ~CAP_FCNTL_ALL) != 0) 535247602Spjd return (EINVAL); 536224056Sjonathan 537247602Spjd fdp = td->td_proc->p_fd; 538247602Spjd FILEDESC_XLOCK(fdp); 539224056Sjonathan 540247602Spjd if (fget_locked(fdp, fd) == NULL) { 541247602Spjd FILEDESC_XUNLOCK(fdp); 542247602Spjd return (EBADF); 543247602Spjd } 544224056Sjonathan 545247602Spjd if ((fcntlrights & ~fdp->fd_ofiles[fd].fde_fcntls) != 0) { 546247602Spjd FILEDESC_XUNLOCK(fdp); 547247602Spjd return (ENOTCAPABLE); 548247602Spjd } 549224056Sjonathan 550247602Spjd fdp->fd_ofiles[fd].fde_fcntls = fcntlrights; 551247602Spjd FILEDESC_XUNLOCK(fdp); 552224056Sjonathan 553247602Spjd return (0); 554224056Sjonathan} 555224056Sjonathan 556224914Skibint 557247602Spjdsys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap) 558224914Skib{ 559247602Spjd struct filedesc *fdp; 560247602Spjd uint32_t rights; 561247602Spjd int fd; 562224914Skib 563247602Spjd fd = uap->fd; 564247602Spjd 565247602Spjd AUDIT_ARG_FD(fd); 566247602Spjd 567247602Spjd fdp = td->td_proc->p_fd; 568247602Spjd FILEDESC_SLOCK(fdp); 569247602Spjd if (fget_locked(fdp, fd) == NULL) { 570247602Spjd FILEDESC_SUNLOCK(fdp); 571247602Spjd return (EBADF); 572247602Spjd } 573247602Spjd rights = fdp->fd_ofiles[fd].fde_fcntls; 574247602Spjd FILEDESC_SUNLOCK(fdp); 575247602Spjd 576247602Spjd return (copyout(&rights, uap->fcntlrightsp, sizeof(rights))); 577224914Skib} 578224914Skib 579223762Sjonathan#else /* !CAPABILITIES */ 580223762Sjonathan 581223762Sjonathan/* 582223762Sjonathan * Stub Capability functions for when options CAPABILITIES isn't compiled 583223762Sjonathan * into the kernel. 584223762Sjonathan */ 585247602Spjd 586223762Sjonathanint 587247602Spjdsys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) 588224066Sjonathan{ 589224066Sjonathan 590224066Sjonathan return (ENOSYS); 591224066Sjonathan} 592224066Sjonathan 593224066Sjonathanint 594255229Ssbrunosys___cap_rights_get(struct thread *td, struct __cap_rights_get_args *uap) 595224066Sjonathan{ 596224066Sjonathan 597224066Sjonathan return (ENOSYS); 598224066Sjonathan} 599224066Sjonathan 600224066Sjonathanint 601247602Spjdsys_cap_ioctls_limit(struct thread *td, struct cap_ioctls_limit_args *uap) 602223762Sjonathan{ 603223762Sjonathan 604247602Spjd return (ENOSYS); 605247602Spjd} 606223762Sjonathan 607247602Spjdint 608247602Spjdsys_cap_ioctls_get(struct thread *td, struct cap_ioctls_get_args *uap) 609247602Spjd{ 610247602Spjd 611247602Spjd return (ENOSYS); 612223762Sjonathan} 613223762Sjonathan 614223762Sjonathanint 615247602Spjdsys_cap_fcntls_limit(struct thread *td, struct cap_fcntls_limit_args *uap) 616223762Sjonathan{ 617223762Sjonathan 618247602Spjd return (ENOSYS); 619247602Spjd} 620223762Sjonathan 621247602Spjdint 622247602Spjdsys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap) 623247602Spjd{ 624247602Spjd 625247602Spjd return (ENOSYS); 626223762Sjonathan} 627223762Sjonathan 628223762Sjonathan#endif /* CAPABILITIES */ 629