xref: /freebsd/sys/kern/kern_priv.c (revision 05e1e482c7db7a2a3163b1308d36a75f30ccbe6a)
1800c9408SRobert Watson /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
38a36da99SPedro F. Giffuni  *
4800c9408SRobert Watson  * Copyright (c) 2006 nCircle Network Security, Inc.
56efcc2f2SRobert Watson  * Copyright (c) 2009 Robert N. M. Watson
6*05e1e482SMariusz Zaborski  * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org>
7800c9408SRobert Watson  * All rights reserved.
8800c9408SRobert Watson  *
9800c9408SRobert Watson  * This software was developed by Robert N. M. Watson for the TrustedBSD
10800c9408SRobert Watson  * Project under contract to nCircle Network Security, Inc.
11800c9408SRobert Watson  *
12800c9408SRobert Watson  * Redistribution and use in source and binary forms, with or without
13800c9408SRobert Watson  * modification, are permitted provided that the following conditions
14800c9408SRobert Watson  * are met:
15800c9408SRobert Watson  * 1. Redistributions of source code must retain the above copyright
16800c9408SRobert Watson  *    notice, this list of conditions and the following disclaimer.
17800c9408SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
18800c9408SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
19800c9408SRobert Watson  *    documentation and/or other materials provided with the distribution.
20800c9408SRobert Watson  *
21800c9408SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22800c9408SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23800c9408SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24800c9408SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
25800c9408SRobert Watson  * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26800c9408SRobert Watson  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27800c9408SRobert Watson  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28800c9408SRobert Watson  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29800c9408SRobert Watson  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30800c9408SRobert Watson  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31800c9408SRobert Watson  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32800c9408SRobert Watson  */
33800c9408SRobert Watson 
34b916b56bSRobert Watson #include <sys/cdefs.h>
35b916b56bSRobert Watson __FBSDID("$FreeBSD$");
36b916b56bSRobert Watson 
37800c9408SRobert Watson #include <sys/param.h>
38800c9408SRobert Watson #include <sys/jail.h>
39800c9408SRobert Watson #include <sys/kernel.h>
40*05e1e482SMariusz Zaborski #include <sys/lock.h>
41*05e1e482SMariusz Zaborski #include <sys/mutex.h>
42*05e1e482SMariusz Zaborski #include <sys/sx.h>
43800c9408SRobert Watson #include <sys/priv.h>
44800c9408SRobert Watson #include <sys/proc.h>
456efcc2f2SRobert Watson #include <sys/sdt.h>
46800c9408SRobert Watson #include <sys/sysctl.h>
47800c9408SRobert Watson #include <sys/systm.h>
48800c9408SRobert Watson 
49800c9408SRobert Watson #include <security/mac/mac_framework.h>
50800c9408SRobert Watson 
51800c9408SRobert Watson /*
52800c9408SRobert Watson  * `suser_enabled' (which can be set by the security.bsd.suser_enabled
53800c9408SRobert Watson  * sysctl) determines whether the system 'super-user' policy is in effect.  If
54800c9408SRobert Watson  * it is nonzero, an effective uid of 0 connotes special privilege,
55800c9408SRobert Watson  * overriding many mandatory and discretionary protections.  If it is zero,
56800c9408SRobert Watson  * uid 0 is offered no special privilege in the kernel security policy.
57800c9408SRobert Watson  * Setting it to zero may seriously impact the functionality of many existing
58800c9408SRobert Watson  * userland programs, and should not be done without careful consideration of
59800c9408SRobert Watson  * the consequences.
60800c9408SRobert Watson  */
61*05e1e482SMariusz Zaborski 
62*05e1e482SMariusz Zaborski static bool
63*05e1e482SMariusz Zaborski suser_enabled(struct ucred *cred)
64*05e1e482SMariusz Zaborski {
65*05e1e482SMariusz Zaborski 
66*05e1e482SMariusz Zaborski 	return (prison_allow(cred, PR_ALLOW_SUSER) ? true : false);
67*05e1e482SMariusz Zaborski }
68*05e1e482SMariusz Zaborski 
69*05e1e482SMariusz Zaborski static void inline
70*05e1e482SMariusz Zaborski prison_suser_set(struct prison *pr, int enabled)
71*05e1e482SMariusz Zaborski {
72*05e1e482SMariusz Zaborski 
73*05e1e482SMariusz Zaborski 	if (enabled) {
74*05e1e482SMariusz Zaborski 		pr->pr_allow |= PR_ALLOW_SUSER;
75*05e1e482SMariusz Zaborski 	} else {
76*05e1e482SMariusz Zaborski 		pr->pr_allow &= ~PR_ALLOW_SUSER;
77*05e1e482SMariusz Zaborski 	}
78*05e1e482SMariusz Zaborski }
79*05e1e482SMariusz Zaborski 
80*05e1e482SMariusz Zaborski static int
81*05e1e482SMariusz Zaborski sysctl_kern_suser_enabled(SYSCTL_HANDLER_ARGS)
82*05e1e482SMariusz Zaborski {
83*05e1e482SMariusz Zaborski 	struct prison *pr, *cpr;
84*05e1e482SMariusz Zaborski 	struct ucred *cred;
85*05e1e482SMariusz Zaborski 	int descend, error, enabled;
86*05e1e482SMariusz Zaborski 
87*05e1e482SMariusz Zaborski 	cred = req->td->td_ucred;
88*05e1e482SMariusz Zaborski 	enabled = suser_enabled(cred);
89*05e1e482SMariusz Zaborski 
90*05e1e482SMariusz Zaborski 	error = sysctl_handle_int(oidp, &enabled, 0, req);
91*05e1e482SMariusz Zaborski 	if (error || !req->newptr)
92*05e1e482SMariusz Zaborski 		return (error);
93*05e1e482SMariusz Zaborski 
94*05e1e482SMariusz Zaborski 	pr = cred->cr_prison;
95*05e1e482SMariusz Zaborski 	sx_slock(&allprison_lock);
96*05e1e482SMariusz Zaborski 	mtx_lock(&pr->pr_mtx);
97*05e1e482SMariusz Zaborski 
98*05e1e482SMariusz Zaborski 	prison_suser_set(pr, enabled);
99*05e1e482SMariusz Zaborski 	if (!enabled) {
100*05e1e482SMariusz Zaborski 		FOREACH_PRISON_DESCENDANT_LOCKED(pr, cpr, descend) {
101*05e1e482SMariusz Zaborski 			prison_suser_set(cpr, 0);
102*05e1e482SMariusz Zaborski 		}
103*05e1e482SMariusz Zaborski 	}
104*05e1e482SMariusz Zaborski 	mtx_unlock(&pr->pr_mtx);
105*05e1e482SMariusz Zaborski 	sx_sunlock(&allprison_lock);
106*05e1e482SMariusz Zaborski 	return (0);
107*05e1e482SMariusz Zaborski }
108*05e1e482SMariusz Zaborski 
109*05e1e482SMariusz Zaborski SYSCTL_PROC(_security_bsd, OID_AUTO, suser_enabled, CTLTYPE_INT |
110*05e1e482SMariusz Zaborski     CTLFLAG_RWTUN | CTLFLAG_PRISON, 0, 0, &sysctl_kern_suser_enabled, "I",
111*05e1e482SMariusz Zaborski     "Processes with uid 0 have privilege");
112800c9408SRobert Watson 
1135eb0d283SAndrey Zonov static int	unprivileged_mlock = 1;
114af3b2549SHans Petter Selasky SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_mlock, CTLFLAG_RWTUN,
1155eb0d283SAndrey Zonov     &unprivileged_mlock, 0, "Allow non-root users to call mlock(2)");
1165eb0d283SAndrey Zonov 
117b19d66fdSJamie Gritton static int	unprivileged_read_msgbuf = 1;
118b19d66fdSJamie Gritton SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
119b19d66fdSJamie Gritton     CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
120b19d66fdSJamie Gritton     "Unprivileged processes may read the kernel message buffer");
121b19d66fdSJamie Gritton 
1226efcc2f2SRobert Watson SDT_PROVIDER_DEFINE(priv);
123d9fae5abSAndriy Gapon SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int");
124d9fae5abSAndriy Gapon SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int");
1256efcc2f2SRobert Watson 
1267b2ff0dcSMateusz Guzik static __always_inline int
1277b2ff0dcSMateusz Guzik priv_check_cred_pre(struct ucred *cred, int priv)
1287b2ff0dcSMateusz Guzik {
1297b2ff0dcSMateusz Guzik 	int error;
1307b2ff0dcSMateusz Guzik 
1317b2ff0dcSMateusz Guzik #ifdef MAC
1327b2ff0dcSMateusz Guzik 	error = mac_priv_check(cred, priv);
1337b2ff0dcSMateusz Guzik #else
1347b2ff0dcSMateusz Guzik 	error = 0;
1357b2ff0dcSMateusz Guzik #endif
1367b2ff0dcSMateusz Guzik 	return (error);
1377b2ff0dcSMateusz Guzik }
1387b2ff0dcSMateusz Guzik 
1397b2ff0dcSMateusz Guzik static __always_inline int
1407b2ff0dcSMateusz Guzik priv_check_cred_post(struct ucred *cred, int priv, int error, bool handled)
1417b2ff0dcSMateusz Guzik {
1427b2ff0dcSMateusz Guzik 
1437b2ff0dcSMateusz Guzik 	if (__predict_true(handled))
1447b2ff0dcSMateusz Guzik 		goto out;
1457b2ff0dcSMateusz Guzik 	/*
1467b2ff0dcSMateusz Guzik 	 * Now check with MAC, if enabled, to see if a policy module grants
1477b2ff0dcSMateusz Guzik 	 * privilege.
1487b2ff0dcSMateusz Guzik 	 */
1497b2ff0dcSMateusz Guzik #ifdef MAC
1507b2ff0dcSMateusz Guzik 	if (mac_priv_grant(cred, priv) == 0) {
1517b2ff0dcSMateusz Guzik 		error = 0;
1527b2ff0dcSMateusz Guzik 		goto out;
1537b2ff0dcSMateusz Guzik 	}
1547b2ff0dcSMateusz Guzik #endif
1557b2ff0dcSMateusz Guzik 
1567b2ff0dcSMateusz Guzik 	/*
1577b2ff0dcSMateusz Guzik 	 * The default is deny, so if no policies have granted it, reject
1587b2ff0dcSMateusz Guzik 	 * with a privilege error here.
1597b2ff0dcSMateusz Guzik 	 */
1607b2ff0dcSMateusz Guzik 	error = EPERM;
1617b2ff0dcSMateusz Guzik out:
1627b2ff0dcSMateusz Guzik 	if (SDT_PROBES_ENABLED()) {
1637b2ff0dcSMateusz Guzik 		if (error)
1647b2ff0dcSMateusz Guzik 			SDT_PROBE1(priv, kernel, priv_check, priv__err, priv);
1657b2ff0dcSMateusz Guzik 		else
1667b2ff0dcSMateusz Guzik 			SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv);
1677b2ff0dcSMateusz Guzik 	}
1687b2ff0dcSMateusz Guzik 	return (error);
1697b2ff0dcSMateusz Guzik }
1707b2ff0dcSMateusz Guzik 
171800c9408SRobert Watson /*
172800c9408SRobert Watson  * Check a credential for privilege.  Lots of good reasons to deny privilege;
173800c9408SRobert Watson  * only a few to grant it.
174800c9408SRobert Watson  */
175800c9408SRobert Watson int
176cc426dd3SMateusz Guzik priv_check_cred(struct ucred *cred, int priv)
177800c9408SRobert Watson {
178800c9408SRobert Watson 	int error;
179800c9408SRobert Watson 
180800c9408SRobert Watson 	KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d",
181800c9408SRobert Watson 	    priv));
182800c9408SRobert Watson 
1837b2ff0dcSMateusz Guzik 	switch (priv) {
184a459a6cfSMateusz Guzik 	case PRIV_VFS_LOOKUP:
185a459a6cfSMateusz Guzik 		return (priv_check_cred_vfs_lookup(cred));
1867b2ff0dcSMateusz Guzik 	case PRIV_VFS_GENERATION:
1877b2ff0dcSMateusz Guzik 		return (priv_check_cred_vfs_generation(cred));
1887b2ff0dcSMateusz Guzik 	}
1897b2ff0dcSMateusz Guzik 
1907251b786SRobert Watson 	/*
1917251b786SRobert Watson 	 * We first evaluate policies that may deny the granting of
1927251b786SRobert Watson 	 * privilege unilaterally.
1937251b786SRobert Watson 	 */
1947b2ff0dcSMateusz Guzik 	error = priv_check_cred_pre(cred, priv);
195800c9408SRobert Watson 	if (error)
1966efcc2f2SRobert Watson 		goto out;
197800c9408SRobert Watson 
198800c9408SRobert Watson 	/*
199800c9408SRobert Watson 	 * Jail policy will restrict certain privileges that may otherwise be
200800c9408SRobert Watson 	 * be granted.
201800c9408SRobert Watson 	 */
202800c9408SRobert Watson 	error = prison_priv_check(cred, priv);
203800c9408SRobert Watson 	if (error)
2046efcc2f2SRobert Watson 		goto out;
205800c9408SRobert Watson 
2065eb0d283SAndrey Zonov 	if (unprivileged_mlock) {
2075eb0d283SAndrey Zonov 		/*
2085eb0d283SAndrey Zonov 		 * Allow unprivileged users to call mlock(2)/munlock(2) and
2095eb0d283SAndrey Zonov 		 * mlockall(2)/munlockall(2).
2105eb0d283SAndrey Zonov 		 */
2115eb0d283SAndrey Zonov 		switch (priv) {
2125eb0d283SAndrey Zonov 		case PRIV_VM_MLOCK:
2135eb0d283SAndrey Zonov 		case PRIV_VM_MUNLOCK:
2145eb0d283SAndrey Zonov 			error = 0;
2155eb0d283SAndrey Zonov 			goto out;
2165eb0d283SAndrey Zonov 		}
2175eb0d283SAndrey Zonov 	}
2185eb0d283SAndrey Zonov 
219b19d66fdSJamie Gritton 	if (unprivileged_read_msgbuf) {
220b19d66fdSJamie Gritton 		/*
221b19d66fdSJamie Gritton 		 * Allow an unprivileged user to read the kernel message
222b19d66fdSJamie Gritton 		 * buffer.
223b19d66fdSJamie Gritton 		 */
224b19d66fdSJamie Gritton 		if (priv == PRIV_MSGBUF) {
225b19d66fdSJamie Gritton 			error = 0;
226b19d66fdSJamie Gritton 			goto out;
227b19d66fdSJamie Gritton 		}
228b19d66fdSJamie Gritton 	}
229b19d66fdSJamie Gritton 
230800c9408SRobert Watson 	/*
231800c9408SRobert Watson 	 * Having determined if privilege is restricted by various policies,
2327251b786SRobert Watson 	 * now determine if privilege is granted.  At this point, any policy
2337251b786SRobert Watson 	 * may grant privilege.  For now, we allow short-circuit boolean
2347251b786SRobert Watson 	 * evaluation, so may not call all policies.  Perhaps we should.
235800c9408SRobert Watson 	 *
236800c9408SRobert Watson 	 * Superuser policy grants privilege based on the effective (or in
2377251b786SRobert Watson 	 * the case of specific privileges, real) uid being 0.  We allow the
2387251b786SRobert Watson 	 * superuser policy to be globally disabled, although this is
2397251b786SRobert Watson 	 * currenty of limited utility.
240800c9408SRobert Watson 	 */
241*05e1e482SMariusz Zaborski 	if (suser_enabled(cred)) {
2427251b786SRobert Watson 		switch (priv) {
2437251b786SRobert Watson 		case PRIV_MAXFILES:
2447251b786SRobert Watson 		case PRIV_MAXPROC:
2457251b786SRobert Watson 		case PRIV_PROC_LIMIT:
2466efcc2f2SRobert Watson 			if (cred->cr_ruid == 0) {
2476efcc2f2SRobert Watson 				error = 0;
2486efcc2f2SRobert Watson 				goto out;
2496efcc2f2SRobert Watson 			}
2507251b786SRobert Watson 			break;
25163619b6dSKyle Evans 		case PRIV_VFS_READ_DIR:
25263619b6dSKyle Evans 			/*
25363619b6dSKyle Evans 			 * Allow PRIV_VFS_READ_DIR for root if we're not in a
25463619b6dSKyle Evans 			 * jail, otherwise deny unless a MAC policy grants it.
25563619b6dSKyle Evans 			 */
25663619b6dSKyle Evans 			if (jailed(cred))
25763619b6dSKyle Evans 				break;
25863619b6dSKyle Evans 			/* FALLTHROUGH */
2597251b786SRobert Watson 		default:
2606efcc2f2SRobert Watson 			if (cred->cr_uid == 0) {
2616efcc2f2SRobert Watson 				error = 0;
2626efcc2f2SRobert Watson 				goto out;
2636efcc2f2SRobert Watson 			}
2647251b786SRobert Watson 			break;
265800c9408SRobert Watson 		}
266800c9408SRobert Watson 	}
267800c9408SRobert Watson 
268800c9408SRobert Watson 	/*
2691e7df843SJamie Gritton 	 * Writes to kernel/physical memory are a typical root-only operation,
2701e7df843SJamie Gritton 	 * but non-root users are expected to be able to read it (provided they
2711e7df843SJamie Gritton 	 * have permission to access /dev/[k]mem).
272c71e3362SJamie Gritton 	 */
273c71e3362SJamie Gritton 	if (priv == PRIV_KMEM_READ) {
274c71e3362SJamie Gritton 		error = 0;
275c71e3362SJamie Gritton 		goto out;
276c71e3362SJamie Gritton 	}
277c71e3362SJamie Gritton 
278c71e3362SJamie Gritton 	/*
279b3079544SJamie Gritton 	 * Allow unprivileged process debugging on a per-jail basis.
280b3079544SJamie Gritton 	 * Do this here instead of prison_priv_check(), so it can also
281b3079544SJamie Gritton 	 * apply to prison0.
282b3079544SJamie Gritton 	 */
283b3079544SJamie Gritton 	if (priv == PRIV_DEBUG_UNPRIV) {
284b3079544SJamie Gritton 		if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) {
285b3079544SJamie Gritton 			error = 0;
286b3079544SJamie Gritton 			goto out;
287b3079544SJamie Gritton 		}
288b3079544SJamie Gritton 	}
289b3079544SJamie Gritton 
2907b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, priv, error, false));
2916efcc2f2SRobert Watson out:
2927b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, priv, error, true));
293800c9408SRobert Watson }
294800c9408SRobert Watson 
295800c9408SRobert Watson int
296800c9408SRobert Watson priv_check(struct thread *td, int priv)
297800c9408SRobert Watson {
298800c9408SRobert Watson 
299800c9408SRobert Watson 	KASSERT(td == curthread, ("priv_check: td != curthread"));
300800c9408SRobert Watson 
301cc426dd3SMateusz Guzik 	return (priv_check_cred(td->td_ucred, priv));
302800c9408SRobert Watson }
3037b2ff0dcSMateusz Guzik 
30495275911SMateusz Guzik static int __noinline
305a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup_slow(struct ucred *cred)
306a459a6cfSMateusz Guzik {
307a459a6cfSMateusz Guzik 	int error;
308a459a6cfSMateusz Guzik 
309a459a6cfSMateusz Guzik 	error = priv_check_cred_pre(cred, PRIV_VFS_LOOKUP);
310a459a6cfSMateusz Guzik 	if (error)
311a459a6cfSMateusz Guzik 		goto out;
312a459a6cfSMateusz Guzik 
313*05e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred)) {
314a459a6cfSMateusz Guzik 		error = 0;
315a459a6cfSMateusz Guzik 		goto out;
316a459a6cfSMateusz Guzik 	}
317a459a6cfSMateusz Guzik 
318a459a6cfSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, false));
319a459a6cfSMateusz Guzik out:
320a459a6cfSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, true));
321a459a6cfSMateusz Guzik 
322a459a6cfSMateusz Guzik }
323a459a6cfSMateusz Guzik 
324a459a6cfSMateusz Guzik int
325a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup(struct ucred *cred)
326a459a6cfSMateusz Guzik {
327a459a6cfSMateusz Guzik 	int error;
328a459a6cfSMateusz Guzik 
329a459a6cfSMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
330a459a6cfSMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
331a459a6cfSMateusz Guzik 		return (priv_check_cred_vfs_lookup_slow(cred));
332a459a6cfSMateusz Guzik 
333a459a6cfSMateusz Guzik 	error = EPERM;
334*05e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred))
335a459a6cfSMateusz Guzik 		error = 0;
336a459a6cfSMateusz Guzik 	return (error);
337a459a6cfSMateusz Guzik }
338a459a6cfSMateusz Guzik 
339a459a6cfSMateusz Guzik int
340a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup_nomac(struct ucred *cred)
341a459a6cfSMateusz Guzik {
342a459a6cfSMateusz Guzik 	int error;
343a459a6cfSMateusz Guzik 
344a459a6cfSMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
345a459a6cfSMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
346a459a6cfSMateusz Guzik 		return (EAGAIN);
347a459a6cfSMateusz Guzik 
348a459a6cfSMateusz Guzik 	error = EPERM;
349*05e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred))
350a459a6cfSMateusz Guzik 		error = 0;
351a459a6cfSMateusz Guzik 	return (error);
352a459a6cfSMateusz Guzik }
353a459a6cfSMateusz Guzik 
354a459a6cfSMateusz Guzik static int __noinline
35595275911SMateusz Guzik priv_check_cred_vfs_generation_slow(struct ucred *cred)
3567b2ff0dcSMateusz Guzik {
3577b2ff0dcSMateusz Guzik 	int error;
3587b2ff0dcSMateusz Guzik 
3597b2ff0dcSMateusz Guzik 	error = priv_check_cred_pre(cred, PRIV_VFS_GENERATION);
3607b2ff0dcSMateusz Guzik 	if (error)
3617b2ff0dcSMateusz Guzik 		goto out;
3627b2ff0dcSMateusz Guzik 
3637b2ff0dcSMateusz Guzik 	if (jailed(cred)) {
3647b2ff0dcSMateusz Guzik 		error = EPERM;
3657b2ff0dcSMateusz Guzik 		goto out;
3667b2ff0dcSMateusz Guzik 	}
3677b2ff0dcSMateusz Guzik 
368*05e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred)) {
3697b2ff0dcSMateusz Guzik 		error = 0;
3707b2ff0dcSMateusz Guzik 		goto out;
3717b2ff0dcSMateusz Guzik 	}
3727b2ff0dcSMateusz Guzik 
3737b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, false));
3747b2ff0dcSMateusz Guzik out:
3757b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true));
3767b2ff0dcSMateusz Guzik 
3777b2ff0dcSMateusz Guzik }
37895275911SMateusz Guzik 
37995275911SMateusz Guzik int
38095275911SMateusz Guzik priv_check_cred_vfs_generation(struct ucred *cred)
38195275911SMateusz Guzik {
38295275911SMateusz Guzik 	int error;
38395275911SMateusz Guzik 
38495275911SMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
38595275911SMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
38695275911SMateusz Guzik 		return (priv_check_cred_vfs_generation_slow(cred));
38795275911SMateusz Guzik 
38895275911SMateusz Guzik 	error = EPERM;
389*05e1e482SMariusz Zaborski 	if (!jailed(cred) && cred->cr_uid == 0 && suser_enabled(cred))
39095275911SMateusz Guzik 		error = 0;
39195275911SMateusz Guzik 	return (error);
39295275911SMateusz Guzik }
393