ugidfw_system.c revision 156300
1/*-
2 * Copyright (c) 2005 Tom Rhodes
3 * Copyright (c) 1999-2002 Robert N. M. Watson
4 * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5 * All rights reserved.
6 *
7 * This software was developed by Robert Watson for the TrustedBSD Project.
8 * It was later enhanced by Tom Rhodes for the TrustedBSD Project.
9 *
10 * This software was developed for the FreeBSD Project in part by Network
11 * Associates Laboratories, the Security Research Division of Network
12 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13 * as part of the DARPA CHATS research program.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $FreeBSD: head/sys/security/mac_bsdextended/mac_bsdextended.c 156300 2006-03-04 20:47:19Z dwmalone $
37 */
38
39/*
40 * Developed by the TrustedBSD Project.
41 * "BSD Extended" MAC policy, allowing the administrator to impose
42 * mandatory rules regarding users and some system objects.
43 */
44
45#include <sys/types.h>
46#include <sys/param.h>
47#include <sys/acl.h>
48#include <sys/conf.h>
49#include <sys/kernel.h>
50#include <sys/lock.h>
51#include <sys/mac.h>
52#include <sys/malloc.h>
53#include <sys/mount.h>
54#include <sys/mutex.h>
55#include <sys/proc.h>
56#include <sys/systm.h>
57#include <sys/sysproto.h>
58#include <sys/sysent.h>
59#include <sys/vnode.h>
60#include <sys/file.h>
61#include <sys/socket.h>
62#include <sys/socketvar.h>
63#include <sys/sysctl.h>
64#include <sys/syslog.h>
65
66#include <net/bpfdesc.h>
67#include <net/if.h>
68#include <net/if_types.h>
69#include <net/if_var.h>
70
71#include <vm/vm.h>
72
73#include <sys/mac_policy.h>
74
75#include <security/mac_bsdextended/mac_bsdextended.h>
76
77static struct mtx mac_bsdextended_mtx;
78
79SYSCTL_DECL(_security_mac);
80
81SYSCTL_NODE(_security_mac, OID_AUTO, bsdextended, CTLFLAG_RW, 0,
82    "TrustedBSD extended BSD MAC policy controls");
83
84static int	mac_bsdextended_enabled = 1;
85SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, enabled, CTLFLAG_RW,
86    &mac_bsdextended_enabled, 0, "Enforce extended BSD policy");
87TUNABLE_INT("security.mac.bsdextended.enabled", &mac_bsdextended_enabled);
88
89MALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended", "BSD Extended MAC rule");
90
91#define	MAC_BSDEXTENDED_MAXRULES	250
92static struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES];
93static int rule_count = 0;
94static int rule_slots = 0;
95
96SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD,
97    &rule_count, 0, "Number of defined rules\n");
98SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD,
99    &rule_slots, 0, "Number of used rule slots\n");
100
101/*
102 * This is just used for logging purposes, eventually we would like
103 * to log much more then failed requests.
104 */
105static int mac_bsdextended_logging;
106SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, logging, CTLFLAG_RW,
107    &mac_bsdextended_logging, 0, "Log failed authorization requests");
108
109/*
110 * This tunable is here for compatibility.  It will allow the user
111 * to switch between the new mode (first rule matches) and the old
112 * functionality (all rules match).
113 */
114static int
115mac_bsdextended_firstmatch_enabled;
116SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, firstmatch_enabled,
117	CTLFLAG_RW, &mac_bsdextended_firstmatch_enabled, 1,
118	"Disable/enable match first rule functionality");
119
120static int
121mac_bsdextended_rule_valid(struct mac_bsdextended_rule *rule)
122{
123
124	if ((rule->mbr_subject.mbi_flags | MBI_BITS) != MBI_BITS)
125		return (EINVAL);
126
127	if ((rule->mbr_object.mbi_flags | MBI_BITS) != MBI_BITS)
128		return (EINVAL);
129
130	if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
131		return (EINVAL);
132
133	return (0);
134}
135
136static int
137sysctl_rule(SYSCTL_HANDLER_ARGS)
138{
139	struct mac_bsdextended_rule temprule, *ruleptr;
140	u_int namelen;
141	int error, index, *name;
142
143	error = 0;
144	name = (int *)arg1;
145	namelen = arg2;
146
147	/* printf("bsdextended sysctl handler (namelen %d)\n", namelen); */
148
149	if (namelen != 1)
150		return (EINVAL);
151
152	index = name[0];
153        if (index >= MAC_BSDEXTENDED_MAXRULES)
154		return (ENOENT);
155
156	ruleptr = NULL;
157	if (req->newptr && req->newlen != 0) {
158		error = SYSCTL_IN(req, &temprule, sizeof(temprule));
159		if (error)
160			return (error);
161		MALLOC(ruleptr, struct mac_bsdextended_rule *,
162		    sizeof(*ruleptr), M_MACBSDEXTENDED, M_WAITOK | M_ZERO);
163	}
164
165	mtx_lock(&mac_bsdextended_mtx);
166
167	if (req->oldptr) {
168		if (index < 0 || index > rule_slots + 1) {
169			error = ENOENT;
170			goto out;
171		}
172		if (rules[index] == NULL) {
173			error = ENOENT;
174			goto out;
175		}
176		temprule = *rules[index];
177	}
178
179	if (req->newptr && req->newlen == 0) {
180		/* printf("deletion\n"); */
181		KASSERT(ruleptr == NULL, ("sysctl_rule: ruleptr != NULL"));
182		ruleptr = rules[index];
183		if (ruleptr == NULL) {
184			error = ENOENT;
185			goto out;
186		}
187		rule_count--;
188		rules[index] = NULL;
189	} else if (req->newptr) {
190		error = mac_bsdextended_rule_valid(&temprule);
191		if (error)
192			goto out;
193
194		if (rules[index] == NULL) {
195			/* printf("addition\n"); */
196			*ruleptr = temprule;
197			rules[index] = ruleptr;
198			ruleptr = NULL;
199			if (index + 1 > rule_slots)
200				rule_slots = index + 1;
201			rule_count++;
202		} else {
203			/* printf("replacement\n"); */
204			*rules[index] = temprule;
205		}
206	}
207
208out:
209	mtx_unlock(&mac_bsdextended_mtx);
210	if (ruleptr != NULL)
211		FREE(ruleptr, M_MACBSDEXTENDED);
212	if (req->oldptr && error == 0)
213		error = SYSCTL_OUT(req, &temprule, sizeof(temprule));
214
215	return (error);
216}
217
218SYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules,
219    CTLFLAG_RW, sysctl_rule, "BSD extended MAC rules");
220
221static void
222mac_bsdextended_init(struct mac_policy_conf *mpc)
223{
224
225	/* Initialize ruleset lock. */
226	mtx_init(&mac_bsdextended_mtx, "mac_bsdextended lock", NULL, MTX_DEF);
227
228	/* Register dynamic sysctl's for rules. */
229}
230
231static void
232mac_bsdextended_destroy(struct mac_policy_conf *mpc)
233{
234
235	/* Destroy ruleset lock. */
236	mtx_destroy(&mac_bsdextended_mtx);
237
238	/* Tear down sysctls. */
239}
240
241static int
242mac_bsdextended_rulecheck(struct mac_bsdextended_rule *rule,
243    struct ucred *cred, uid_t object_uid, gid_t object_gid, int acc_mode)
244{
245	int match;
246
247	/*
248	 * Is there a subject match?
249	 */
250	mtx_assert(&mac_bsdextended_mtx, MA_OWNED);
251	if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
252		match =  (rule->mbr_subject.mbi_uid == cred->cr_uid ||
253		    rule->mbr_subject.mbi_uid == cred->cr_ruid ||
254		    rule->mbr_subject.mbi_uid == cred->cr_svuid);
255
256		if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
257			match = !match;
258
259		if (!match)
260			return (0);
261	}
262
263	if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
264		match = (groupmember(rule->mbr_subject.mbi_gid, cred) ||
265		    rule->mbr_subject.mbi_gid == cred->cr_rgid ||
266		    rule->mbr_subject.mbi_gid == cred->cr_svgid);
267
268		if (rule->mbr_subject.mbi_flags & MBI_NEGATED)
269			match = !match;
270
271		if (!match)
272			return (0);
273	}
274
275	/*
276	 * Is there an object match?
277	 */
278	if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
279		match = (rule->mbr_object.mbi_uid == object_uid);
280
281		if (rule->mbr_object.mbi_flags & MBI_NEGATED)
282			match = !match;
283
284		if (!match)
285			return (0);
286	}
287
288	if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
289		match = (rule->mbr_object.mbi_gid == object_gid);
290
291		if (rule->mbr_object.mbi_flags & MBI_NEGATED)
292			match = !match;
293
294		if (!match)
295			return (0);
296	}
297
298	/*
299	 * Is the access permitted?
300	 */
301	if ((rule->mbr_mode & acc_mode) != acc_mode) {
302		if (mac_bsdextended_logging)
303			log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
304			    " on %d:%d failed. \n", cred->cr_ruid,
305			    cred->cr_rgid, acc_mode, object_uid, object_gid);
306		return (EACCES); /* Matching rule denies access */
307	}
308
309	/*
310	 * If the rule matched, permits access, and first match is enabled,
311	 * return success.
312	 */
313	if (mac_bsdextended_firstmatch_enabled)
314		return (EJUSTRETURN);
315	else
316		return(0);
317}
318
319static int
320mac_bsdextended_check(struct ucred *cred, uid_t object_uid, gid_t object_gid,
321    int acc_mode)
322{
323	int error, i;
324
325	if (suser_cred(cred, 0) == 0)
326		return (0);
327
328	mtx_lock(&mac_bsdextended_mtx);
329	for (i = 0; i < rule_slots; i++) {
330		if (rules[i] == NULL)
331			continue;
332
333		/*
334		 * Since we do not separately handle append, map append to
335		 * write.
336		 */
337		if (acc_mode & MBI_APPEND) {
338			acc_mode &= ~MBI_APPEND;
339			acc_mode |= MBI_WRITE;
340		}
341
342		error = mac_bsdextended_rulecheck(rules[i], cred, object_uid,
343		    object_gid, acc_mode);
344		if (error == EJUSTRETURN)
345			break;
346		if (error) {
347			mtx_unlock(&mac_bsdextended_mtx);
348			return (error);
349		}
350	}
351	mtx_unlock(&mac_bsdextended_mtx);
352	return (0);
353}
354
355static int
356mac_bsdextended_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode)
357{
358	int error;
359	struct vattr vap;
360
361	if (!mac_bsdextended_enabled)
362		return (0);
363
364	error = VOP_GETATTR(vp, &vap, cred, curthread);
365	if (error)
366		return (error);
367
368	return (mac_bsdextended_check(cred, vap.va_uid, vap.va_gid,
369	    acc_mode));
370}
371
372static int
373mac_bsdextended_check_system_swapon(struct ucred *cred, struct vnode *vp,
374    struct label *label)
375{
376
377	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
378}
379
380static int
381mac_bsdextended_check_vnode_access(struct ucred *cred, struct vnode *vp,
382    struct label *label, int acc_mode)
383{
384
385	return (mac_bsdextended_check_vp(cred, vp, acc_mode));
386}
387
388static int
389mac_bsdextended_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
390    struct label *dlabel)
391{
392
393	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
394}
395
396static int
397mac_bsdextended_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
398    struct label *dlabel)
399{
400
401	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
402}
403
404static int
405mac_bsdextended_check_create_vnode(struct ucred *cred, struct vnode *dvp,
406    struct label *dlabel, struct componentname *cnp, struct vattr *vap)
407{
408
409	return (mac_bsdextended_check_vp(cred, dvp, MBI_WRITE));
410}
411
412static int
413mac_bsdextended_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
414    struct label *dlabel, struct vnode *vp, struct label *label,
415    struct componentname *cnp)
416{
417	int error;
418
419	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
420	if (error)
421		return (error);
422
423	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
424}
425
426static int
427mac_bsdextended_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
428    struct label *label, acl_type_t type)
429{
430
431	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
432}
433
434static int
435mac_bsdextended_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp,
436    struct label *label, int attrnamespace, const char *name)
437{
438
439	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
440}
441
442static int
443mac_bsdextended_check_vnode_exec(struct ucred *cred, struct vnode *vp,
444    struct label *label, struct image_params *imgp,
445    struct label *execlabel)
446{
447
448	return (mac_bsdextended_check_vp(cred, vp, MBI_READ|MBI_EXEC));
449}
450
451static int
452mac_bsdextended_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
453    struct label *label, acl_type_t type)
454{
455
456	return (mac_bsdextended_check_vp(cred, vp, MBI_STAT));
457}
458
459static int
460mac_bsdextended_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
461    struct label *label, int attrnamespace, const char *name, struct uio *uio)
462{
463
464	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
465}
466
467static int
468mac_bsdextended_check_vnode_link(struct ucred *cred, struct vnode *dvp,
469    struct label *dlabel, struct vnode *vp, struct label *label,
470    struct componentname *cnp)
471{
472	int error;
473
474	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
475	if (error)
476		return (error);
477
478	error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
479	if (error)
480		return (error);
481	return (0);
482}
483
484static int
485mac_bsdextended_check_vnode_listextattr(struct ucred *cred, struct vnode *vp,
486    struct label *label, int attrnamespace)
487{
488
489	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
490}
491
492static int
493mac_bsdextended_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
494    struct label *dlabel, struct componentname *cnp)
495{
496
497	return (mac_bsdextended_check_vp(cred, dvp, MBI_EXEC));
498}
499
500static int
501mac_bsdextended_check_vnode_open(struct ucred *cred, struct vnode *vp,
502    struct label *filelabel, int acc_mode)
503{
504
505	return (mac_bsdextended_check_vp(cred, vp, acc_mode));
506}
507
508static int
509mac_bsdextended_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
510    struct label *dlabel)
511{
512
513	return (mac_bsdextended_check_vp(cred, dvp, MBI_READ));
514}
515
516static int
517mac_bsdextended_check_vnode_readdlink(struct ucred *cred, struct vnode *vp,
518    struct label *label)
519{
520
521	return (mac_bsdextended_check_vp(cred, vp, MBI_READ));
522}
523
524static int
525mac_bsdextended_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
526    struct label *dlabel, struct vnode *vp, struct label *label,
527    struct componentname *cnp)
528{
529	int error;
530
531	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
532	if (error)
533		return (error);
534	error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
535
536	return (error);
537}
538
539static int
540mac_bsdextended_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
541    struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
542    struct componentname *cnp)
543{
544	int error;
545
546	error = mac_bsdextended_check_vp(cred, dvp, MBI_WRITE);
547	if (error)
548		return (error);
549
550	if (vp != NULL)
551		error = mac_bsdextended_check_vp(cred, vp, MBI_WRITE);
552
553	return (error);
554}
555
556static int
557mac_bsdextended_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
558    struct label *label)
559{
560
561	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
562}
563
564static int
565mac_bsdextended_check_setacl_vnode(struct ucred *cred, struct vnode *vp,
566    struct label *label, acl_type_t type, struct acl *acl)
567{
568
569	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
570}
571
572static int
573mac_bsdextended_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
574    struct label *label, int attrnamespace, const char *name, struct uio *uio)
575{
576
577	return (mac_bsdextended_check_vp(cred, vp, MBI_WRITE));
578}
579
580static int
581mac_bsdextended_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
582    struct label *label, u_long flags)
583{
584
585	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
586}
587
588static int
589mac_bsdextended_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
590    struct label *label, mode_t mode)
591{
592
593	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
594}
595
596static int
597mac_bsdextended_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
598    struct label *label, uid_t uid, gid_t gid)
599{
600
601	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
602}
603
604static int
605mac_bsdextended_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
606    struct label *label, struct timespec atime, struct timespec utime)
607{
608
609	return (mac_bsdextended_check_vp(cred, vp, MBI_ADMIN));
610}
611
612static int
613mac_bsdextended_check_vnode_stat(struct ucred *active_cred,
614    struct ucred *file_cred, struct vnode *vp, struct label *label)
615{
616
617	return (mac_bsdextended_check_vp(active_cred, vp, MBI_STAT));
618}
619
620static struct mac_policy_ops mac_bsdextended_ops =
621{
622	.mpo_destroy = mac_bsdextended_destroy,
623	.mpo_init = mac_bsdextended_init,
624	.mpo_check_system_swapon = mac_bsdextended_check_system_swapon,
625	.mpo_check_vnode_access = mac_bsdextended_check_vnode_access,
626	.mpo_check_vnode_chdir = mac_bsdextended_check_vnode_chdir,
627	.mpo_check_vnode_chroot = mac_bsdextended_check_vnode_chroot,
628	.mpo_check_vnode_create = mac_bsdextended_check_create_vnode,
629	.mpo_check_vnode_delete = mac_bsdextended_check_vnode_delete,
630	.mpo_check_vnode_deleteacl = mac_bsdextended_check_vnode_deleteacl,
631	.mpo_check_vnode_deleteextattr = mac_bsdextended_check_vnode_deleteextattr,
632	.mpo_check_vnode_exec = mac_bsdextended_check_vnode_exec,
633	.mpo_check_vnode_getacl = mac_bsdextended_check_vnode_getacl,
634	.mpo_check_vnode_getextattr = mac_bsdextended_check_vnode_getextattr,
635	.mpo_check_vnode_link = mac_bsdextended_check_vnode_link,
636	.mpo_check_vnode_listextattr = mac_bsdextended_check_vnode_listextattr,
637	.mpo_check_vnode_lookup = mac_bsdextended_check_vnode_lookup,
638	.mpo_check_vnode_open = mac_bsdextended_check_vnode_open,
639	.mpo_check_vnode_readdir = mac_bsdextended_check_vnode_readdir,
640	.mpo_check_vnode_readlink = mac_bsdextended_check_vnode_readdlink,
641	.mpo_check_vnode_rename_from = mac_bsdextended_check_vnode_rename_from,
642	.mpo_check_vnode_rename_to = mac_bsdextended_check_vnode_rename_to,
643	.mpo_check_vnode_revoke = mac_bsdextended_check_vnode_revoke,
644	.mpo_check_vnode_setacl = mac_bsdextended_check_setacl_vnode,
645	.mpo_check_vnode_setextattr = mac_bsdextended_check_vnode_setextattr,
646	.mpo_check_vnode_setflags = mac_bsdextended_check_vnode_setflags,
647	.mpo_check_vnode_setmode = mac_bsdextended_check_vnode_setmode,
648	.mpo_check_vnode_setowner = mac_bsdextended_check_vnode_setowner,
649	.mpo_check_vnode_setutimes = mac_bsdextended_check_vnode_setutimes,
650	.mpo_check_vnode_stat = mac_bsdextended_check_vnode_stat,
651};
652
653MAC_POLICY_SET(&mac_bsdextended_ops, mac_bsdextended,
654    "TrustedBSD MAC/BSD Extended", MPC_LOADTIME_FLAG_UNLOADOK, NULL);
655