xref: /freebsd/sys/kern/kern_priv.c (revision fdafd315)
1800c9408SRobert Watson /*-
24d846d26SWarner 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 
34800c9408SRobert Watson #include <sys/param.h>
35800c9408SRobert Watson #include <sys/jail.h>
36800c9408SRobert Watson #include <sys/kernel.h>
3705e1e482SMariusz Zaborski #include <sys/lock.h>
3805e1e482SMariusz Zaborski #include <sys/mutex.h>
3905e1e482SMariusz Zaborski #include <sys/sx.h>
40800c9408SRobert Watson #include <sys/priv.h>
41800c9408SRobert Watson #include <sys/proc.h>
426efcc2f2SRobert Watson #include <sys/sdt.h>
43800c9408SRobert Watson #include <sys/sysctl.h>
44800c9408SRobert Watson #include <sys/systm.h>
45800c9408SRobert Watson 
46800c9408SRobert Watson #include <security/mac/mac_framework.h>
47800c9408SRobert Watson 
48800c9408SRobert Watson /*
49800c9408SRobert Watson  * `suser_enabled' (which can be set by the security.bsd.suser_enabled
50800c9408SRobert Watson  * sysctl) determines whether the system 'super-user' policy is in effect.  If
51800c9408SRobert Watson  * it is nonzero, an effective uid of 0 connotes special privilege,
52800c9408SRobert Watson  * overriding many mandatory and discretionary protections.  If it is zero,
53800c9408SRobert Watson  * uid 0 is offered no special privilege in the kernel security policy.
54800c9408SRobert Watson  * Setting it to zero may seriously impact the functionality of many existing
55800c9408SRobert Watson  * userland programs, and should not be done without careful consideration of
56800c9408SRobert Watson  * the consequences.
57800c9408SRobert Watson  */
5805e1e482SMariusz Zaborski 
5905e1e482SMariusz Zaborski static bool
suser_enabled(struct ucred * cred)6005e1e482SMariusz Zaborski suser_enabled(struct ucred *cred)
6105e1e482SMariusz Zaborski {
6205e1e482SMariusz Zaborski 
630fe74ae6SJamie Gritton 	return (prison_allow(cred, PR_ALLOW_SUSER));
6405e1e482SMariusz Zaborski }
6505e1e482SMariusz Zaborski 
6605e1e482SMariusz Zaborski static int
sysctl_kern_suser_enabled(SYSCTL_HANDLER_ARGS)6705e1e482SMariusz Zaborski sysctl_kern_suser_enabled(SYSCTL_HANDLER_ARGS)
6805e1e482SMariusz Zaborski {
6905e1e482SMariusz Zaborski 	struct ucred *cred;
700fe74ae6SJamie Gritton 	int error, enabled;
7105e1e482SMariusz Zaborski 
7205e1e482SMariusz Zaborski 	cred = req->td->td_ucred;
7305e1e482SMariusz Zaborski 	enabled = suser_enabled(cred);
7405e1e482SMariusz Zaborski 	error = sysctl_handle_int(oidp, &enabled, 0, req);
7505e1e482SMariusz Zaborski 	if (error || !req->newptr)
7605e1e482SMariusz Zaborski 		return (error);
770fe74ae6SJamie Gritton 	prison_set_allow(cred, PR_ALLOW_SUSER, enabled);
7805e1e482SMariusz Zaborski 	return (0);
7905e1e482SMariusz Zaborski }
8005e1e482SMariusz Zaborski 
8105e1e482SMariusz Zaborski SYSCTL_PROC(_security_bsd, OID_AUTO, suser_enabled, CTLTYPE_INT |
82f488d5b7SMariusz Zaborski     CTLFLAG_RWTUN | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0,
83f488d5b7SMariusz Zaborski     &sysctl_kern_suser_enabled, "I", "Processes with uid 0 have privilege");
84800c9408SRobert Watson 
855eb0d283SAndrey Zonov static int	unprivileged_mlock = 1;
86af3b2549SHans Petter Selasky SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_mlock, CTLFLAG_RWTUN,
875eb0d283SAndrey Zonov     &unprivileged_mlock, 0, "Allow non-root users to call mlock(2)");
885eb0d283SAndrey Zonov 
89b19d66fdSJamie Gritton static int	unprivileged_read_msgbuf = 1;
90b19d66fdSJamie Gritton SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
91b19d66fdSJamie Gritton     CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
92b19d66fdSJamie Gritton     "Unprivileged processes may read the kernel message buffer");
93b19d66fdSJamie Gritton 
946efcc2f2SRobert Watson SDT_PROVIDER_DEFINE(priv);
95d9fae5abSAndriy Gapon SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int");
96d9fae5abSAndriy Gapon SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int");
976efcc2f2SRobert Watson 
987b2ff0dcSMateusz Guzik static __always_inline int
priv_check_cred_pre(struct ucred * cred,int priv)997b2ff0dcSMateusz Guzik priv_check_cred_pre(struct ucred *cred, int priv)
1007b2ff0dcSMateusz Guzik {
1017b2ff0dcSMateusz Guzik 	int error;
1027b2ff0dcSMateusz Guzik 
1037b2ff0dcSMateusz Guzik #ifdef MAC
1047b2ff0dcSMateusz Guzik 	error = mac_priv_check(cred, priv);
1057b2ff0dcSMateusz Guzik #else
1067b2ff0dcSMateusz Guzik 	error = 0;
1077b2ff0dcSMateusz Guzik #endif
1087b2ff0dcSMateusz Guzik 	return (error);
1097b2ff0dcSMateusz Guzik }
1107b2ff0dcSMateusz Guzik 
1117b2ff0dcSMateusz Guzik static __always_inline int
priv_check_cred_post(struct ucred * cred,int priv,int error,bool handled)1127b2ff0dcSMateusz Guzik priv_check_cred_post(struct ucred *cred, int priv, int error, bool handled)
1137b2ff0dcSMateusz Guzik {
1147b2ff0dcSMateusz Guzik 
1157b2ff0dcSMateusz Guzik 	if (__predict_true(handled))
1167b2ff0dcSMateusz Guzik 		goto out;
1177b2ff0dcSMateusz Guzik 	/*
1187b2ff0dcSMateusz Guzik 	 * Now check with MAC, if enabled, to see if a policy module grants
1197b2ff0dcSMateusz Guzik 	 * privilege.
1207b2ff0dcSMateusz Guzik 	 */
1217b2ff0dcSMateusz Guzik #ifdef MAC
1227b2ff0dcSMateusz Guzik 	if (mac_priv_grant(cred, priv) == 0) {
1237b2ff0dcSMateusz Guzik 		error = 0;
1247b2ff0dcSMateusz Guzik 		goto out;
1257b2ff0dcSMateusz Guzik 	}
1267b2ff0dcSMateusz Guzik #endif
1277b2ff0dcSMateusz Guzik 
1287b2ff0dcSMateusz Guzik 	/*
1297b2ff0dcSMateusz Guzik 	 * The default is deny, so if no policies have granted it, reject
1307b2ff0dcSMateusz Guzik 	 * with a privilege error here.
1317b2ff0dcSMateusz Guzik 	 */
1327b2ff0dcSMateusz Guzik 	error = EPERM;
1337b2ff0dcSMateusz Guzik out:
1347b2ff0dcSMateusz Guzik 	if (SDT_PROBES_ENABLED()) {
1357b2ff0dcSMateusz Guzik 		if (error)
1367b2ff0dcSMateusz Guzik 			SDT_PROBE1(priv, kernel, priv_check, priv__err, priv);
1377b2ff0dcSMateusz Guzik 		else
1387b2ff0dcSMateusz Guzik 			SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv);
1397b2ff0dcSMateusz Guzik 	}
1407b2ff0dcSMateusz Guzik 	return (error);
1417b2ff0dcSMateusz Guzik }
1427b2ff0dcSMateusz Guzik 
143800c9408SRobert Watson /*
144800c9408SRobert Watson  * Check a credential for privilege.  Lots of good reasons to deny privilege;
145800c9408SRobert Watson  * only a few to grant it.
146800c9408SRobert Watson  */
147800c9408SRobert Watson int
priv_check_cred(struct ucred * cred,int priv)148cc426dd3SMateusz Guzik priv_check_cred(struct ucred *cred, int priv)
149800c9408SRobert Watson {
150800c9408SRobert Watson 	int error;
151800c9408SRobert Watson 
152800c9408SRobert Watson 	KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d",
153800c9408SRobert Watson 	    priv));
154800c9408SRobert Watson 
1557b2ff0dcSMateusz Guzik 	switch (priv) {
156a459a6cfSMateusz Guzik 	case PRIV_VFS_LOOKUP:
157a459a6cfSMateusz Guzik 		return (priv_check_cred_vfs_lookup(cred));
1587b2ff0dcSMateusz Guzik 	case PRIV_VFS_GENERATION:
1597b2ff0dcSMateusz Guzik 		return (priv_check_cred_vfs_generation(cred));
1607b2ff0dcSMateusz Guzik 	}
1617b2ff0dcSMateusz Guzik 
1627251b786SRobert Watson 	/*
1637251b786SRobert Watson 	 * We first evaluate policies that may deny the granting of
1647251b786SRobert Watson 	 * privilege unilaterally.
1657251b786SRobert Watson 	 */
1667b2ff0dcSMateusz Guzik 	error = priv_check_cred_pre(cred, priv);
167800c9408SRobert Watson 	if (error)
1686efcc2f2SRobert Watson 		goto out;
169800c9408SRobert Watson 
170800c9408SRobert Watson 	/*
171800c9408SRobert Watson 	 * Jail policy will restrict certain privileges that may otherwise be
172800c9408SRobert Watson 	 * be granted.
173800c9408SRobert Watson 	 */
174800c9408SRobert Watson 	error = prison_priv_check(cred, priv);
175800c9408SRobert Watson 	if (error)
1766efcc2f2SRobert Watson 		goto out;
177800c9408SRobert Watson 
1785eb0d283SAndrey Zonov 	if (unprivileged_mlock) {
1795eb0d283SAndrey Zonov 		/*
1805eb0d283SAndrey Zonov 		 * Allow unprivileged users to call mlock(2)/munlock(2) and
1815eb0d283SAndrey Zonov 		 * mlockall(2)/munlockall(2).
1825eb0d283SAndrey Zonov 		 */
1835eb0d283SAndrey Zonov 		switch (priv) {
1845eb0d283SAndrey Zonov 		case PRIV_VM_MLOCK:
1855eb0d283SAndrey Zonov 		case PRIV_VM_MUNLOCK:
1865eb0d283SAndrey Zonov 			error = 0;
1875eb0d283SAndrey Zonov 			goto out;
1885eb0d283SAndrey Zonov 		}
1895eb0d283SAndrey Zonov 	}
1905eb0d283SAndrey Zonov 
191b19d66fdSJamie Gritton 	if (unprivileged_read_msgbuf) {
192b19d66fdSJamie Gritton 		/*
193b19d66fdSJamie Gritton 		 * Allow an unprivileged user to read the kernel message
194b19d66fdSJamie Gritton 		 * buffer.
195b19d66fdSJamie Gritton 		 */
196b19d66fdSJamie Gritton 		if (priv == PRIV_MSGBUF) {
197b19d66fdSJamie Gritton 			error = 0;
198b19d66fdSJamie Gritton 			goto out;
199b19d66fdSJamie Gritton 		}
200b19d66fdSJamie Gritton 	}
201b19d66fdSJamie Gritton 
202800c9408SRobert Watson 	/*
203800c9408SRobert Watson 	 * Having determined if privilege is restricted by various policies,
2047251b786SRobert Watson 	 * now determine if privilege is granted.  At this point, any policy
2057251b786SRobert Watson 	 * may grant privilege.  For now, we allow short-circuit boolean
2067251b786SRobert Watson 	 * evaluation, so may not call all policies.  Perhaps we should.
207800c9408SRobert Watson 	 *
208800c9408SRobert Watson 	 * Superuser policy grants privilege based on the effective (or in
2097251b786SRobert Watson 	 * the case of specific privileges, real) uid being 0.  We allow the
2107251b786SRobert Watson 	 * superuser policy to be globally disabled, although this is
2117251b786SRobert Watson 	 * currenty of limited utility.
212800c9408SRobert Watson 	 */
21305e1e482SMariusz Zaborski 	if (suser_enabled(cred)) {
2147251b786SRobert Watson 		switch (priv) {
2157251b786SRobert Watson 		case PRIV_MAXFILES:
2167251b786SRobert Watson 		case PRIV_MAXPROC:
2177251b786SRobert Watson 		case PRIV_PROC_LIMIT:
2186efcc2f2SRobert Watson 			if (cred->cr_ruid == 0) {
2196efcc2f2SRobert Watson 				error = 0;
2206efcc2f2SRobert Watson 				goto out;
2216efcc2f2SRobert Watson 			}
2227251b786SRobert Watson 			break;
22363619b6dSKyle Evans 		case PRIV_VFS_READ_DIR:
22463619b6dSKyle Evans 			/*
22563619b6dSKyle Evans 			 * Allow PRIV_VFS_READ_DIR for root if we're not in a
22663619b6dSKyle Evans 			 * jail, otherwise deny unless a MAC policy grants it.
22763619b6dSKyle Evans 			 */
22863619b6dSKyle Evans 			if (jailed(cred))
22963619b6dSKyle Evans 				break;
23063619b6dSKyle Evans 			/* FALLTHROUGH */
2317251b786SRobert Watson 		default:
2326efcc2f2SRobert Watson 			if (cred->cr_uid == 0) {
2336efcc2f2SRobert Watson 				error = 0;
2346efcc2f2SRobert Watson 				goto out;
2356efcc2f2SRobert Watson 			}
2367251b786SRobert Watson 			break;
237800c9408SRobert Watson 		}
238800c9408SRobert Watson 	}
239800c9408SRobert Watson 
240800c9408SRobert Watson 	/*
2411e7df843SJamie Gritton 	 * Writes to kernel/physical memory are a typical root-only operation,
2421e7df843SJamie Gritton 	 * but non-root users are expected to be able to read it (provided they
2431e7df843SJamie Gritton 	 * have permission to access /dev/[k]mem).
244c71e3362SJamie Gritton 	 */
245c71e3362SJamie Gritton 	if (priv == PRIV_KMEM_READ) {
246c71e3362SJamie Gritton 		error = 0;
247c71e3362SJamie Gritton 		goto out;
248c71e3362SJamie Gritton 	}
249c71e3362SJamie Gritton 
250c71e3362SJamie Gritton 	/*
251b3079544SJamie Gritton 	 * Allow unprivileged process debugging on a per-jail basis.
252b3079544SJamie Gritton 	 * Do this here instead of prison_priv_check(), so it can also
253b3079544SJamie Gritton 	 * apply to prison0.
254b3079544SJamie Gritton 	 */
255b3079544SJamie Gritton 	if (priv == PRIV_DEBUG_UNPRIV) {
256b3079544SJamie Gritton 		if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) {
257b3079544SJamie Gritton 			error = 0;
258b3079544SJamie Gritton 			goto out;
259b3079544SJamie Gritton 		}
260b3079544SJamie Gritton 	}
261b3079544SJamie Gritton 
2627b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, priv, error, false));
2636efcc2f2SRobert Watson out:
2647b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, priv, error, true));
265800c9408SRobert Watson }
266800c9408SRobert Watson 
267800c9408SRobert Watson int
priv_check(struct thread * td,int priv)268800c9408SRobert Watson priv_check(struct thread *td, int priv)
269800c9408SRobert Watson {
270800c9408SRobert Watson 
271800c9408SRobert Watson 	KASSERT(td == curthread, ("priv_check: td != curthread"));
272800c9408SRobert Watson 
273cc426dd3SMateusz Guzik 	return (priv_check_cred(td->td_ucred, priv));
274800c9408SRobert Watson }
2757b2ff0dcSMateusz Guzik 
27695275911SMateusz Guzik static int __noinline
priv_check_cred_vfs_lookup_slow(struct ucred * cred)277a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup_slow(struct ucred *cred)
278a459a6cfSMateusz Guzik {
279a459a6cfSMateusz Guzik 	int error;
280a459a6cfSMateusz Guzik 
281a459a6cfSMateusz Guzik 	error = priv_check_cred_pre(cred, PRIV_VFS_LOOKUP);
282a459a6cfSMateusz Guzik 	if (error)
283a459a6cfSMateusz Guzik 		goto out;
284a459a6cfSMateusz Guzik 
28505e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred)) {
286a459a6cfSMateusz Guzik 		error = 0;
287a459a6cfSMateusz Guzik 		goto out;
288a459a6cfSMateusz Guzik 	}
289a459a6cfSMateusz Guzik 
290a459a6cfSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, false));
291a459a6cfSMateusz Guzik out:
292a459a6cfSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, true));
293a459a6cfSMateusz Guzik 
294a459a6cfSMateusz Guzik }
295a459a6cfSMateusz Guzik 
296a459a6cfSMateusz Guzik int
priv_check_cred_vfs_lookup(struct ucred * cred)297a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup(struct ucred *cred)
298a459a6cfSMateusz Guzik {
299a459a6cfSMateusz Guzik 	int error;
300a459a6cfSMateusz Guzik 
301a459a6cfSMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
302a459a6cfSMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
303a459a6cfSMateusz Guzik 		return (priv_check_cred_vfs_lookup_slow(cred));
304a459a6cfSMateusz Guzik 
305a459a6cfSMateusz Guzik 	error = EPERM;
30605e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred))
307a459a6cfSMateusz Guzik 		error = 0;
308a459a6cfSMateusz Guzik 	return (error);
309a459a6cfSMateusz Guzik }
310a459a6cfSMateusz Guzik 
311a459a6cfSMateusz Guzik int
priv_check_cred_vfs_lookup_nomac(struct ucred * cred)312a459a6cfSMateusz Guzik priv_check_cred_vfs_lookup_nomac(struct ucred *cred)
313a459a6cfSMateusz Guzik {
314a459a6cfSMateusz Guzik 	int error;
315a459a6cfSMateusz Guzik 
316a459a6cfSMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
317a459a6cfSMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
318a459a6cfSMateusz Guzik 		return (EAGAIN);
319a459a6cfSMateusz Guzik 
320a459a6cfSMateusz Guzik 	error = EPERM;
32105e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred))
322a459a6cfSMateusz Guzik 		error = 0;
323a459a6cfSMateusz Guzik 	return (error);
324a459a6cfSMateusz Guzik }
325a459a6cfSMateusz Guzik 
326a459a6cfSMateusz Guzik static int __noinline
priv_check_cred_vfs_generation_slow(struct ucred * cred)32795275911SMateusz Guzik priv_check_cred_vfs_generation_slow(struct ucred *cred)
3287b2ff0dcSMateusz Guzik {
3297b2ff0dcSMateusz Guzik 	int error;
3307b2ff0dcSMateusz Guzik 
3317b2ff0dcSMateusz Guzik 	error = priv_check_cred_pre(cred, PRIV_VFS_GENERATION);
3327b2ff0dcSMateusz Guzik 	if (error)
3337b2ff0dcSMateusz Guzik 		goto out;
3347b2ff0dcSMateusz Guzik 
3357b2ff0dcSMateusz Guzik 	if (jailed(cred)) {
3367b2ff0dcSMateusz Guzik 		error = EPERM;
3377b2ff0dcSMateusz Guzik 		goto out;
3387b2ff0dcSMateusz Guzik 	}
3397b2ff0dcSMateusz Guzik 
34005e1e482SMariusz Zaborski 	if (cred->cr_uid == 0 && suser_enabled(cred)) {
3417b2ff0dcSMateusz Guzik 		error = 0;
3427b2ff0dcSMateusz Guzik 		goto out;
3437b2ff0dcSMateusz Guzik 	}
3447b2ff0dcSMateusz Guzik 
3457b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, false));
3467b2ff0dcSMateusz Guzik out:
3477b2ff0dcSMateusz Guzik 	return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true));
3487b2ff0dcSMateusz Guzik 
3497b2ff0dcSMateusz Guzik }
35095275911SMateusz Guzik 
35195275911SMateusz Guzik int
priv_check_cred_vfs_generation(struct ucred * cred)35295275911SMateusz Guzik priv_check_cred_vfs_generation(struct ucred *cred)
35395275911SMateusz Guzik {
35495275911SMateusz Guzik 	int error;
35595275911SMateusz Guzik 
35695275911SMateusz Guzik 	if (__predict_false(mac_priv_check_fp_flag ||
35795275911SMateusz Guzik 	    mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
35895275911SMateusz Guzik 		return (priv_check_cred_vfs_generation_slow(cred));
35995275911SMateusz Guzik 
36095275911SMateusz Guzik 	error = EPERM;
36105e1e482SMariusz Zaborski 	if (!jailed(cred) && cred->cr_uid == 0 && suser_enabled(cred))
36295275911SMateusz Guzik 		error = 0;
36395275911SMateusz Guzik 	return (error);
36495275911SMateusz Guzik }
365