1101099Srwatson/*-
2184467Srwatson * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
3145412Strhodes * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
4171253Srwatson * Copyright (c) 2005 Tom Rhodes
5172930Srwatson * Copyright (c) 2006 SPARTA, Inc.
6101099Srwatson * All rights reserved.
7101099Srwatson *
8101099Srwatson * This software was developed by Robert Watson for the TrustedBSD Project.
9145412Strhodes * It was later enhanced by Tom Rhodes for the TrustedBSD Project.
10101099Srwatson *
11106393Srwatson * This software was developed for the FreeBSD Project in part by Network
12106393Srwatson * Associates Laboratories, the Security Research Division of Network
13106393Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
14106393Srwatson * as part of the DARPA CHATS research program.
15101099Srwatson *
16172930Srwatson * This software was enhanced by SPARTA ISSO under SPAWAR contract
17172930Srwatson * N66001-04-C-6019 ("SEFOS").
18172930Srwatson *
19101099Srwatson * Redistribution and use in source and binary forms, with or without
20101099Srwatson * modification, are permitted provided that the following conditions
21101099Srwatson * are met:
22101099Srwatson * 1. Redistributions of source code must retain the above copyright
23101099Srwatson *    notice, this list of conditions and the following disclaimer.
24101099Srwatson * 2. Redistributions in binary form must reproduce the above copyright
25101099Srwatson *    notice, this list of conditions and the following disclaimer in the
26101099Srwatson *    documentation and/or other materials provided with the distribution.
27101099Srwatson *
28101099Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29101099Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30101099Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31101099Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32101099Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33101099Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34101099Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35101099Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36101099Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37101099Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38101099Srwatson * SUCH DAMAGE.
39101099Srwatson *
40101099Srwatson * $FreeBSD: stable/10/sys/security/mac_bsdextended/mac_bsdextended.c 321056 2017-07-16 19:25:18Z emaste $
41101099Srwatson */
42136774Srwatson
43101099Srwatson/*
44101099Srwatson * Developed by the TrustedBSD Project.
45171253Srwatson *
46171253Srwatson * "BSD Extended" MAC policy, allowing the administrator to impose mandatory
47171253Srwatson * firewall-like rules regarding users and file system objects.
48101099Srwatson */
49101099Srwatson
50101099Srwatson#include <sys/param.h>
51101099Srwatson#include <sys/acl.h>
52101099Srwatson#include <sys/kernel.h>
53157986Sdwmalone#include <sys/jail.h>
54145412Strhodes#include <sys/lock.h>
55101099Srwatson#include <sys/malloc.h>
56166905Srwatson#include <sys/module.h>
57101099Srwatson#include <sys/mount.h>
58145412Strhodes#include <sys/mutex.h>
59170689Srwatson#include <sys/priv.h>
60185435Sbz#include <sys/proc.h>
61101099Srwatson#include <sys/systm.h>
62101099Srwatson#include <sys/vnode.h>
63101099Srwatson#include <sys/sysctl.h>
64134132Strhodes#include <sys/syslog.h>
65182905Strasz#include <sys/stat.h>
66101099Srwatson
67165469Srwatson#include <security/mac/mac_policy.h>
68101099Srwatson#include <security/mac_bsdextended/mac_bsdextended.h>
69184331Srwatson#include <security/mac_bsdextended/ugidfw_internal.h>
70101099Srwatson
71172955Srwatsonstatic struct mtx ugidfw_mtx;
72145412Strhodes
73101099SrwatsonSYSCTL_DECL(_security_mac);
74101099Srwatson
75227309Sedstatic SYSCTL_NODE(_security_mac, OID_AUTO, bsdextended, CTLFLAG_RW, 0,
76101099Srwatson    "TrustedBSD extended BSD MAC policy controls");
77101099Srwatson
78172955Srwatsonstatic int	ugidfw_enabled = 1;
79101099SrwatsonSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, enabled, CTLFLAG_RW,
80172955Srwatson    &ugidfw_enabled, 0, "Enforce extended BSD policy");
81172955SrwatsonTUNABLE_INT("security.mac.bsdextended.enabled", &ugidfw_enabled);
82101099Srwatson
83227293Sedstatic MALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended",
84227293Sed    "BSD Extended MAC rule");
85101099Srwatson
86101099Srwatson#define	MAC_BSDEXTENDED_MAXRULES	250
87101099Srwatsonstatic struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES];
88101099Srwatsonstatic int rule_count = 0;
89101099Srwatsonstatic int rule_slots = 0;
90157986Sdwmalonestatic int rule_version = MB_VERSION;
91101099Srwatson
92101099SrwatsonSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD,
93101099Srwatson    &rule_count, 0, "Number of defined rules\n");
94101099SrwatsonSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD,
95101099Srwatson    &rule_slots, 0, "Number of used rule slots\n");
96157986SdwmaloneSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_version, CTLFLAG_RD,
97157986Sdwmalone    &rule_version, 0, "Version number for API\n");
98101099Srwatson
99134132Strhodes/*
100171253Srwatson * This is just used for logging purposes, eventually we would like to log
101171253Srwatson * much more then failed requests.
102134132Strhodes */
103172955Srwatsonstatic int ugidfw_logging;
104134132StrhodesSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, logging, CTLFLAG_RW,
105172955Srwatson    &ugidfw_logging, 0, "Log failed authorization requests");
106134132Strhodes
107134132Strhodes/*
108171253Srwatson * This tunable is here for compatibility.  It will allow the user to switch
109171253Srwatson * between the new mode (first rule matches) and the old functionality (all
110171253Srwatson * rules match).
111134131Strhodes */
112172955Srwatsonstatic int ugidfw_firstmatch_enabled;
113134131StrhodesSYSCTL_INT(_security_mac_bsdextended, OID_AUTO, firstmatch_enabled,
114172955Srwatson    CTLFLAG_RW, &ugidfw_firstmatch_enabled, 1,
115171253Srwatson    "Disable/enable match first rule functionality");
116134131Strhodes
117134131Strhodesstatic int
118172955Srwatsonugidfw_rule_valid(struct mac_bsdextended_rule *rule)
119101099Srwatson{
120101099Srwatson
121157986Sdwmalone	if ((rule->mbr_subject.mbs_flags | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
122101099Srwatson		return (EINVAL);
123157986Sdwmalone	if ((rule->mbr_subject.mbs_neg | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
124101099Srwatson		return (EINVAL);
125157986Sdwmalone	if ((rule->mbr_object.mbo_flags | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
126157986Sdwmalone		return (EINVAL);
127157986Sdwmalone	if ((rule->mbr_object.mbo_neg | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
128157986Sdwmalone		return (EINVAL);
129321056Semaste	if (((rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) != 0) &&
130157986Sdwmalone	    (rule->mbr_object.mbo_type | MBO_ALL_TYPE) != MBO_ALL_TYPE)
131157986Sdwmalone		return (EINVAL);
132136739Srwatson	if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
133101099Srwatson		return (EINVAL);
134101099Srwatson	return (0);
135101099Srwatson}
136101099Srwatson
137101099Srwatsonstatic int
138101099Srwatsonsysctl_rule(SYSCTL_HANDLER_ARGS)
139101099Srwatson{
140101099Srwatson	struct mac_bsdextended_rule temprule, *ruleptr;
141101099Srwatson	u_int namelen;
142101099Srwatson	int error, index, *name;
143101099Srwatson
144145412Strhodes	error = 0;
145101099Srwatson	name = (int *)arg1;
146101099Srwatson	namelen = arg2;
147101099Srwatson	if (namelen != 1)
148101099Srwatson		return (EINVAL);
149101099Srwatson	index = name[0];
150154386Scsjp        if (index >= MAC_BSDEXTENDED_MAXRULES)
151101099Srwatson		return (ENOENT);
152101099Srwatson
153145412Strhodes	ruleptr = NULL;
154145412Strhodes	if (req->newptr && req->newlen != 0) {
155145412Strhodes		error = SYSCTL_IN(req, &temprule, sizeof(temprule));
156101099Srwatson		if (error)
157101099Srwatson			return (error);
158184214Sdes		ruleptr = malloc(sizeof(*ruleptr), M_MACBSDEXTENDED,
159184214Sdes		    M_WAITOK | M_ZERO);
160101099Srwatson	}
161101099Srwatson
162172955Srwatson	mtx_lock(&ugidfw_mtx);
163145412Strhodes	if (req->oldptr) {
164145412Strhodes		if (index < 0 || index > rule_slots + 1) {
165145412Strhodes			error = ENOENT;
166145412Strhodes			goto out;
167101099Srwatson		}
168145412Strhodes		if (rules[index] == NULL) {
169145412Strhodes			error = ENOENT;
170145412Strhodes			goto out;
171145412Strhodes		}
172145412Strhodes		temprule = *rules[index];
173145412Strhodes	}
174145412Strhodes	if (req->newptr && req->newlen == 0) {
175145412Strhodes		KASSERT(ruleptr == NULL, ("sysctl_rule: ruleptr != NULL"));
176145412Strhodes		ruleptr = rules[index];
177145412Strhodes		if (ruleptr == NULL) {
178145412Strhodes			error = ENOENT;
179145412Strhodes			goto out;
180145412Strhodes		}
181145412Strhodes		rule_count--;
182145412Strhodes		rules[index] = NULL;
183145412Strhodes	} else if (req->newptr) {
184172955Srwatson		error = ugidfw_rule_valid(&temprule);
185101099Srwatson		if (error)
186145412Strhodes			goto out;
187101099Srwatson		if (rules[index] == NULL) {
188101099Srwatson			*ruleptr = temprule;
189101099Srwatson			rules[index] = ruleptr;
190145412Strhodes			ruleptr = NULL;
191145412Strhodes			if (index + 1 > rule_slots)
192145412Strhodes				rule_slots = index + 1;
193101099Srwatson			rule_count++;
194171253Srwatson		} else
195101099Srwatson			*rules[index] = temprule;
196101099Srwatson	}
197145412Strhodesout:
198172955Srwatson	mtx_unlock(&ugidfw_mtx);
199145412Strhodes	if (ruleptr != NULL)
200184205Sdes		free(ruleptr, M_MACBSDEXTENDED);
201148482Strhodes	if (req->oldptr && error == 0)
202145412Strhodes		error = SYSCTL_OUT(req, &temprule, sizeof(temprule));
203148482Strhodes	return (error);
204101099Srwatson}
205101099Srwatson
206227309Sedstatic SYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules,
207189590Scsjp    CTLFLAG_MPSAFE | CTLFLAG_RW, sysctl_rule, "BSD extended MAC rules");
208101099Srwatson
209101099Srwatsonstatic void
210172955Srwatsonugidfw_init(struct mac_policy_conf *mpc)
211101099Srwatson{
212101099Srwatson
213172955Srwatson	mtx_init(&ugidfw_mtx, "mac_bsdextended lock", NULL, MTX_DEF);
214101099Srwatson}
215101099Srwatson
216101099Srwatsonstatic void
217172955Srwatsonugidfw_destroy(struct mac_policy_conf *mpc)
218101099Srwatson{
219184367Srwatson	int i;
220101099Srwatson
221184367Srwatson	for (i = 0; i < MAC_BSDEXTENDED_MAXRULES; i++) {
222184367Srwatson		if (rules[i] != NULL)
223184367Srwatson			free(rules[i], M_MACBSDEXTENDED);
224184367Srwatson	}
225172955Srwatson	mtx_destroy(&ugidfw_mtx);
226101099Srwatson}
227101099Srwatson
228101099Srwatsonstatic int
229172955Srwatsonugidfw_rulecheck(struct mac_bsdextended_rule *rule,
230157986Sdwmalone    struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode)
231101099Srwatson{
232183113Sattilio	int mac_granted, match, priv_granted;
233157986Sdwmalone	int i;
234101099Srwatson
235101099Srwatson	/*
236101099Srwatson	 * Is there a subject match?
237101099Srwatson	 */
238172955Srwatson	mtx_assert(&ugidfw_mtx, MA_OWNED);
239157986Sdwmalone	if (rule->mbr_subject.mbs_flags & MBS_UID_DEFINED) {
240157986Sdwmalone		match =  ((cred->cr_uid <= rule->mbr_subject.mbs_uid_max &&
241157986Sdwmalone		    cred->cr_uid >= rule->mbr_subject.mbs_uid_min) ||
242157986Sdwmalone		    (cred->cr_ruid <= rule->mbr_subject.mbs_uid_max &&
243157986Sdwmalone		    cred->cr_ruid >= rule->mbr_subject.mbs_uid_min) ||
244157986Sdwmalone		    (cred->cr_svuid <= rule->mbr_subject.mbs_uid_max &&
245157986Sdwmalone		    cred->cr_svuid >= rule->mbr_subject.mbs_uid_min));
246157986Sdwmalone		if (rule->mbr_subject.mbs_neg & MBS_UID_DEFINED)
247101099Srwatson			match = !match;
248101099Srwatson		if (!match)
249101099Srwatson			return (0);
250101099Srwatson	}
251101099Srwatson
252157986Sdwmalone	if (rule->mbr_subject.mbs_flags & MBS_GID_DEFINED) {
253157986Sdwmalone		match = ((cred->cr_rgid <= rule->mbr_subject.mbs_gid_max &&
254157986Sdwmalone		    cred->cr_rgid >= rule->mbr_subject.mbs_gid_min) ||
255157986Sdwmalone		    (cred->cr_svgid <= rule->mbr_subject.mbs_gid_max &&
256157986Sdwmalone		    cred->cr_svgid >= rule->mbr_subject.mbs_gid_min));
257157986Sdwmalone		if (!match) {
258171253Srwatson			for (i = 0; i < cred->cr_ngroups; i++) {
259157986Sdwmalone				if (cred->cr_groups[i]
260157986Sdwmalone				    <= rule->mbr_subject.mbs_gid_max &&
261157986Sdwmalone				    cred->cr_groups[i]
262157986Sdwmalone				    >= rule->mbr_subject.mbs_gid_min) {
263157986Sdwmalone					match = 1;
264157986Sdwmalone					break;
265157986Sdwmalone				}
266171253Srwatson			}
267157986Sdwmalone		}
268157986Sdwmalone		if (rule->mbr_subject.mbs_neg & MBS_GID_DEFINED)
269101099Srwatson			match = !match;
270101099Srwatson		if (!match)
271101099Srwatson			return (0);
272101099Srwatson	}
273101099Srwatson
274157986Sdwmalone	if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
275192895Sjamie		match =
276192895Sjamie		    (cred->cr_prison->pr_id == rule->mbr_subject.mbs_prison);
277157986Sdwmalone		if (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)
278157986Sdwmalone			match = !match;
279157986Sdwmalone		if (!match)
280157986Sdwmalone			return (0);
281157986Sdwmalone	}
282157986Sdwmalone
283101099Srwatson	/*
284101099Srwatson	 * Is there an object match?
285101099Srwatson	 */
286157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
287157986Sdwmalone		match = (vap->va_uid <= rule->mbr_object.mbo_uid_max &&
288157986Sdwmalone		    vap->va_uid >= rule->mbr_object.mbo_uid_min);
289157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)
290101099Srwatson			match = !match;
291101099Srwatson		if (!match)
292101099Srwatson			return (0);
293101099Srwatson	}
294101099Srwatson
295157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
296157986Sdwmalone		match = (vap->va_gid <= rule->mbr_object.mbo_gid_max &&
297157986Sdwmalone		    vap->va_gid >= rule->mbr_object.mbo_gid_min);
298157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)
299101099Srwatson			match = !match;
300101099Srwatson		if (!match)
301101099Srwatson			return (0);
302101099Srwatson	}
303101099Srwatson
304157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
305157986Sdwmalone		match = (bcmp(&(vp->v_mount->mnt_stat.f_fsid),
306157986Sdwmalone		    &(rule->mbr_object.mbo_fsid),
307157986Sdwmalone		    sizeof(rule->mbr_object.mbo_fsid)) == 0);
308157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)
309157986Sdwmalone			match = !match;
310157986Sdwmalone		if (!match)
311171253Srwatson			return (0);
312157986Sdwmalone	}
313157986Sdwmalone
314157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_SUID) {
315182905Strasz		match = (vap->va_mode & S_ISUID);
316157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_SUID)
317157986Sdwmalone			match = !match;
318157986Sdwmalone		if (!match)
319171253Srwatson			return (0);
320157986Sdwmalone	}
321157986Sdwmalone
322157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_SGID) {
323182905Strasz		match = (vap->va_mode & S_ISGID);
324157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_SGID)
325157986Sdwmalone			match = !match;
326157986Sdwmalone		if (!match)
327171253Srwatson			return (0);
328157986Sdwmalone	}
329157986Sdwmalone
330157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
331157986Sdwmalone		match = (vap->va_uid == cred->cr_uid ||
332157986Sdwmalone		    vap->va_uid == cred->cr_ruid ||
333157986Sdwmalone		    vap->va_uid == cred->cr_svuid);
334157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)
335157986Sdwmalone			match = !match;
336157986Sdwmalone		if (!match)
337171253Srwatson			return (0);
338157986Sdwmalone	}
339157986Sdwmalone
340157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
341157986Sdwmalone		match = (groupmember(vap->va_gid, cred) ||
342157986Sdwmalone		    vap->va_gid == cred->cr_rgid ||
343157986Sdwmalone		    vap->va_gid == cred->cr_svgid);
344157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)
345157986Sdwmalone			match = !match;
346157986Sdwmalone		if (!match)
347171253Srwatson			return (0);
348157986Sdwmalone	}
349157986Sdwmalone
350157986Sdwmalone	if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
351157986Sdwmalone		switch (vap->va_type) {
352157986Sdwmalone		case VREG:
353157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_REG);
354157986Sdwmalone			break;
355157986Sdwmalone		case VDIR:
356157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_DIR);
357157986Sdwmalone			break;
358157986Sdwmalone		case VBLK:
359157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_BLK);
360157986Sdwmalone			break;
361157986Sdwmalone		case VCHR:
362157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_CHR);
363157986Sdwmalone			break;
364157986Sdwmalone		case VLNK:
365157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_LNK);
366157986Sdwmalone			break;
367157986Sdwmalone		case VSOCK:
368157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_SOCK);
369157986Sdwmalone			break;
370157986Sdwmalone		case VFIFO:
371157986Sdwmalone			match = (rule->mbr_object.mbo_type & MBO_TYPE_FIFO);
372157986Sdwmalone			break;
373157986Sdwmalone		default:
374157986Sdwmalone			match = 0;
375157986Sdwmalone		}
376157986Sdwmalone		if (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)
377157986Sdwmalone			match = !match;
378157986Sdwmalone		if (!match)
379171253Srwatson			return (0);
380157986Sdwmalone	}
381157986Sdwmalone
382101099Srwatson	/*
383183113Sattilio	 * MBI_APPEND should not be here as it should get converted to
384183113Sattilio	 * MBI_WRITE.
385183113Sattilio	 */
386183113Sattilio	priv_granted = 0;
387183113Sattilio	mac_granted = rule->mbr_mode;
388183113Sattilio	if ((acc_mode & MBI_ADMIN) && (mac_granted & MBI_ADMIN) == 0 &&
389183113Sattilio	    priv_check_cred(cred, PRIV_VFS_ADMIN, 0) == 0)
390183113Sattilio		priv_granted |= MBI_ADMIN;
391183113Sattilio	if ((acc_mode & MBI_EXEC) && (mac_granted & MBI_EXEC) == 0 &&
392183113Sattilio	    priv_check_cred(cred, (vap->va_type == VDIR) ? PRIV_VFS_LOOKUP :
393183113Sattilio	    PRIV_VFS_EXEC, 0) == 0)
394183113Sattilio		priv_granted |= MBI_EXEC;
395183113Sattilio	if ((acc_mode & MBI_READ) && (mac_granted & MBI_READ) == 0 &&
396183113Sattilio	    priv_check_cred(cred, PRIV_VFS_READ, 0) == 0)
397183113Sattilio		priv_granted |= MBI_READ;
398183113Sattilio	if ((acc_mode & MBI_STAT) && (mac_granted & MBI_STAT) == 0 &&
399183113Sattilio	    priv_check_cred(cred, PRIV_VFS_STAT, 0) == 0)
400183113Sattilio		priv_granted |= MBI_STAT;
401183113Sattilio	if ((acc_mode & MBI_WRITE) && (mac_granted & MBI_WRITE) == 0 &&
402183113Sattilio	    priv_check_cred(cred, PRIV_VFS_WRITE, 0) == 0)
403183113Sattilio		priv_granted |= MBI_WRITE;
404183113Sattilio	/*
405101099Srwatson	 * Is the access permitted?
406101099Srwatson	 */
407183113Sattilio	if (((mac_granted | priv_granted) & acc_mode) != acc_mode) {
408172955Srwatson		if (ugidfw_logging)
409134132Strhodes			log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
410134132Strhodes			    " on %d:%d failed. \n", cred->cr_ruid,
411171253Srwatson			    cred->cr_rgid, acc_mode, vap->va_uid,
412171253Srwatson			    vap->va_gid);
413171253Srwatson		return (EACCES);
414101099Srwatson	}
415145412Strhodes
416134131Strhodes	/*
417145412Strhodes	 * If the rule matched, permits access, and first match is enabled,
418145412Strhodes	 * return success.
419134131Strhodes	 */
420172955Srwatson	if (ugidfw_firstmatch_enabled)
421134131Strhodes		return (EJUSTRETURN);
422134131Strhodes	else
423171253Srwatson		return (0);
424101099Srwatson}
425101099Srwatson
426184331Srwatsonint
427172955Srwatsonugidfw_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
428106212Srwatson    int acc_mode)
429101099Srwatson{
430101099Srwatson	int error, i;
431101099Srwatson
432164033Srwatson	/*
433166843Srwatson	 * Since we do not separately handle append, map append to write.
434166843Srwatson	 */
435166843Srwatson	if (acc_mode & MBI_APPEND) {
436166843Srwatson		acc_mode &= ~MBI_APPEND;
437166843Srwatson		acc_mode |= MBI_WRITE;
438166843Srwatson	}
439172955Srwatson	mtx_lock(&ugidfw_mtx);
440101099Srwatson	for (i = 0; i < rule_slots; i++) {
441101099Srwatson		if (rules[i] == NULL)
442101099Srwatson			continue;
443172955Srwatson		error = ugidfw_rulecheck(rules[i], cred,
444157986Sdwmalone		    vp, vap, acc_mode);
445134131Strhodes		if (error == EJUSTRETURN)
446134131Strhodes			break;
447145412Strhodes		if (error) {
448172955Srwatson			mtx_unlock(&ugidfw_mtx);
449101099Srwatson			return (error);
450145412Strhodes		}
451101099Srwatson	}
452172955Srwatson	mtx_unlock(&ugidfw_mtx);
453101099Srwatson	return (0);
454101099Srwatson}
455101099Srwatson
456184331Srwatsonint
457172955Srwatsonugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode)
458112575Srwatson{
459156300Sdwmalone	int error;
460112575Srwatson	struct vattr vap;
461112575Srwatson
462172955Srwatson	if (!ugidfw_enabled)
463112575Srwatson		return (0);
464182371Sattilio	error = VOP_GETATTR(vp, &vap, cred);
465112575Srwatson	if (error)
466112575Srwatson		return (error);
467172955Srwatson	return (ugidfw_check(cred, vp, &vap, acc_mode));
468112575Srwatson}
469112575Srwatson
470184467Srwatsonint
471184467Srwatsonugidfw_accmode2mbi(accmode_t accmode)
472184467Srwatson{
473184467Srwatson	int mbi;
474184467Srwatson
475184467Srwatson	mbi = 0;
476184467Srwatson	if (accmode & VEXEC)
477184467Srwatson		mbi |= MBI_EXEC;
478184467Srwatson	if (accmode & VWRITE)
479184467Srwatson		mbi |= MBI_WRITE;
480184467Srwatson	if (accmode & VREAD)
481184467Srwatson		mbi |= MBI_READ;
482190524Strasz	if (accmode & VADMIN_PERMS)
483184467Srwatson		mbi |= MBI_ADMIN;
484190524Strasz	if (accmode & VSTAT_PERMS)
485184467Srwatson		mbi |= MBI_STAT;
486184467Srwatson	if (accmode & VAPPEND)
487184467Srwatson		mbi |= MBI_APPEND;
488184467Srwatson	return (mbi);
489184467Srwatson}
490184467Srwatson
491172955Srwatsonstatic struct mac_policy_ops ugidfw_ops =
492101099Srwatson{
493172955Srwatson	.mpo_destroy = ugidfw_destroy,
494172955Srwatson	.mpo_init = ugidfw_init,
495172955Srwatson	.mpo_system_check_acct = ugidfw_system_check_acct,
496172955Srwatson	.mpo_system_check_auditctl = ugidfw_system_check_auditctl,
497172955Srwatson	.mpo_system_check_swapon = ugidfw_system_check_swapon,
498172955Srwatson	.mpo_vnode_check_access = ugidfw_vnode_check_access,
499172955Srwatson	.mpo_vnode_check_chdir = ugidfw_vnode_check_chdir,
500172955Srwatson	.mpo_vnode_check_chroot = ugidfw_vnode_check_chroot,
501172955Srwatson	.mpo_vnode_check_create = ugidfw_check_create_vnode,
502172955Srwatson	.mpo_vnode_check_deleteacl = ugidfw_vnode_check_deleteacl,
503172955Srwatson	.mpo_vnode_check_deleteextattr = ugidfw_vnode_check_deleteextattr,
504172955Srwatson	.mpo_vnode_check_exec = ugidfw_vnode_check_exec,
505172955Srwatson	.mpo_vnode_check_getacl = ugidfw_vnode_check_getacl,
506172955Srwatson	.mpo_vnode_check_getextattr = ugidfw_vnode_check_getextattr,
507172955Srwatson	.mpo_vnode_check_link = ugidfw_vnode_check_link,
508172955Srwatson	.mpo_vnode_check_listextattr = ugidfw_vnode_check_listextattr,
509172955Srwatson	.mpo_vnode_check_lookup = ugidfw_vnode_check_lookup,
510172955Srwatson	.mpo_vnode_check_open = ugidfw_vnode_check_open,
511172955Srwatson	.mpo_vnode_check_readdir = ugidfw_vnode_check_readdir,
512172955Srwatson	.mpo_vnode_check_readlink = ugidfw_vnode_check_readdlink,
513172955Srwatson	.mpo_vnode_check_rename_from = ugidfw_vnode_check_rename_from,
514172955Srwatson	.mpo_vnode_check_rename_to = ugidfw_vnode_check_rename_to,
515172955Srwatson	.mpo_vnode_check_revoke = ugidfw_vnode_check_revoke,
516172955Srwatson	.mpo_vnode_check_setacl = ugidfw_check_setacl_vnode,
517172955Srwatson	.mpo_vnode_check_setextattr = ugidfw_vnode_check_setextattr,
518172955Srwatson	.mpo_vnode_check_setflags = ugidfw_vnode_check_setflags,
519172955Srwatson	.mpo_vnode_check_setmode = ugidfw_vnode_check_setmode,
520172955Srwatson	.mpo_vnode_check_setowner = ugidfw_vnode_check_setowner,
521172955Srwatson	.mpo_vnode_check_setutimes = ugidfw_vnode_check_setutimes,
522172955Srwatson	.mpo_vnode_check_stat = ugidfw_vnode_check_stat,
523172955Srwatson	.mpo_vnode_check_unlink = ugidfw_vnode_check_unlink,
524101099Srwatson};
525101099Srwatson
526172955SrwatsonMAC_POLICY_SET(&ugidfw_ops, mac_bsdextended, "TrustedBSD MAC/BSD Extended",
527187016Srwatson    MPC_LOADTIME_FLAG_UNLOADOK, NULL);
528