xref: /freebsd/sys/kern/kern_priv.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1800c9408SRobert Watson /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
38a36da99SPedro F. Giffuni  *
4800c9408SRobert Watson  * Copyright (c) 2006 nCircle Network Security, Inc.
56efcc2f2SRobert Watson  * Copyright (c) 2009 Robert N. M. Watson
605e1e482SMariusz 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>
4005e1e482SMariusz Zaborski #include <sys/lock.h>
4105e1e482SMariusz Zaborski #include <sys/mutex.h>
4205e1e482SMariusz 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  */
6105e1e482SMariusz Zaborski 
6205e1e482SMariusz Zaborski static bool
6305e1e482SMariusz Zaborski suser_enabled(struct ucred *cred)
6405e1e482SMariusz Zaborski {
6505e1e482SMariusz Zaborski 
660fe74ae6SJamie Gritton 	return (prison_allow(cred, PR_ALLOW_SUSER));
6705e1e482SMariusz Zaborski }
6805e1e482SMariusz Zaborski 
6905e1e482SMariusz Zaborski static int
7005e1e482SMariusz Zaborski sysctl_kern_suser_enabled(SYSCTL_HANDLER_ARGS)
7105e1e482SMariusz Zaborski {
7205e1e482SMariusz Zaborski 	struct ucred *cred;
730fe74ae6SJamie Gritton 	int error, enabled;
7405e1e482SMariusz Zaborski 
7505e1e482SMariusz Zaborski 	cred = req->td->td_ucred;
7605e1e482SMariusz Zaborski 	enabled = suser_enabled(cred);
7705e1e482SMariusz Zaborski 	error = sysctl_handle_int(oidp, &enabled, 0, req);
7805e1e482SMariusz Zaborski 	if (error || !req->newptr)
7905e1e482SMariusz Zaborski 		return (error);
800fe74ae6SJamie Gritton 	prison_set_allow(cred, PR_ALLOW_SUSER, enabled);
8105e1e482SMariusz Zaborski 	return (0);
8205e1e482SMariusz Zaborski }
8305e1e482SMariusz Zaborski 
8405e1e482SMariusz Zaborski SYSCTL_PROC(_security_bsd, OID_AUTO, suser_enabled, CTLTYPE_INT |
85f488d5b7SMariusz Zaborski     CTLFLAG_RWTUN | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0,
86f488d5b7SMariusz Zaborski     &sysctl_kern_suser_enabled, "I", "Processes with uid 0 have privilege");
87800c9408SRobert Watson 
885eb0d283SAndrey Zonov static int	unprivileged_mlock = 1;
89af3b2549SHans Petter Selasky SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_mlock, CTLFLAG_RWTUN,
905eb0d283SAndrey Zonov     &unprivileged_mlock, 0, "Allow non-root users to call mlock(2)");
915eb0d283SAndrey Zonov 
92b19d66fdSJamie Gritton static int	unprivileged_read_msgbuf = 1;
93b19d66fdSJamie Gritton SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
94b19d66fdSJamie Gritton     CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
95b19d66fdSJamie Gritton     "Unprivileged processes may read the kernel message buffer");
96b19d66fdSJamie Gritton 
976efcc2f2SRobert Watson SDT_PROVIDER_DEFINE(priv);
98d9fae5abSAndriy Gapon SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int");
99d9fae5abSAndriy Gapon SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int");
1006efcc2f2SRobert Watson 
1017b2ff0dcSMateusz Guzik static __always_inline int
1027b2ff0dcSMateusz Guzik priv_check_cred_pre(struct ucred *cred, int priv)
1037b2ff0dcSMateusz Guzik {
1047b2ff0dcSMateusz Guzik 	int error;
1057b2ff0dcSMateusz Guzik 
1067b2ff0dcSMateusz Guzik #ifdef MAC
1077b2ff0dcSMateusz Guzik 	error = mac_priv_check(cred, priv);
1087b2ff0dcSMateusz Guzik #else
1097b2ff0dcSMateusz Guzik 	error = 0;
1107b2ff0dcSMateusz Guzik #endif
1117b2ff0dcSMateusz Guzik 	return (error);
1127b2ff0dcSMateusz Guzik }
1137b2ff0dcSMateusz Guzik 
1147b2ff0dcSMateusz Guzik static __always_inline int
1157b2ff0dcSMateusz Guzik priv_check_cred_post(struct ucred *cred, int priv, int error, bool handled)
1167b2ff0dcSMateusz Guzik {
1177b2ff0dcSMateusz Guzik 
1187b2ff0dcSMateusz Guzik 	if (__predict_true(handled))
1197b2ff0dcSMateusz Guzik 		goto out;
1207b2ff0dcSMateusz Guzik 	/*
1217b2ff0dcSMateusz Guzik 	 * Now check with MAC, if enabled, to see if a policy module grants
1227b2ff0dcSMateusz Guzik 	 * privilege.
1237b2ff0dcSMateusz Guzik 	 */
1247b2ff0dcSMateusz Guzik #ifdef MAC
1257b2ff0dcSMateusz Guzik 	if (mac_priv_grant(cred, priv) == 0) {
1267b2ff0dcSMateusz Guzik 		error = 0;
1277b2ff0dcSMateusz Guzik 		goto out;
1287b2ff0dcSMateusz Guzik 	}
1297b2ff0dcSMateusz Guzik #endif
1307b2ff0dcSMateusz Guzik 
1317b2ff0dcSMateusz Guzik 	/*
1327b2ff0dcSMateusz Guzik 	 * The default is deny, so if no policies have granted it, reject
1337b2ff0dcSMateusz Guzik 	 * with a privilege error here.
1347b2ff0dcSMateusz Guzik 	 */
1357b2ff0dcSMateusz Guzik 	error = EPERM;
1367b2ff0dcSMateusz Guzik out:
1377b2ff0dcSMateusz Guzik 	if (SDT_PROBES_ENABLED()) {
1387b2ff0dcSMateusz Guzik 		if (error)
1397b2ff0dcSMateusz Guzik 			SDT_PROBE1(priv, kernel, priv_check, priv__err, priv);
1407b2ff0dcSMateusz Guzik 		else
1417b2ff0dcSMateusz Guzik 			SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv);
1427b2ff0dcSMateusz Guzik 	}
1437b2ff0dcSMateusz Guzik 	return (error);
1447b2ff0dcSMateusz Guzik }
1457b2ff0dcSMateusz Guzik 
146800c9408SRobert Watson /*
147800c9408SRobert Watson  * Check a credential for privilege.  Lots of good reasons to deny privilege;
148800c9408SRobert Watson  * only a few to grant it.
149800c9408SRobert Watson  */
150800c9408SRobert Watson int
151cc426dd3SMateusz Guzik priv_check_cred(struct ucred *cred, int priv)
152800c9408SRobert Watson {
153800c9408SRobert Watson 	int error;
154800c9408SRobert Watson 
155800c9408SRobert Watson 	KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d",
156800c9408SRobert Watson 	    priv));
157800c9408SRobert Watson 
1587b2ff0dcSMateusz Guzik 	switch (priv) {
159a459a6cfSMateusz Guzik 	case PRIV_VFS_LOOKUP:
160a459a6cfSMateusz Guzik 		return (priv_check_cred_vfs_lookup(cred));
1617b2ff0dcSMateusz Guzik 	case PRIV_VFS_GENERATION:
1627b2ff0dcSMateusz Guzik 		return (priv_check_cred_vfs_generation(cred));
1637b2ff0dcSMateusz Guzik 	}
1647b2ff0dcSMateusz Guzik 
1657251b786SRobert Watson 	/*
1667251b786SRobert Watson 	 * We first evaluate policies that may deny the granting of
1677251b786SRobert Watson 	 * privilege unilaterally.
1687251b786SRobert Watson 	 */
1697b2ff0dcSMateusz Guzik 	error = priv_check_cred_pre(cred, priv);
170800c9408SRobert Watson 	if (error)
1716efcc2f2SRobert Watson 		goto out;
172800c9408SRobert Watson 
173800c9408SRobert Watson 	/*
174800c9408SRobert Watson 	 * Jail policy will restrict certain privileges that may otherwise be
175800c9408SRobert Watson 	 * be granted.
176800c9408SRobert Watson 	 */
177800c9408SRobert Watson 	error = prison_priv_check(cred, priv);
178800c9408SRobert Watson 	if (error)
1796efcc2f2SRobert Watson 		goto out;
180800c9408SRobert Watson 
1815eb0d283SAndrey Zonov 	if (unprivileged_mlock) {
1825eb0d283SAndrey Zonov 		/*
1835eb0d283SAndrey Zonov 		 * Allow unprivileged users to call mlock(2)/munlock(2) and
1845eb0d283SAndrey Zonov 		 * mlockall(2)/munlockall(2).
1855eb0d283SAndrey Zonov 		 */
1865eb0d283SAndrey Zonov 		switch (priv) {
1875eb0d283SAndrey Zonov 		case PRIV_VM_MLOCK:
1885eb0d283SAndrey Zonov 		case PRIV_VM_MUNLOCK:
1895eb0d283SAndrey Zonov 			error = 0;
1905eb0d283SAndrey Zonov 			goto out;
1915eb0d283SAndrey Zonov 		}
1925eb0d283SAndrey Zonov 	}
1935eb0d283SAndrey Zonov 
194b19d66fdSJamie Gritton 	if (unprivileged_read_msgbuf) {
195b19d66fdSJamie Gritton 		/*
196b19d66fdSJamie Gritton 		 * Allow an unprivileged user to read the kernel message
197b19d66fdSJamie Gritton 		 * buffer.
198b19d66fdSJamie Gritton 		 */
199b19d66fdSJamie Gritton 		if (priv == PRIV_MSGBUF) {
200b19d66fdSJamie Gritton 			error = 0;
201b19d66fdSJamie Gritton 			goto out;
202b19d66fdSJamie Gritton 		}
203b19d66fdSJamie Gritton 	}
204b19d66fdSJamie Gritton 
205800c9408SRobert Watson 	/*
206800c9408SRobert Watson 	 * Having determined if privilege is restricted by various policies,
2077251b786SRobert Watson 	 * now determine if privilege is granted.  At this point, any policy
2087251b786SRobert Watson 	 * may grant privilege.  For now, we allow short-circuit boolean
2097251b786SRobert Watson 	 * evaluation, so may not call all policies.  Perhaps we should.
210800c9408SRobert Watson 	 *
211800c9408SRobert Watson 	 * Superuser policy grants privilege based on the effective (or in
2127251b786SRobert Watson 	 * the case of specific privileges, real) uid being 0.  We allow the
2137251b786SRobert Watson 	 * superuser policy to be globally disabled, although this is
2147251b786SRobert Watson 	 * currenty of limited utility.
215800c9408SRobert Watson 	 */
21605e1e482SMariusz Zaborski 	if (suser_enabled(cred)) {
2177251b786SRobert Watson 		switch (priv) {
2187251b786SRobert Watson 		case PRIV_MAXFILES:
2197251b786SRobert Watson 		case PRIV_MAXPROC:
2207251b786SRobert Watson 		case PRIV_PROC_LIMIT:
2216efcc2f2SRobert Watson 			if (cred->cr_ruid == 0) {
2226efcc2f2SRobert Watson 				error = 0;
2236efcc2f2SRobert Watson 				goto out;
2246efcc2f2SRobert Watson 			}
2257251b786SRobert Watson 			break;
22663619b6dSKyle Evans 		case PRIV_VFS_READ_DIR:
22763619b6dSKyle Evans 			/*
22863619b6dSKyle Evans 			 * Allow PRIV_VFS_READ_DIR for root if we're not in a
22963619b6dSKyle Evans 			 * jail, otherwise deny unless a MAC policy grants it.
23063619b6dSKyle Evans 			 */
23163619b6dSKyle Evans 			if (jailed(cred))
23263619b6dSKyle Evans 				break;
23363619b6dSKyle Evans 			/* FALLTHROUGH */
2347251b786SRobert Watson 		default:
2356efcc2f2SRobert Watson 			if (cred->cr_uid == 0) {
2366efcc2f2SRobert Watson 				error = 0;
2376efcc2f2SRobert Watson 				goto out;
2386efcc2f2SRobert Watson 			}
2397251b786SRobert Watson 			break;
240800c9408SRobert Watson 		}
241800c9408SRobert Watson 	}
242800c9408SRobert Watson 
243800c9408SRobert Watson 	/*
2441e7df843SJamie Gritton 	 * Writes to kernel/physical memory are a typical root-only operation,
2451e7df843SJamie Gritton 	 * but non-root users are expected to be able to read it (provided they
2461e7df843SJamie Gritton 	 * have permission to access /dev/[k]mem).
247c71e3362SJamie Gritton 	 */
248c71e3362SJamie Gritton 	if (priv == PRIV_KMEM_READ) {
249c71e3362SJamie Gritton 		error = 0;
250c71e3362SJamie Gritton 		goto out;
251c71e3362SJamie Gritton 	}
252c71e3362SJamie Gritton 
253c71e3362SJamie Gritton 	/*
254b3079544SJamie Gritton 	 * Allow unprivileged process debugging on a per-jail basis.
255b3079544SJamie Gritton 	 * Do this here instead of prison_priv_check(), so it can also
256b3079544SJamie Gritton 	 * apply to prison0.
257b3079544SJamie Gritton 	 */
258b3079544SJamie Gritton 	if (priv == PRIV_DEBUG_UNPRIV) {
259b3079544SJamie Gritton 		if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) {
260b3079544SJamie Gritton 			error = 0;
261b3079544SJamie Gritton 			goto out;
262b3079544SJamie Gritton 		}
263b3079544SJamie Gritton 	}
264b3079544SJamie Gritton 
2657b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, priv, error, false));
2666efcc2f2SRobert Watson out:
2677b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, priv, error, true));
268800c9408SRobert Watson }
269800c9408SRobert Watson 
270800c9408SRobert Watson int
271800c9408SRobert Watson priv_check(struct thread *td, int priv)
272800c9408SRobert Watson {
273800c9408SRobert Watson 
274800c9408SRobert Watson 	KASSERT(td == curthread, ("priv_check: td != curthread"));
275800c9408SRobert Watson 
276cc426dd3SMateusz Guzik 	return (priv_check_cred(td->td_ucred, priv));
277800c9408SRobert Watson }
2787b2ff0dcSMateusz Guzik 
27995275911SMateusz Guzik static int __noinline
280a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup_slow(struct ucred *cred)
281a459a6cfSMateusz Guzik {
282a459a6cfSMateusz Guzik 	int error;
283a459a6cfSMateusz Guzik 
284a459a6cfSMateusz Guzik 	error = priv_check_cred_pre(cred, PRIV_VFS_LOOKUP);
285a459a6cfSMateusz Guzik 	if (error)
286a459a6cfSMateusz Guzik 		goto out;
287a459a6cfSMateusz Guzik 
28805e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred)) {
289a459a6cfSMateusz Guzik 		error = 0;
290a459a6cfSMateusz Guzik 		goto out;
291a459a6cfSMateusz Guzik 	}
292a459a6cfSMateusz Guzik 
293a459a6cfSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, false));
294a459a6cfSMateusz Guzik out:
295a459a6cfSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, true));
296a459a6cfSMateusz Guzik 
297a459a6cfSMateusz Guzik }
298a459a6cfSMateusz Guzik 
299a459a6cfSMateusz Guzik int
300a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup(struct ucred *cred)
301a459a6cfSMateusz Guzik {
302a459a6cfSMateusz Guzik 	int error;
303a459a6cfSMateusz Guzik 
304a459a6cfSMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
305a459a6cfSMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
306a459a6cfSMateusz Guzik 		return (priv_check_cred_vfs_lookup_slow(cred));
307a459a6cfSMateusz Guzik 
308a459a6cfSMateusz Guzik 	error = EPERM;
30905e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred))
310a459a6cfSMateusz Guzik 		error = 0;
311a459a6cfSMateusz Guzik 	return (error);
312a459a6cfSMateusz Guzik }
313a459a6cfSMateusz Guzik 
314a459a6cfSMateusz Guzik int
315a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup_nomac(struct ucred *cred)
316a459a6cfSMateusz Guzik {
317a459a6cfSMateusz Guzik 	int error;
318a459a6cfSMateusz Guzik 
319a459a6cfSMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
320a459a6cfSMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
321a459a6cfSMateusz Guzik 		return (EAGAIN);
322a459a6cfSMateusz Guzik 
323a459a6cfSMateusz Guzik 	error = EPERM;
32405e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred))
325a459a6cfSMateusz Guzik 		error = 0;
326a459a6cfSMateusz Guzik 	return (error);
327a459a6cfSMateusz Guzik }
328a459a6cfSMateusz Guzik 
329a459a6cfSMateusz Guzik static int __noinline
33095275911SMateusz Guzik priv_check_cred_vfs_generation_slow(struct ucred *cred)
3317b2ff0dcSMateusz Guzik {
3327b2ff0dcSMateusz Guzik 	int error;
3337b2ff0dcSMateusz Guzik 
3347b2ff0dcSMateusz Guzik 	error = priv_check_cred_pre(cred, PRIV_VFS_GENERATION);
3357b2ff0dcSMateusz Guzik 	if (error)
3367b2ff0dcSMateusz Guzik 		goto out;
3377b2ff0dcSMateusz Guzik 
3387b2ff0dcSMateusz Guzik 	if (jailed(cred)) {
3397b2ff0dcSMateusz Guzik 		error = EPERM;
3407b2ff0dcSMateusz Guzik 		goto out;
3417b2ff0dcSMateusz Guzik 	}
3427b2ff0dcSMateusz Guzik 
34305e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred)) {
3447b2ff0dcSMateusz Guzik 		error = 0;
3457b2ff0dcSMateusz Guzik 		goto out;
3467b2ff0dcSMateusz Guzik 	}
3477b2ff0dcSMateusz Guzik 
3487b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, false));
3497b2ff0dcSMateusz Guzik out:
3507b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true));
3517b2ff0dcSMateusz Guzik 
3527b2ff0dcSMateusz Guzik }
35395275911SMateusz Guzik 
35495275911SMateusz Guzik int
35595275911SMateusz Guzik priv_check_cred_vfs_generation(struct ucred *cred)
35695275911SMateusz Guzik {
35795275911SMateusz Guzik 	int error;
35895275911SMateusz Guzik 
35995275911SMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
36095275911SMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
36195275911SMateusz Guzik 		return (priv_check_cred_vfs_generation_slow(cred));
36295275911SMateusz Guzik 
36395275911SMateusz Guzik 	error = EPERM;
36405e1e482SMariusz Zaborski 	if (!jailed(cred) && cred->cr_uid == 0 && suser_enabled(cred))
36595275911SMateusz Guzik 		error = 0;
36695275911SMateusz Guzik 	return (error);
36795275911SMateusz Guzik }
368