xref: /dragonfly/sys/kern/kern_caps.c (revision a44776b2)
12b3f93eaSMatthew Dillon /*
22b3f93eaSMatthew Dillon  * Copyright (c) 2023 The DragonFly Project.  All rights reserved.
32b3f93eaSMatthew Dillon  *
42b3f93eaSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
52b3f93eaSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
62b3f93eaSMatthew Dillon  *
72b3f93eaSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
82b3f93eaSMatthew Dillon  * modification, are permitted provided that the following conditions
92b3f93eaSMatthew Dillon  * are met:
102b3f93eaSMatthew Dillon  *
112b3f93eaSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
122b3f93eaSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
132b3f93eaSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
142b3f93eaSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
152b3f93eaSMatthew Dillon  *    the documentation and/or other materials provided with the
162b3f93eaSMatthew Dillon  *    distribution.
172b3f93eaSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
182b3f93eaSMatthew Dillon  *    contributors may be used to endorse or promote products derived
192b3f93eaSMatthew Dillon  *    from this software without specific, prior written permission.
202b3f93eaSMatthew Dillon  *
212b3f93eaSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
222b3f93eaSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
232b3f93eaSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
242b3f93eaSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
252b3f93eaSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
262b3f93eaSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
272b3f93eaSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
282b3f93eaSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
292b3f93eaSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
302b3f93eaSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
312b3f93eaSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322b3f93eaSMatthew Dillon  * SUCH DAMAGE.
332b3f93eaSMatthew Dillon  */
342b3f93eaSMatthew Dillon 
352b3f93eaSMatthew Dillon #include <sys/param.h>
362b3f93eaSMatthew Dillon #include <sys/acct.h>
372b3f93eaSMatthew Dillon #include <sys/caps.h>
382b3f93eaSMatthew Dillon #include <sys/systm.h>
392b3f93eaSMatthew Dillon #include <sys/sysmsg.h>
402b3f93eaSMatthew Dillon #include <sys/kernel.h>
412b3f93eaSMatthew Dillon #include <sys/lock.h>
422b3f93eaSMatthew Dillon #include <sys/proc.h>
432b3f93eaSMatthew Dillon #include <sys/malloc.h>
442b3f93eaSMatthew Dillon #include <sys/pioctl.h>
452b3f93eaSMatthew Dillon #include <sys/resourcevar.h>
462b3f93eaSMatthew Dillon #include <sys/jail.h>
472b3f93eaSMatthew Dillon #include <sys/lockf.h>
482b3f93eaSMatthew Dillon #include <sys/spinlock.h>
492b3f93eaSMatthew Dillon #include <sys/sysctl.h>
502b3f93eaSMatthew Dillon 
512b3f93eaSMatthew Dillon #include <sys/spinlock2.h>
522b3f93eaSMatthew Dillon 
532b3f93eaSMatthew Dillon __read_mostly static int caps_available = 1;
542b3f93eaSMatthew Dillon SYSCTL_INT(_kern, OID_AUTO, caps_available,
552b3f93eaSMatthew Dillon 	   CTLFLAG_RW, &caps_available, 0 , "");
562b3f93eaSMatthew Dillon 
572b3f93eaSMatthew Dillon /*
582b3f93eaSMatthew Dillon  * Quick check for cap restriction in cred (no bounds checks),
592b3f93eaSMatthew Dillon  * return cap flags.
602b3f93eaSMatthew Dillon  */
612b3f93eaSMatthew Dillon static __inline
622b3f93eaSMatthew Dillon int
caps_check_cred(struct ucred * cred,int cap)632b3f93eaSMatthew Dillon caps_check_cred(struct ucred *cred, int cap)
642b3f93eaSMatthew Dillon {
652b3f93eaSMatthew Dillon 	__syscapelm_t elm;
662b3f93eaSMatthew Dillon 
672b3f93eaSMatthew Dillon 	cap &= ~__SYSCAP_XFLAGS;
682b3f93eaSMatthew Dillon 	elm = cred->cr_caps.caps[__SYSCAP_INDEX(cap)];
692b3f93eaSMatthew Dillon 
702b3f93eaSMatthew Dillon 	return ((int)(elm >> __SYSCAP_SHIFT(cap)) & __SYSCAP_ALL);
712b3f93eaSMatthew Dillon }
722b3f93eaSMatthew Dillon 
732b3f93eaSMatthew Dillon /*
742b3f93eaSMatthew Dillon  * int syscap_get(int cap, void *data, size_t bytes);
752b3f93eaSMatthew Dillon  */
762b3f93eaSMatthew Dillon int
sys_syscap_get(struct sysmsg * sysmsg,const struct syscap_get_args * uap)772b3f93eaSMatthew Dillon sys_syscap_get(struct sysmsg *sysmsg, const struct syscap_get_args *uap)
782b3f93eaSMatthew Dillon {
792b3f93eaSMatthew Dillon 	struct ucred *cred;
802b3f93eaSMatthew Dillon 	int cap = uap->cap & ~__SYSCAP_XFLAGS;
812b3f93eaSMatthew Dillon 	int res;
822b3f93eaSMatthew Dillon 	int error;
832b3f93eaSMatthew Dillon 
842b3f93eaSMatthew Dillon 	if (cap < 0)
852b3f93eaSMatthew Dillon 		return EINVAL;
862b3f93eaSMatthew Dillon 	if (cap >= __SYSCAP_COUNT)
872b3f93eaSMatthew Dillon 		return EOPNOTSUPP;
882b3f93eaSMatthew Dillon 	if (uap->bytes && uap->bytes < sizeof(syscap_base_t))
892b3f93eaSMatthew Dillon 		return EINVAL;
902b3f93eaSMatthew Dillon 	error = 0;
912b3f93eaSMatthew Dillon 
922b3f93eaSMatthew Dillon 	/*
932b3f93eaSMatthew Dillon 	 * Get capability restriction from parent pid
942b3f93eaSMatthew Dillon 	 */
952b3f93eaSMatthew Dillon 	if (uap->cap & __SYSCAP_INPARENT) {
962b3f93eaSMatthew Dillon 		struct proc *pp;
972b3f93eaSMatthew Dillon 
982b3f93eaSMatthew Dillon 		pp = pfind(curproc->p_ppid);
992b3f93eaSMatthew Dillon 		if (pp == NULL)
1002b3f93eaSMatthew Dillon 			return EINVAL;
1012b3f93eaSMatthew Dillon                 lwkt_gettoken_shared(&pp->p_token);	/* protect cred */
1022b3f93eaSMatthew Dillon 		cred = pp->p_ucred;
1032b3f93eaSMatthew Dillon 		crhold(cred);
1042b3f93eaSMatthew Dillon                 lwkt_reltoken(&pp->p_token);
1052b3f93eaSMatthew Dillon 		PRELE(pp);				/* from pfind */
1062b3f93eaSMatthew Dillon 	} else {
1072b3f93eaSMatthew Dillon 		cred = curthread->td_ucred;
1082b3f93eaSMatthew Dillon 	}
1092b3f93eaSMatthew Dillon 
1102b3f93eaSMatthew Dillon 	/*
1112b3f93eaSMatthew Dillon 	 * No resource data by default
1122b3f93eaSMatthew Dillon 	 */
1132b3f93eaSMatthew Dillon 	if (uap->data && uap->bytes) {
1142b3f93eaSMatthew Dillon 		syscap_base_t base;
1152b3f93eaSMatthew Dillon 
1162b3f93eaSMatthew Dillon 		base.res = SYSCAP_RESOURCE_EOF;
1172b3f93eaSMatthew Dillon 		base.len = sizeof(base);
1182b3f93eaSMatthew Dillon 		error = copyout(&base, uap->data, sizeof(base));
1192b3f93eaSMatthew Dillon 	}
1202b3f93eaSMatthew Dillon 
1212b3f93eaSMatthew Dillon 	/*
1222b3f93eaSMatthew Dillon 	 * Get resource bits
1232b3f93eaSMatthew Dillon 	 */
1242b3f93eaSMatthew Dillon 	if (error == 0) {
1252b3f93eaSMatthew Dillon 		res = (int)(cred->cr_caps.caps[__SYSCAP_INDEX(cap)] >>
1262b3f93eaSMatthew Dillon 			    __SYSCAP_SHIFT(cap));
1272b3f93eaSMatthew Dillon 		res &= __SYSCAP_BITS_MASK;
1282b3f93eaSMatthew Dillon 		sysmsg->sysmsg_result = res;
1292b3f93eaSMatthew Dillon 	}
1302b3f93eaSMatthew Dillon 
1312b3f93eaSMatthew Dillon 	if (uap->cap & __SYSCAP_INPARENT)
1322b3f93eaSMatthew Dillon 		crfree(cred);
1332b3f93eaSMatthew Dillon 
1342b3f93eaSMatthew Dillon 	return error;
1352b3f93eaSMatthew Dillon }
1362b3f93eaSMatthew Dillon 
1372b3f93eaSMatthew Dillon /*
1382b3f93eaSMatthew Dillon  * int syscap_set(int cap, int flags, const void *data, size_t bytes)
1392b3f93eaSMatthew Dillon  */
1402b3f93eaSMatthew Dillon int
sys_syscap_set(struct sysmsg * sysmsg,const struct syscap_set_args * uap)1412b3f93eaSMatthew Dillon sys_syscap_set(struct sysmsg *sysmsg, const struct syscap_set_args *uap)
1422b3f93eaSMatthew Dillon {
1432b3f93eaSMatthew Dillon 	struct ucred *cred;
1442b3f93eaSMatthew Dillon 	struct proc *pp;
1452b3f93eaSMatthew Dillon 	int cap = uap->cap & ~__SYSCAP_XFLAGS;
1462b3f93eaSMatthew Dillon 	int res;
1472b3f93eaSMatthew Dillon 	int error;
1482b3f93eaSMatthew Dillon 	int flags = uap->flags;
1492b3f93eaSMatthew Dillon 	__syscapelm_t anymask;
1502b3f93eaSMatthew Dillon 
1512b3f93eaSMatthew Dillon 	if (cap < 0 || cap >= __SYSCAP_COUNT)
1522b3f93eaSMatthew Dillon 		return EINVAL;
1532b3f93eaSMatthew Dillon 	if (flags & ~__SYSCAP_BITS_MASK)
1542b3f93eaSMatthew Dillon 		return EINVAL;
1552b3f93eaSMatthew Dillon 	if (uap->data || uap->bytes)
1562b3f93eaSMatthew Dillon 		return EINVAL;
1572b3f93eaSMatthew Dillon 	error = 0;
1582b3f93eaSMatthew Dillon 
1592b3f93eaSMatthew Dillon 	/*
1602b3f93eaSMatthew Dillon 	 * Get capability restriction from parent pid.  We can only
1612b3f93eaSMatthew Dillon 	 * mess with the parent if it is running under the same userid
1622b3f93eaSMatthew Dillon 	 * and prison.
1632b3f93eaSMatthew Dillon 	 */
1642b3f93eaSMatthew Dillon 	if (uap->cap & __SYSCAP_INPARENT) {
1652b3f93eaSMatthew Dillon 		pp = pfind(curproc->p_ppid);
1662b3f93eaSMatthew Dillon 		if (pp == NULL)
1672b3f93eaSMatthew Dillon 			return EINVAL;
1682b3f93eaSMatthew Dillon 		if (pp->p_ucred->cr_uid != curproc->p_ucred->cr_uid ||
1692b3f93eaSMatthew Dillon 		    pp->p_ucred->cr_prison != curproc->p_ucred->cr_prison)
1702b3f93eaSMatthew Dillon 		{
1712b3f93eaSMatthew Dillon 			PRELE(pp);		/* from pfind */
1722b3f93eaSMatthew Dillon 			return EINVAL;
1732b3f93eaSMatthew Dillon 		}
1742b3f93eaSMatthew Dillon 	} else {
1752b3f93eaSMatthew Dillon 		pp = curproc;
1762b3f93eaSMatthew Dillon 	}
1772b3f93eaSMatthew Dillon 	lwkt_gettoken(&pp->p_token);		/* protect p_ucred */
1782b3f93eaSMatthew Dillon 	cred = pp->p_ucred;
1792b3f93eaSMatthew Dillon 
1802b3f93eaSMatthew Dillon 	/*
1812b3f93eaSMatthew Dillon 	 * Calculate normalized value for requested capability and check
1822b3f93eaSMatthew Dillon 	 * against the stored value.  If they do not match, wire-or to
1832b3f93eaSMatthew Dillon 	 * add the bits and set appropriate SYSCAP_ANY bits indicating
1842b3f93eaSMatthew Dillon 	 * deviation from the root syscaps.
1852b3f93eaSMatthew Dillon 	 */
1862b3f93eaSMatthew Dillon 	res = (int)(cred->cr_caps.caps[__SYSCAP_INDEX(cap)] >>
1872b3f93eaSMatthew Dillon 		    __SYSCAP_SHIFT(cap));
1882b3f93eaSMatthew Dillon 	res &= __SYSCAP_BITS_MASK;
1892b3f93eaSMatthew Dillon 
1902b3f93eaSMatthew Dillon 	/*
1912b3f93eaSMatthew Dillon 	 * Handle resource data, if any
1922b3f93eaSMatthew Dillon 	 */
1932b3f93eaSMatthew Dillon 
1942b3f93eaSMatthew Dillon 	/*
1952b3f93eaSMatthew Dillon 	 * Set resource bits
1962b3f93eaSMatthew Dillon 	 */
1972b3f93eaSMatthew Dillon 	if (error == 0) {
1982b3f93eaSMatthew Dillon 		if (res != (res | flags)) {
1992b3f93eaSMatthew Dillon 			cred = cratom_proc(pp);
2002b3f93eaSMatthew Dillon 			anymask = (__syscapelm_t)flags <<
2012b3f93eaSMatthew Dillon 				  __SYSCAP_SHIFT(SYSCAP_ANY);
2022b3f93eaSMatthew Dillon 			atomic_set_64(&cred->cr_caps.caps[0], anymask);
2032b3f93eaSMatthew Dillon 			atomic_set_64(&cred->cr_caps.caps[ __SYSCAP_INDEX(cap)],
2042b3f93eaSMatthew Dillon 				      ((__syscapelm_t)uap->flags <<
2052b3f93eaSMatthew Dillon 				       __SYSCAP_SHIFT(cap)));
2062b3f93eaSMatthew Dillon 		}
2072b3f93eaSMatthew Dillon 		sysmsg->sysmsg_result = res | uap->flags;
2082b3f93eaSMatthew Dillon 	}
2092b3f93eaSMatthew Dillon 
2102b3f93eaSMatthew Dillon 	/*
2112b3f93eaSMatthew Dillon 	 * Cleanup
2122b3f93eaSMatthew Dillon 	 */
2132b3f93eaSMatthew Dillon 	lwkt_reltoken(&pp->p_token);
2142b3f93eaSMatthew Dillon 	if (uap->cap & __SYSCAP_INPARENT)
2152b3f93eaSMatthew Dillon 		PRELE(pp);			/* from pfind */
2162b3f93eaSMatthew Dillon 	return error;
2172b3f93eaSMatthew Dillon }
2182b3f93eaSMatthew Dillon 
2192b3f93eaSMatthew Dillon /*
2202b3f93eaSMatthew Dillon  * Adjust capabilities for exec after the point of no return.
2212b3f93eaSMatthew Dillon  *
2222b3f93eaSMatthew Dillon  * This function shifts the EXEC bits into the SELF bits and
2232b3f93eaSMatthew Dillon  * replicates the EXEC bits.
2242b3f93eaSMatthew Dillon  */
2252b3f93eaSMatthew Dillon void
caps_exec(struct proc * p)2262b3f93eaSMatthew Dillon caps_exec(struct proc *p)
2272b3f93eaSMatthew Dillon {
2282b3f93eaSMatthew Dillon 	struct ucred *cred;
2292b3f93eaSMatthew Dillon 	__syscapelm_t elm;
2302b3f93eaSMatthew Dillon 	int changed = 0;
2312b3f93eaSMatthew Dillon 	int i;
2322b3f93eaSMatthew Dillon 
2332b3f93eaSMatthew Dillon 	/*
2342b3f93eaSMatthew Dillon 	 * Dry-run caps inheritance, did anything change?
2352b3f93eaSMatthew Dillon 	 *
2362b3f93eaSMatthew Dillon 	 * caps inheritance basically shifts the EXEC bits into the SELF bits,
2372b3f93eaSMatthew Dillon 	 * and then replicates the EXEC bits.  We have to avoid shifting any
2382b3f93eaSMatthew Dillon 	 * 1's from the SELF bits into the adjacent EXEC bits that may have
2392b3f93eaSMatthew Dillon 	 * previously been 0.
2402b3f93eaSMatthew Dillon 	 */
2412b3f93eaSMatthew Dillon 	cred = p->p_ucred;
2422b3f93eaSMatthew Dillon 	for (i = 0; i < __SYSCAP_NUMELMS; ++i) {
2432b3f93eaSMatthew Dillon 		elm = cred->cr_caps.caps[i];
2442b3f93eaSMatthew Dillon 		elm = ((elm & __SYSCAP_EXECMASK) >> 1) |
2452b3f93eaSMatthew Dillon 		      (elm & __SYSCAP_EXECMASK);
2462b3f93eaSMatthew Dillon 		if (elm != cred->cr_caps.caps[i])
2472b3f93eaSMatthew Dillon 			changed = 1;
2482b3f93eaSMatthew Dillon 	}
2492b3f93eaSMatthew Dillon 
2502b3f93eaSMatthew Dillon 	/*
2512b3f93eaSMatthew Dillon 	 * Yes, setup a new ucred for the process
2522b3f93eaSMatthew Dillon 	 */
2532b3f93eaSMatthew Dillon 	if (changed) {
2542b3f93eaSMatthew Dillon 		cratom_proc(p);
2552b3f93eaSMatthew Dillon 		cred = p->p_ucred;
2562b3f93eaSMatthew Dillon 		for (i = 0; i < __SYSCAP_NUMELMS; ++i) {
2572b3f93eaSMatthew Dillon 			elm = cred->cr_caps.caps[i];
2582b3f93eaSMatthew Dillon 			elm = ((elm & __SYSCAP_EXECMASK) >> 1) |
2592b3f93eaSMatthew Dillon 			      (elm & __SYSCAP_EXECMASK);
2602b3f93eaSMatthew Dillon 			cred->cr_caps.caps[i] = elm;
2612b3f93eaSMatthew Dillon 		}
2622b3f93eaSMatthew Dillon 	}
2632b3f93eaSMatthew Dillon }
2642b3f93eaSMatthew Dillon 
2652b3f93eaSMatthew Dillon /*
2662b3f93eaSMatthew Dillon  * Return the raw flags for the requested capability.
2672b3f93eaSMatthew Dillon  */
2682b3f93eaSMatthew Dillon int
caps_get(struct ucred * cred,int cap)2692b3f93eaSMatthew Dillon caps_get(struct ucred *cred, int cap)
2702b3f93eaSMatthew Dillon {
2712b3f93eaSMatthew Dillon 	int res;
2722b3f93eaSMatthew Dillon 
2732b3f93eaSMatthew Dillon 	cap &= ~__SYSCAP_XFLAGS;
2742b3f93eaSMatthew Dillon 	if (cap < 0 || cap >= __SYSCAP_COUNT)
2752b3f93eaSMatthew Dillon 		return 0;
2762b3f93eaSMatthew Dillon 	res = (int)(cred->cr_caps.caps[__SYSCAP_INDEX(cap)] >>
2772b3f93eaSMatthew Dillon 		    __SYSCAP_SHIFT(cap));
2782b3f93eaSMatthew Dillon 	res &= __SYSCAP_BITS_MASK;
2792b3f93eaSMatthew Dillon 
2802b3f93eaSMatthew Dillon 	return res;
2812b3f93eaSMatthew Dillon }
2822b3f93eaSMatthew Dillon 
2832b3f93eaSMatthew Dillon /*
2842b3f93eaSMatthew Dillon  * Set capability restriction bits
2852b3f93eaSMatthew Dillon  */
2862b3f93eaSMatthew Dillon void
caps_set_locked(struct proc * p,int cap,int flags)2872b3f93eaSMatthew Dillon caps_set_locked(struct proc *p, int cap, int flags)
2882b3f93eaSMatthew Dillon {
2892b3f93eaSMatthew Dillon 	struct ucred *cred;
2902b3f93eaSMatthew Dillon 	__syscapelm_t elm;
2912b3f93eaSMatthew Dillon 
2922b3f93eaSMatthew Dillon 	cap &= ~__SYSCAP_XFLAGS;
2932b3f93eaSMatthew Dillon 	if (cap < 0 || cap >= __SYSCAP_COUNT)
2942b3f93eaSMatthew Dillon 		return;
2952b3f93eaSMatthew Dillon 
2962b3f93eaSMatthew Dillon 	cred = cratom_proc(p);
2972b3f93eaSMatthew Dillon 	elm = (__syscapelm_t)flags << __SYSCAP_SHIFT(SYSCAP_ANY);
2982b3f93eaSMatthew Dillon 	atomic_set_64(&cred->cr_caps.caps[0], elm);
2992b3f93eaSMatthew Dillon 	elm = (__syscapelm_t)flags << __SYSCAP_SHIFT(cap);
3002b3f93eaSMatthew Dillon 	atomic_set_64(&cred->cr_caps.caps[ __SYSCAP_INDEX(cap)], elm);
3012b3f93eaSMatthew Dillon }
3022b3f93eaSMatthew Dillon 
3032b3f93eaSMatthew Dillon /*
3042b3f93eaSMatthew Dillon  * Returns error code if restricted, 0 on success.
3052b3f93eaSMatthew Dillon  *
3062b3f93eaSMatthew Dillon  * These are more sophisticated versions of the baseline caps checks.
3072b3f93eaSMatthew Dillon  * cr_prison capabilities are also checked, and some capabilities may
3082b3f93eaSMatthew Dillon  * imply several tests.
3092b3f93eaSMatthew Dillon  */
3102b3f93eaSMatthew Dillon int
caps_priv_check(struct ucred * cred,int cap)3112b3f93eaSMatthew Dillon caps_priv_check(struct ucred *cred, int cap)
3122b3f93eaSMatthew Dillon {
3132b3f93eaSMatthew Dillon 	int res;
3142b3f93eaSMatthew Dillon 
3152b3f93eaSMatthew Dillon 	if (cred == NULL) {
3162b3f93eaSMatthew Dillon 		if (cap & __SYSCAP_NULLCRED)
3172b3f93eaSMatthew Dillon 			return 0;
3182b3f93eaSMatthew Dillon 		return EPERM;
3192b3f93eaSMatthew Dillon 	}
3202b3f93eaSMatthew Dillon 
321*a44776b2SMatthew Dillon 	/*
322*a44776b2SMatthew Dillon 	 * Uid must be 0 unless NOROOTTEST is requested.  If requested
323*a44776b2SMatthew Dillon 	 * it means the caller is depending on e.g. /dev/blah perms.
324*a44776b2SMatthew Dillon 	 */
325*a44776b2SMatthew Dillon 	if (cred->cr_uid != 0 && (cap & __SYSCAP_NOROOTTEST) == 0)
3262b3f93eaSMatthew Dillon 		return EPERM;
3272b3f93eaSMatthew Dillon 
3282b3f93eaSMatthew Dillon 	res = caps_check_cred(cred, cap);
3292b3f93eaSMatthew Dillon 	if (cap & __SYSCAP_GROUP_MASK) {
3302b3f93eaSMatthew Dillon 		cap = (cap & __SYSCAP_GROUP_MASK) >> __SYSCAP_GROUP_SHIFT;
3312b3f93eaSMatthew Dillon 		res |= caps_check_cred(cred, cap);
3322b3f93eaSMatthew Dillon 	}
3332b3f93eaSMatthew Dillon 	if (res & __SYSCAP_SELF)
3342b3f93eaSMatthew Dillon 		return EPERM;
33501d4028dSMatthew Dillon 	return (prison_priv_check(cred, cap));
3362b3f93eaSMatthew Dillon }
3372b3f93eaSMatthew Dillon 
3382b3f93eaSMatthew Dillon int
caps_priv_check_td(thread_t td,int cap)3392b3f93eaSMatthew Dillon caps_priv_check_td(thread_t td, int cap)
3402b3f93eaSMatthew Dillon {
3412b3f93eaSMatthew Dillon 	struct ucred *cred;
3422b3f93eaSMatthew Dillon 
3432b3f93eaSMatthew Dillon 	if (td->td_lwp == NULL)			/* not user thread */
3442b3f93eaSMatthew Dillon 		return 0;
3452b3f93eaSMatthew Dillon 	cred = td->td_ucred;
3462b3f93eaSMatthew Dillon         if (cred == NULL)
3472b3f93eaSMatthew Dillon 		return (EPERM);
3482b3f93eaSMatthew Dillon 						/* must pass restrictions */
3492b3f93eaSMatthew Dillon 	if (caps_check_cred(cred, cap) & __SYSCAP_SELF)
3502b3f93eaSMatthew Dillon 		return EPERM;
3512b3f93eaSMatthew Dillon 	return (prison_priv_check(cred, cap));
3522b3f93eaSMatthew Dillon }
3532b3f93eaSMatthew Dillon 
3542b3f93eaSMatthew Dillon int
caps_priv_check_self(int cap)3552b3f93eaSMatthew Dillon caps_priv_check_self(int cap)
3562b3f93eaSMatthew Dillon {
3572b3f93eaSMatthew Dillon 	return (caps_priv_check_td(curthread, cap));
3582b3f93eaSMatthew Dillon }
359