xref: /freebsd/sys/security/mac_do/mac_do.c (revision f01d26dec67fb6597438ed765269b85d1099a6fa)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
5  * Copyright (c) 2024 The FreeBSD Foundation
6  *
7  * Portions of this software were developed by Olivier Certner
8  * <olce.freebsd@certner.fr> at Kumacom SARL under sponsorship from the FreeBSD
9  * Foundation.
10  */
11 
12 #include <sys/param.h>
13 #include <sys/systm.h>
14 #include <sys/ctype.h>
15 #include <sys/jail.h>
16 #include <sys/kernel.h>
17 #include <sys/limits.h>
18 #include <sys/lock.h>
19 #include <sys/malloc.h>
20 #include <sys/module.h>
21 #include <sys/mount.h>
22 #include <sys/mutex.h>
23 #include <sys/priv.h>
24 #include <sys/proc.h>
25 #include <sys/refcount.h>
26 #include <sys/socket.h>
27 #include <sys/sx.h>
28 #include <sys/sysctl.h>
29 #include <sys/ucred.h>
30 #include <sys/vnode.h>
31 
32 #include <machine/stdarg.h>
33 
34 #include <security/mac/mac_policy.h>
35 
36 static SYSCTL_NODE(_security_mac, OID_AUTO, do,
37     CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "mac_do policy controls");
38 
39 static int	do_enabled = 1;
40 SYSCTL_INT(_security_mac_do, OID_AUTO, enabled, CTLFLAG_RWTUN,
41     &do_enabled, 0, "Enforce do policy");
42 
43 static int	print_parse_error = 1;
44 SYSCTL_INT(_security_mac_do, OID_AUTO, print_parse_error, CTLFLAG_RWTUN,
45     &print_parse_error, 0, "Print parse errors on setting rules "
46     "(via sysctl(8)).");
47 
48 static MALLOC_DEFINE(M_DO, "do_rule", "Rules for mac_do");
49 
50 #define MAC_RULE_STRING_LEN	1024
51 
52 static unsigned		osd_jail_slot;
53 static unsigned		osd_thread_slot;
54 
55 #define IT_INVALID	0 /* Must stay 0. */
56 #define IT_UID		1
57 #define IT_GID		2
58 #define IT_ANY		3
59 #define IT_LAST		IT_ANY
60 
61 static const char *id_type_to_str[] = {
62 	[IT_INVALID]	= "invalid",
63 	[IT_UID]	= "uid",
64 	[IT_GID]	= "gid",
65 	/* See also parse_id_type(). */
66 	[IT_ANY]	= "*",
67 };
68 
69 #define PARSE_ERROR_SIZE	256
70 
71 struct parse_error {
72 	size_t	pos;
73 	char	msg[PARSE_ERROR_SIZE];
74 };
75 
76 /*
77  * We assume that 'uid_t' and 'gid_t' are aliases to 'u_int' in conversions
78  * required for parsing rules specification strings.
79  */
80 _Static_assert(sizeof(uid_t) == sizeof(u_int) && (uid_t)-1 >= 0 &&
81     sizeof(gid_t) == sizeof(u_int) && (gid_t)-1 >= 0,
82     "mac_do(4) assumes that 'uid_t' and 'gid_t' are aliases to 'u_int'");
83 
84 /*
85  * Internal flags.
86  *
87  * They either apply as per-type (t) or per-ID (i) but are conflated because all
88  * per-ID flags are also valid as per-type ones to qualify the "current" (".")
89  * per-type flag.  Also, some of them are in fact exclusive, but we use one-hot
90  * encoding for simplicity.
91  *
92  * There is currently room for "only" 16 bits.  As these flags are purely
93  * internal, they can be renumbered and/or their type changed as needed.
94  *
95  * See also the check_*() functions below.
96  */
97 typedef uint16_t	flags_t;
98 
99 /* (i,gid) Specification concerns primary groups. */
100 #define MDF_PRIMARY	(1u << 0)
101 /* (i,gid) Specification concerns supplementary groups. */
102 #define MDF_SUPP_ALLOW	(1u << 1)
103 /* (i,gid) Group must appear as a supplementary group. */
104 #define MDF_SUPP_MUST	(1u << 2)
105 /* (i,gid) Group must not appear as a supplementary group. */
106 #define MDF_SUPP_DONT	(1u << 3)
107 #define MDF_SUPP_MASK	(MDF_SUPP_ALLOW | MDF_SUPP_MUST | MDF_SUPP_DONT)
108 #define MDF_ID_MASK	(MDF_PRIMARY | MDF_SUPP_MASK)
109 
110 /*
111  * (t) All IDs allowed.
112  *
113  * For GIDs, MDF_ANY only concerns primary groups.  The MDF_PRIMARY and
114  * MDF_SUPP_* flags never apply to MDF_ANY, but can be present if MDF_CURRENT is
115  * present also, as usual.
116  */
117 #define MDF_ANY			(1u << 8)
118 /* (t) Current IDs allowed. */
119 #define MDF_CURRENT		(1u << 9)
120 #define MDF_TYPE_COMMON_MASK	(MDF_ANY | MDF_CURRENT)
121 /* (t,gid) All IDs allowed as supplementary groups. */
122 #define MDF_ANY_SUPP		(1u << 10)
123 /* (t,gid) Some ID or MDF_CURRENT has MDF_SUPP_MUST or MDF_SUPP_DONT. */
124 #define MDF_MAY_REJ_SUPP	(1u << 11)
125 /* (t,gid) Some explicit ID (not MDF_CURRENT) has MDF_SUPP_MUST. */
126 #define MDF_EXPLICIT_SUPP_MUST	(1u << 12)
127 /* (t,gid) Whether any target clause is about primary groups.  Used during
128  * parsing only. */
129 #define MDF_HAS_PRIMARY_CLAUSE	(1u << 13)
130 /* (t,gid) Whether any target clause is about supplementary groups.  Used during
131  * parsing only. */
132 #define MDF_HAS_SUPP_CLAUSE	(1u << 14)
133 #define MDF_TYPE_GID_MASK	(MDF_ANY_SUPP | MDF_MAY_REJ_SUPP |	\
134     MDF_EXPLICIT_SUPP_MUST | MDF_HAS_PRIMARY_CLAUSE | MDF_HAS_SUPP_CLAUSE)
135 #define MDF_TYPE_MASK		(MDF_TYPE_COMMON_MASK | MDF_TYPE_GID_MASK)
136 
137 /*
138  * Persistent structures.
139  */
140 
141 struct id_spec {
142 	u_int		 id;
143 	flags_t		 flags; /* See MDF_* above. */
144 };
145 
146 /*
147  * This limits the number of target clauses per type to 65535.  With the current
148  * value of MAC_RULE_STRING_LEN (1024), this is way more than enough anyway.
149  */
150 typedef uint16_t	 id_nb_t;
151 /* We only have a few IT_* types. */
152 typedef uint16_t	 id_type_t;
153 
154 struct rule {
155 	STAILQ_ENTRY(rule) r_entries;
156 	id_type_t	 from_type;
157 	u_int		 from_id;
158 	flags_t		 uid_flags; /* See MDF_* above. */
159 	id_nb_t		 uids_nb;
160 	flags_t		 gid_flags; /* See MDF_* above. */
161 	id_nb_t		 gids_nb;
162 	struct id_spec	*uids;
163 	struct id_spec	*gids;
164 };
165 
166 STAILQ_HEAD(rulehead, rule);
167 
168 struct rules {
169 	char		string[MAC_RULE_STRING_LEN];
170 	struct rulehead	head;
171 	volatile u_int	use_count __aligned(CACHE_LINE_SIZE);
172 };
173 
174 /*
175  * Temporary structures used to build a 'struct rule' above.
176  */
177 
178 struct id_elem {
179 	STAILQ_ENTRY(id_elem) ie_entries;
180 	struct id_spec spec;
181 };
182 
183 STAILQ_HEAD(id_list, id_elem);
184 
185 #ifdef INVARIANTS
186 static void
check_type(const id_type_t type)187 check_type(const id_type_t type)
188 {
189 	if (type > IT_LAST)
190 		panic("Invalid type number %u", type);
191 }
192 
193 static void
panic_for_unexpected_flags(const id_type_t type,const flags_t flags,const char * const str)194 panic_for_unexpected_flags(const id_type_t type, const flags_t flags,
195     const char *const str)
196 {
197 	panic("ID type %s: Unexpected flags %u (%s), ", id_type_to_str[type],
198 	    flags, str);
199 }
200 
201 static void
check_type_and_id_flags(const id_type_t type,const flags_t flags)202 check_type_and_id_flags(const id_type_t type, const flags_t flags)
203 {
204 	const char *str;
205 
206 	check_type(type);
207 	switch (type) {
208 	case IT_UID:
209 		if (flags != 0) {
210 			str = "only 0 allowed";
211 			goto unexpected_flags;
212 		}
213 		break;
214 	case IT_GID:
215 		if ((flags & ~MDF_ID_MASK) != 0) {
216 			str = "only bits in MDF_ID_MASK allowed";
217 			goto unexpected_flags;
218 		}
219 		if (!powerof2(flags & MDF_SUPP_MASK)) {
220 			str = "only a single flag in MDF_SUPP_MASK allowed";
221 			goto unexpected_flags;
222 		}
223 		break;
224 	default:
225 	    __assert_unreachable();
226 	}
227 	return;
228 
229 unexpected_flags:
230 	panic_for_unexpected_flags(type, flags, str);
231 }
232 
233 static void
check_type_and_id_spec(const id_type_t type,const struct id_spec * const is)234 check_type_and_id_spec(const id_type_t type, const struct id_spec *const is)
235 {
236 	check_type_and_id_flags(type, is->flags);
237 }
238 
239 static void
check_type_and_type_flags(const id_type_t type,const flags_t flags)240 check_type_and_type_flags(const id_type_t type, const flags_t flags)
241 {
242 	const char *str;
243 
244 	check_type_and_id_flags(type, flags & MDF_ID_MASK);
245 	if ((flags & ~MDF_ID_MASK & ~MDF_TYPE_MASK) != 0) {
246 		str = "only MDF_ID_MASK | MDF_TYPE_MASK bits allowed";
247 		goto unexpected_flags;
248 	}
249 	if ((flags & MDF_ANY) != 0 && (flags & MDF_CURRENT) != 0 &&
250 	    (type == IT_UID || (flags & MDF_PRIMARY) != 0)) {
251 		str = "MDF_ANY and MDF_CURRENT are exclusive for UIDs "
252 		    "or primary group GIDs";
253 		goto unexpected_flags;
254 	}
255 	if ((flags & MDF_ANY_SUPP) != 0 && (flags & MDF_CURRENT) != 0 &&
256 	    (flags & MDF_SUPP_MASK) != 0) {
257 		str = "MDF_SUPP_ANY and MDF_CURRENT with supplementary "
258 		    "groups specification are exclusive";
259 		goto unexpected_flags;
260 	}
261 	if (((flags & MDF_PRIMARY) != 0 || (flags & MDF_ANY) != 0) &&
262 	    (flags & MDF_HAS_PRIMARY_CLAUSE) == 0) {
263 		str = "Presence of folded primary clause not reflected "
264 		    "by presence of MDF_HAS_PRIMARY_CLAUSE";
265 		goto unexpected_flags;
266 	}
267 	if (((flags & MDF_SUPP_MASK) != 0 || (flags & MDF_ANY_SUPP) != 0) &&
268 	    (flags & MDF_HAS_SUPP_CLAUSE) == 0) {
269 		str = "Presence of folded supplementary clause not reflected "
270 		    "by presence of MDF_HAS_SUPP_CLAUSE";
271 		goto unexpected_flags;
272 	}
273 	return;
274 
275 unexpected_flags:
276 	panic_for_unexpected_flags(type, flags, str);
277 }
278 #else /* !INVARIANTS */
279 #define check_type_and_id_flags(...)
280 #define check_type_and_id_spec(...)
281 #define check_type_and_type_flags(...)
282 #endif /* INVARIANTS */
283 
284 /*
285  * Returns EALREADY if both flags have some overlap, or EINVAL if flags are
286  * incompatible, else 0 with flags successfully merged into 'dest'.
287  */
288 static int
coalesce_id_flags(const flags_t src,flags_t * const dest)289 coalesce_id_flags(const flags_t src, flags_t *const dest)
290 {
291 	flags_t res;
292 
293 	if ((src & *dest) != 0)
294 		return (EALREADY);
295 
296 	res = src | *dest;
297 
298 	/* Check for compatibility of supplementary flags, and coalesce. */
299 	if ((res & MDF_SUPP_MASK) != 0) {
300 		/* MDF_SUPP_DONT incompatible with the rest. */
301 		if ((res & MDF_SUPP_DONT) != 0 && (res & MDF_SUPP_MASK &
302 		    ~MDF_SUPP_DONT) != 0)
303 			return (EINVAL);
304 		/*
305 		 * Coalesce MDF_SUPP_ALLOW and MDF_SUPP_MUST into MDF_SUPP_MUST.
306 		 */
307 		if ((res & MDF_SUPP_ALLOW) != 0 && (res & MDF_SUPP_MUST) != 0)
308 			res &= ~MDF_SUPP_ALLOW;
309 	}
310 
311 	*dest = res;
312 	return (0);
313 }
314 
315 static void
toast_rules(struct rules * const rules)316 toast_rules(struct rules *const rules)
317 {
318 	struct rulehead *const head = &rules->head;
319 	struct rule *rule, *rule_next;
320 
321 	STAILQ_FOREACH_SAFE(rule, head, r_entries, rule_next) {
322 		free(rule->uids, M_DO);
323 		free(rule->gids, M_DO);
324 		free(rule, M_DO);
325 	}
326 	free(rules, M_DO);
327 }
328 
329 static struct rules *
alloc_rules(void)330 alloc_rules(void)
331 {
332 	struct rules *const rules = malloc(sizeof(*rules), M_DO, M_WAITOK);
333 
334 	_Static_assert(MAC_RULE_STRING_LEN > 0, "MAC_RULE_STRING_LEN <= 0!");
335 	rules->string[0] = 0;
336 	STAILQ_INIT(&rules->head);
337 	rules->use_count = 0;
338 	return (rules);
339 }
340 
341 static bool
is_null_or_empty(const char * s)342 is_null_or_empty(const char *s)
343 {
344 	return (s == NULL || s[0] == '\0');
345 }
346 
347 /*
348  * String to unsigned int.
349  *
350  * Contrary to the "standard" strtou*() family of functions, do not tolerate
351  * spaces at start nor an empty string, and returns a status code, the 'u_int'
352  * result being returned through a passed pointer (if no error).
353  *
354  * We detour through 'quad_t' because in-kernel strto*() functions cannot set
355  * 'errno' and thus can't distinguish a true maximum value from one returned
356  * because of overflow.  We use 'quad_t' instead of 'u_quad_t' to support
357  * negative specifications (e.g., such as "-1" for UINT_MAX).
358  */
359 static int
strtoui_strict(const char * const restrict s,const char ** const restrict endptr,int base,u_int * result)360 strtoui_strict(const char *const restrict s, const char **const restrict endptr,
361     int base, u_int *result)
362 {
363 	char *ep;
364 	quad_t q;
365 
366 	/* Rule out spaces and empty specifications. */
367 	if (s[0] == '\0' || isspace(s[0])) {
368 		if (endptr != NULL)
369 			*endptr = s;
370 		return (EINVAL);
371 	}
372 
373 	q = strtoq(s, &ep, base);
374 	if (endptr != NULL)
375 		*endptr = ep;
376 	if (q < 0) {
377 		/* We allow specifying a negative number. */
378 		if (q < -(quad_t)UINT_MAX - 1 || q == QUAD_MIN)
379 			return (EOVERFLOW);
380 	} else {
381 		if (q > UINT_MAX || q == UQUAD_MAX)
382 			return (EOVERFLOW);
383 	}
384 
385 	*result = (u_int)q;
386 	return (0);
387 }
388 
389 /*
390  * strsep() variant skipping spaces and tabs.
391  *
392  * Skips spaces and tabs at beginning and end of the token before one of the
393  * 'delim' characters, i.e., at start of string and just before one of the
394  * delimiter characters (so it doesn't prevent tokens containing spaces and tabs
395  * in the middle).
396  */
397 static char *
strsep_noblanks(char ** const stringp,const char * delim)398 strsep_noblanks(char **const stringp, const char *delim)
399 {
400 	char *p = *stringp;
401 	char *ret, *wsp;
402 	size_t idx;
403 
404 	if (p == NULL)
405 		return (NULL);
406 
407 	idx = strspn(p, " \t");
408 	p += idx;
409 
410 	ret = strsep(&p, delim);
411 
412 	/* Rewind spaces/tabs at the end. */
413 	if (p == NULL)
414 		wsp = ret + strlen(ret);
415 	else
416 		wsp = p - 1;
417 	for (; wsp != ret; --wsp) {
418 		switch (wsp[-1]) {
419 		case ' ':
420 		case '\t':
421 			continue;
422 		}
423 		break;
424 	}
425 	*wsp = '\0';
426 
427 	*stringp = p;
428 	return (ret);
429 }
430 
431 
432 static void
make_parse_error(struct parse_error ** const parse_error,const size_t pos,const char * const fmt,...)433 make_parse_error(struct parse_error **const parse_error, const size_t pos,
434     const char *const fmt, ...)
435 {
436 	struct parse_error *const err = malloc(sizeof(*err), M_DO, M_WAITOK);
437 	va_list ap;
438 
439 	err->pos = pos;
440 	va_start(ap, fmt);
441 	vsnprintf(err->msg, PARSE_ERROR_SIZE, fmt, ap);
442 	va_end(ap);
443 
444 	MPASS(*parse_error == NULL);
445 	*parse_error = err;
446 }
447 
448 static void
free_parse_error(struct parse_error * const parse_error)449 free_parse_error(struct parse_error *const parse_error)
450 {
451 	free(parse_error, M_DO);
452 }
453 
454 static int
parse_id_type(const char * const string,id_type_t * const type,struct parse_error ** const parse_error)455 parse_id_type(const char *const string, id_type_t *const type,
456     struct parse_error **const parse_error)
457 {
458 	/*
459 	 * Special case for "any", as the canonical form for IT_ANY in
460 	 * id_type_to_str[] is "*".
461 	 */
462 	if (strcmp(string, "any") == 0) {
463 		*type = IT_ANY;
464 		return (0);
465 	}
466 
467 	/* Start at 1 to avoid parsing "invalid". */
468 	for (size_t i = 1; i <= IT_LAST; ++i) {
469 		if (strcmp(string, id_type_to_str[i]) == 0) {
470 			*type = i;
471 			return (0);
472 		}
473 	}
474 
475 	*type = IT_INVALID;
476 	make_parse_error(parse_error, 0, "No valid type found.");
477 	return (EINVAL);
478 }
479 
480 static size_t
parse_gid_flags(const char * const string,flags_t * const flags,flags_t * const gid_flags)481 parse_gid_flags(const char *const string, flags_t *const flags,
482     flags_t *const gid_flags)
483 {
484 	switch (string[0]) {
485 	case '+':
486 		*flags |= MDF_SUPP_ALLOW;
487 		goto has_supp_clause;
488 	case '!':
489 		*flags |= MDF_SUPP_MUST;
490 		*gid_flags |= MDF_MAY_REJ_SUPP;
491 		goto has_supp_clause;
492 	case '-':
493 		*flags |= MDF_SUPP_DONT;
494 		*gid_flags |= MDF_MAY_REJ_SUPP;
495 		goto has_supp_clause;
496 	has_supp_clause:
497 		*gid_flags |= MDF_HAS_SUPP_CLAUSE;
498 		return (1);
499 	}
500 
501 	return (0);
502 }
503 
504 static bool
parse_any(const char * const string)505 parse_any(const char *const string)
506 {
507 	return (strcmp(string, "*") == 0 || strcmp(string, "any") == 0);
508 }
509 
510 static bool
has_clauses(const id_nb_t nb,const flags_t type_flags)511 has_clauses(const id_nb_t nb, const flags_t type_flags)
512 {
513 	return ((type_flags & MDF_TYPE_MASK) != 0 || nb != 0);
514 }
515 
516 static int
parse_target_clause(char * to,struct rule * const rule,struct id_list * const uid_list,struct id_list * const gid_list,struct parse_error ** const parse_error)517 parse_target_clause(char *to, struct rule *const rule,
518     struct id_list *const uid_list, struct id_list *const gid_list,
519     struct parse_error **const parse_error)
520 {
521 	const char *const start = to;
522 	char *to_type, *to_id;
523 	const char *p;
524 	struct id_list *list;
525 	id_nb_t *nb;
526 	flags_t *tflags;
527 	struct id_elem *ie;
528 	struct id_spec is = {.flags = 0};
529 	flags_t gid_flags = 0;
530 	id_type_t type;
531 	int error;
532 
533 	MPASS(*parse_error == NULL);
534 	MPASS(to != NULL);
535 	to_type = strsep_noblanks(&to, "=");
536 	MPASS(to_type != NULL);
537 	to_type += parse_gid_flags(to_type, &is.flags, &gid_flags);
538 	error = parse_id_type(to_type, &type, parse_error);
539 	if (error != 0)
540 		goto einval;
541 	if (type != IT_GID && is.flags != 0) {
542 		make_parse_error(parse_error, to_type - start,
543 		    "Expected type 'gid' after flags, not '%s'.",
544 		    to_type);
545 		goto einval;
546 	}
547 
548 	to_id = strsep_noblanks(&to, "");
549 	switch (type) {
550 	case IT_GID:
551 		if (to_id == NULL) {
552 			make_parse_error(parse_error, to_type - start,
553 			    "No '=' and ID specification after type '%s'.",
554 			    to_type);
555 			goto einval;
556 		}
557 
558 		if (is.flags == 0) {
559 			/* No flags: Dealing with a primary group. */
560 			is.flags |= MDF_PRIMARY;
561 			gid_flags |= MDF_HAS_PRIMARY_CLAUSE;
562 		}
563 
564 		list = gid_list;
565 		nb = &rule->gids_nb;
566 		tflags = &rule->gid_flags;
567 
568 		/* "*" or "any"? */
569 		if (parse_any(to_id)) {
570 			/*
571 			 * We check that we have not seen any other clause of
572 			 * the same category (i.e., concerning primary or
573 			 * supplementary groups).
574 			 */
575 			if ((is.flags & MDF_PRIMARY) != 0) {
576 				if ((*tflags & MDF_HAS_PRIMARY_CLAUSE) != 0) {
577 					make_parse_error(parse_error,
578 					    to_id - start,
579 					    "'any' specified after another "
580 					    "(primary) GID.");
581 					goto einval;
582 				}
583 				*tflags |= gid_flags | MDF_ANY;
584 			} else {
585 				/*
586 				 * If a supplementary group flag was present, it
587 				 * must be MDF_SUPP_ALLOW ("+").
588 				 */
589 				if ((is.flags & MDF_SUPP_MASK) != MDF_SUPP_ALLOW) {
590 					make_parse_error(parse_error,
591 					    to_id - start,
592 					    "'any' specified with another "
593 					    "flag than '+'.");
594 					goto einval;
595 				}
596 				if ((*tflags & MDF_HAS_SUPP_CLAUSE) != 0) {
597 					make_parse_error(parse_error,
598 					    to_id - start,
599 					    "'any' with flag '+' specified after "
600 					    "another (supplementary) GID.");
601 					goto einval;
602 				}
603 				*tflags |= gid_flags | MDF_ANY_SUPP;
604 			}
605 			goto check_type_and_finish;
606 		} else {
607 			/*
608 			 * Check that we haven't already seen "any" for the same
609 			 * category.
610 			 */
611 			if ((is.flags & MDF_PRIMARY) != 0) {
612 				if ((*tflags & MDF_ANY) != 0) {
613 					make_parse_error(parse_error,
614 					    to_id - start,
615 					    "Some (primary) GID specified after "
616 					    "'any'.");
617 					goto einval;
618 				}
619 			} else if ((*tflags & MDF_ANY_SUPP) != 0 &&
620 			    (is.flags & MDF_SUPP_ALLOW) != 0) {
621 				make_parse_error(parse_error,
622 				    to_id - start,
623 				    "Some (supplementary) GID specified after "
624 				    "'any' with flag '+'.");
625 				goto einval;
626 			}
627 			*tflags |= gid_flags;
628 		}
629 		break;
630 
631 	case IT_UID:
632 		if (to_id == NULL) {
633 			make_parse_error(parse_error, to_type - start,
634 			    "No '=' and ID specification after type '%s'.",
635 			    to_type);
636 			goto einval;
637 		}
638 
639 		list = uid_list;
640 		nb = &rule->uids_nb;
641 		tflags = &rule->uid_flags;
642 
643 		/* "*" or "any"? */
644 		if (parse_any(to_id)) {
645 			/* There must not be any other clause. */
646 			if (has_clauses(*nb, *tflags)) {
647 				make_parse_error(parse_error, to_id - start,
648 				    "'any' specified after another UID.");
649 				goto einval;
650 			}
651 			*tflags |= MDF_ANY;
652 			goto check_type_and_finish;
653 		} else {
654 			/*
655 			 * Check that we haven't already seen "any" for the same
656 			 * category.
657 			 */
658 			if ((*tflags & MDF_ANY) != 0) {
659 				make_parse_error(parse_error, to_id - start,
660 				    "Some UID specified after 'any'.");
661 				goto einval;
662 			}
663 		}
664 		break;
665 
666 	case IT_ANY:
667 		/* No ID allowed. */
668 		if (to_id != NULL) {
669 			make_parse_error(parse_error, to_type - start,
670 			    "No '=' and ID allowed after type '%s'.", to_type);
671 			goto einval;
672 		}
673 		/*
674 		 * We can't have IT_ANY after any other IT_*, it must be the
675 		 * only one.
676 		 */
677 		if (has_clauses(rule->uids_nb, rule->uid_flags) ||
678 		    has_clauses(rule->gids_nb, rule->gid_flags)) {
679 			make_parse_error(parse_error, to_type - start,
680 			    "Target clause of type '%s' coming after another "
681 			    "clause (must be alone).", to_type);
682 			goto einval;
683 		}
684 		rule->uid_flags |= MDF_ANY;
685 		rule->gid_flags |= MDF_ANY | MDF_ANY_SUPP |
686 		    MDF_HAS_PRIMARY_CLAUSE | MDF_HAS_SUPP_CLAUSE;
687 		goto finish;
688 
689 	default:
690 		/* parse_id_type() returns no other types currently. */
691 		__assert_unreachable();
692 	}
693 
694 	/* Rule out cases that have been treated above. */
695 	MPASS((type == IT_UID || type == IT_GID) && !parse_any(to_id));
696 
697 	/* "."? */
698 	if (strcmp(to_id, ".") == 0) {
699 		if ((*tflags & MDF_CURRENT) != 0) {
700 			/* Duplicate "." <id>.  Try to coalesce. */
701 			error = coalesce_id_flags(is.flags, tflags);
702 			if (error != 0) {
703 				make_parse_error(parse_error, to_id - start,
704 				    "Incompatible flags with prior clause "
705 				    "with same target.");
706 				goto einval;
707 			}
708 		} else
709 			*tflags |= MDF_CURRENT | is.flags;
710 		goto check_type_and_finish;
711 	}
712 
713 	/* Parse an ID. */
714 	error = strtoui_strict(to_id, &p, 10, &is.id);
715 	if (error != 0 || *p != '\0') {
716 		make_parse_error(parse_error, to_id - start,
717 		    "Cannot parse a numerical ID (base 10).");
718 		goto einval;
719 	}
720 
721 	/* Explicit ID flags. */
722 	if (type == IT_GID && (is.flags & MDF_SUPP_MUST) != 0)
723 		*tflags |= MDF_EXPLICIT_SUPP_MUST;
724 
725 	/*
726 	 * We check for duplicate IDs and coalesce their 'struct id_spec' only
727 	 * at end of parse_single_rule() because it is much more performant then
728 	 * (using sorted arrays).
729 	 */
730 	++*nb;
731 	if (*nb == 0) {
732 		make_parse_error(parse_error, 0,
733 		    "Too many target clauses of type '%s'.", to_type);
734 		return (EOVERFLOW);
735 	}
736 	ie = malloc(sizeof(*ie), M_DO, M_WAITOK);
737 	ie->spec = is;
738 	STAILQ_INSERT_TAIL(list, ie, ie_entries);
739 	check_type_and_id_spec(type, &is);
740 check_type_and_finish:
741 	check_type_and_type_flags(type, *tflags);
742 finish:
743 	return (0);
744 einval:
745 	/* We must have built a parse error on error. */
746 	MPASS(*parse_error != NULL);
747 	return (EINVAL);
748 }
749 
750 static int
u_int_cmp(const u_int i1,const u_int i2)751 u_int_cmp(const u_int i1, const u_int i2)
752 {
753 	return ((i1 > i2) - (i1 < i2));
754 }
755 
756 static int
id_spec_cmp(const void * const p1,const void * const p2)757 id_spec_cmp(const void *const p1, const void *const p2)
758 {
759 	const struct id_spec *const is1 = p1;
760 	const struct id_spec *const is2 = p2;
761 
762 	return (u_int_cmp(is1->id, is2->id));
763 }
764 
765 /*
766  * Transfer content of 'list' into 'array', freeing and emptying list.
767  *
768  * 'nb' must be 'list''s length and not be greater than 'array''s size.  The
769  * destination array is sorted by ID.  Structures 'struct id_spec' with same IDs
770  * are coalesced if that makes sense (not including duplicate clauses), else
771  * EINVAL is returned.  On success, 'nb' is updated (lowered) to account for
772  * coalesced specifications.  The parameter 'type' is only for testing purposes
773  * (INVARIANTS).
774  */
775 static int
pour_list_into_rule(const id_type_t type,struct id_list * const list,struct id_spec * const array,id_nb_t * const nb,struct parse_error ** const parse_error)776 pour_list_into_rule(const id_type_t type, struct id_list *const list,
777     struct id_spec *const array, id_nb_t *const nb,
778     struct parse_error **const parse_error)
779 {
780 	struct id_elem *ie, *ie_next;
781 	size_t idx = 0;
782 
783 	/* Fill the array. */
784 	STAILQ_FOREACH_SAFE(ie, list, ie_entries, ie_next) {
785 		MPASS(idx < *nb);
786 		array[idx] = ie->spec;
787 		free(ie, M_DO);
788 		++idx;
789 	}
790 	MPASS(idx == *nb);
791 	STAILQ_INIT(list);
792 
793 	/* Sort it (by ID). */
794 	qsort(array, *nb, sizeof(*array), id_spec_cmp);
795 
796 	/* Coalesce same IDs. */
797 	if (*nb != 0) {
798 		size_t ref_idx = 0;
799 
800 		for (idx = 1; idx < *nb; ++idx) {
801 			const u_int id = array[idx].id;
802 
803 			if (id != array[ref_idx].id) {
804 				++ref_idx;
805 				if (ref_idx != idx)
806 					array[ref_idx] = array[idx];
807 				continue;
808 			}
809 
810 			switch (type) {
811 				int error;
812 
813 			case IT_GID:
814 				error = coalesce_id_flags(array[idx].flags,
815 				    &array[ref_idx].flags);
816 				if (error != 0) {
817 					make_parse_error(parse_error, 0,
818 					    "Incompatible flags or duplicate "
819 					    "GID %u.", id);
820 					return (EINVAL);
821 				}
822 				check_type_and_id_flags(type,
823 				    array[ref_idx].flags);
824 				break;
825 
826 			case IT_UID:
827 				/*
828 				 * No flags in this case.  Multiple appearances
829 				 * of the same UID is an exact redundancy, so
830 				 * error out.
831 				 */
832 				make_parse_error(parse_error, 0,
833 				    "Duplicate UID %u.", id);
834 				return (EINVAL);
835 
836 			default:
837 				__assert_unreachable();
838 			}
839 		}
840 		*nb = ref_idx + 1;
841 	}
842 
843 	return (0);
844 }
845 
846 /*
847  * See also the herald comment for parse_rules() below.
848  *
849  * The second part of a rule, called <target> (or <to>), is a comma-separated
850  * (',') list of '<flags><type>=<id>' clauses similar to that of the <from>
851  * part, with the extensions that <id> may also be "*" or "any" or ".", and that
852  * <flags> may contain at most one of the '+', '-' and '!' characters when
853  * <type> is "gid" (no flags are allowed for "uid").  No two clauses in a single
854  * <to> list may list the same <id>.  "*" and "any" both designate any ID for
855  * the <type>, and are aliases to each other.  In front of "any" (or "*"), only
856  * the '+' flag is allowed (in the "gid" case).  "." designates the process'
857  * current IDs for the <type>.  The precise meaning of flags and "." is
858  * explained in functions checking privileges below.
859  */
860 static int
parse_single_rule(char * rule,struct rules * const rules,struct parse_error ** const parse_error)861 parse_single_rule(char *rule, struct rules *const rules,
862     struct parse_error **const parse_error)
863 {
864 	const char *const start = rule;
865 	const char *from_type, *from_id, *p;
866 	char *to_list;
867 	struct id_list uid_list, gid_list;
868 	struct id_elem *ie, *ie_next;
869 	struct rule *new;
870 	int error;
871 
872 	MPASS(*parse_error == NULL);
873 	STAILQ_INIT(&uid_list);
874 	STAILQ_INIT(&gid_list);
875 
876 	/* Freed when the 'struct rules' container is freed. */
877 	new = malloc(sizeof(*new), M_DO, M_WAITOK | M_ZERO);
878 
879 	from_type = strsep_noblanks(&rule, "=");
880 	MPASS(from_type != NULL); /* Because 'rule' was not NULL. */
881 	error = parse_id_type(from_type, &new->from_type, parse_error);
882 	if (error != 0)
883 		goto einval;
884 	switch (new->from_type) {
885 	case IT_UID:
886 	case IT_GID:
887 		break;
888 	default:
889 		make_parse_error(parse_error, 0, "Type '%s' not allowed in "
890 		    "the \"from\" part of rules.");
891 		goto einval;
892 	}
893 
894 	from_id = strsep_noblanks(&rule, ":>");
895 	if (is_null_or_empty(from_id)) {
896 		make_parse_error(parse_error, 0, "No ID specified.");
897 		goto einval;
898 	}
899 
900 	error = strtoui_strict(from_id, &p, 10, &new->from_id);
901 	if (error != 0 || *p != '\0') {
902 		make_parse_error(parse_error, from_id - start,
903 		    "Cannot parse a numerical ID (base 10).");
904 		goto einval;
905 	}
906 
907 	/*
908 	 * We will now parse the "to" list.
909 	 *
910 	 * In order to ease parsing, we will begin by building lists of target
911 	 * UIDs and GIDs in local variables 'uid_list' and 'gid_list'.  The
912 	 * number of each type of IDs will be filled directly in 'new'.  At end
913 	 * of parse, we will allocate both arrays of IDs to be placed into the
914 	 * 'uids' and 'gids' members, sort them, and discard the tail queues
915 	 * used to build them.  This conversion to sorted arrays at end of parse
916 	 * allows to minimize memory allocations and enables searching IDs in
917 	 * O(log(n)) instead of linearly.
918 	 */
919 	to_list = strsep_noblanks(&rule, ",");
920 	if (to_list == NULL) {
921 		make_parse_error(parse_error, 0, "No target list.");
922 		goto einval;
923 	}
924 	do {
925 		error = parse_target_clause(to_list, new, &uid_list, &gid_list,
926 		    parse_error);
927 		if (error != 0) {
928 			(*parse_error)->pos += to_list - start;
929 			goto einval;
930 		}
931 
932 		to_list = strsep_noblanks(&rule, ",");
933 	} while (to_list != NULL);
934 
935 	if (new->uids_nb != 0) {
936 		new->uids = malloc(sizeof(*new->uids) * new->uids_nb, M_DO,
937 		    M_WAITOK);
938 		error = pour_list_into_rule(IT_UID, &uid_list, new->uids,
939 		    &new->uids_nb, parse_error);
940 		if (error != 0)
941 			goto einval;
942 	}
943 	MPASS(STAILQ_EMPTY(&uid_list));
944 	if (!has_clauses(new->uids_nb, new->uid_flags)) {
945 		/* No UID specified, default is "uid=.". */
946 		MPASS(new->uid_flags == 0);
947 		new->uid_flags = MDF_CURRENT;
948 		check_type_and_type_flags(IT_UID, new->uid_flags);
949 	}
950 
951 	if (new->gids_nb != 0) {
952 		new->gids = malloc(sizeof(*new->gids) * new->gids_nb, M_DO,
953 		    M_WAITOK);
954 		error = pour_list_into_rule(IT_GID, &gid_list, new->gids,
955 		    &new->gids_nb, parse_error);
956 		if (error != 0)
957 			goto einval;
958 	}
959 	MPASS(STAILQ_EMPTY(&gid_list));
960 	if (!has_clauses(new->gids_nb, new->gid_flags)) {
961 		/* No GID specified, default is "gid=.,!gid=.". */
962 		MPASS(new->gid_flags == 0);
963 		new->gid_flags = MDF_CURRENT | MDF_PRIMARY | MDF_SUPP_MUST |
964 		    MDF_HAS_PRIMARY_CLAUSE | MDF_HAS_SUPP_CLAUSE;
965 		check_type_and_type_flags(IT_GID, new->gid_flags);
966 	}
967 
968 	STAILQ_INSERT_TAIL(&rules->head, new, r_entries);
969 	return (0);
970 
971 einval:
972 	free(new->gids, M_DO);
973 	free(new->uids, M_DO);
974 	free(new, M_DO);
975 	STAILQ_FOREACH_SAFE(ie, &gid_list, ie_entries, ie_next)
976 	    free(ie, M_DO);
977 	STAILQ_FOREACH_SAFE(ie, &uid_list, ie_entries, ie_next)
978 	    free(ie, M_DO);
979 	MPASS(*parse_error != NULL);
980 	return (EINVAL);
981 }
982 
983 /*
984  * Parse rules specification and produce rule structures out of it.
985  *
986  * Returns 0 on success, with '*rulesp' made to point to a 'struct rule'
987  * representing the rules.  On error, the returned value is non-zero and
988  * '*rulesp' is unchanged.  If 'string' has length greater or equal to
989  * MAC_RULE_STRING_LEN, ENAMETOOLONG is returned.  If it is not in the expected
990  * format, EINVAL is returned.  If an error is returned, '*parse_error' is set
991  * to point to a 'struct parse_error' giving an error message for the problem,
992  * else '*parse_error' is set to NULL.
993  *
994  * Expected format: A >-colon-separated list of rules of the form
995  * "<from>><target>" (for backwards compatibility, a semi-colon ":" is accepted
996  * in place of '>').  The <from> part is of the form "<type>=<id>" where <type>
997  * is "uid" or "gid", <id> an UID or GID (depending on <type>) and <target> is
998  * "*", "any" or a comma-separated list of '<flags><type>=<id>' clauses (see the
999  * comment for parse_single_rule() for more details).  For convenience, empty
1000  * rules are allowed (and do nothing), and spaces and tabs are allowed (and
1001  * removed) around each token (tokens are natural ones, except that
1002  * '<flags><type>' as a whole is considered a single token, so no blanks are
1003  * allowed between '<flags>' and '<type>').
1004  *
1005  * Examples:
1006  * - "uid=1001>uid=1010,gid=1010;uid=1002>any"
1007  * - "gid=1010>gid=1011,gid=1012,gid=1013"
1008  */
1009 static int
parse_rules(const char * const string,struct rules ** const rulesp,struct parse_error ** const parse_error)1010 parse_rules(const char *const string, struct rules **const rulesp,
1011     struct parse_error **const parse_error)
1012 {
1013 	const size_t len = strlen(string);
1014 	char *copy, *p, *rule;
1015 	struct rules *rules;
1016 	int error = 0;
1017 
1018 	*parse_error = NULL;
1019 
1020 	if (len >= MAC_RULE_STRING_LEN) {
1021 		make_parse_error(parse_error, 0,
1022 		    "Rule specification string is too long (%zu, max %zu)",
1023 		    len, MAC_RULE_STRING_LEN - 1);
1024 		return (ENAMETOOLONG);
1025 	}
1026 
1027 	rules = alloc_rules();
1028 	bcopy(string, rules->string, len + 1);
1029 	MPASS(rules->string[len] == '\0'); /* Catch some races. */
1030 
1031 	copy = malloc(len + 1, M_DO, M_WAITOK);
1032 	bcopy(string, copy, len + 1);
1033 	MPASS(copy[len] == '\0'); /* Catch some races. */
1034 
1035 	p = copy;
1036 	while ((rule = strsep_noblanks(&p, ";")) != NULL) {
1037 		if (rule[0] == '\0')
1038 			continue;
1039 		error = parse_single_rule(rule, rules, parse_error);
1040 		if (error != 0) {
1041 			(*parse_error)->pos += rule - copy;
1042 			toast_rules(rules);
1043 			goto out;
1044 		}
1045 	}
1046 
1047 	*rulesp = rules;
1048 out:
1049 	free(copy, M_DO);
1050 	return (error);
1051 }
1052 
1053 /*
1054  * Find rules applicable to the passed prison.
1055  *
1056  * Returns the applicable rules (and never NULL).  'pr' must be unlocked.
1057  * 'aprp' is set to the (ancestor) prison holding these, and it must be unlocked
1058  * once the caller is done accessing the rules.  '*aprp' is equal to 'pr' if and
1059  * only if the current jail has its own set of rules.
1060  */
1061 static struct rules *
find_rules(struct prison * const pr,struct prison ** const aprp)1062 find_rules(struct prison *const pr, struct prison **const aprp)
1063 {
1064 	struct prison *cpr, *ppr;
1065 	struct rules *rules;
1066 
1067 	cpr = pr;
1068 	for (;;) {
1069 		prison_lock(cpr);
1070 		rules = osd_jail_get(cpr, osd_jail_slot);
1071 		if (rules != NULL)
1072 			break;
1073 		prison_unlock(cpr);
1074 
1075 		ppr = cpr->pr_parent;
1076 		MPASS(ppr != NULL); /* prison0 always has rules. */
1077 		cpr = ppr;
1078 	}
1079 
1080 	*aprp = cpr;
1081 	return (rules);
1082 }
1083 
1084 static void
hold_rules(struct rules * const rules)1085 hold_rules(struct rules *const rules)
1086 {
1087 	refcount_acquire(&rules->use_count);
1088 }
1089 
1090 static void
drop_rules(struct rules * const rules)1091 drop_rules(struct rules *const rules)
1092 {
1093 	if (refcount_release(&rules->use_count))
1094 		toast_rules(rules);
1095 }
1096 
1097 #ifdef INVARIANTS
1098 static void
check_rules_use_count(const struct rules * const rules,u_int expected)1099 check_rules_use_count(const struct rules *const rules, u_int expected)
1100 {
1101 	const u_int use_count = refcount_load(&rules->use_count);
1102 
1103 	if (use_count != expected)
1104 		panic("MAC/do: Rules at %p: Use count is %u, expected %u",
1105 		    rules, use_count, expected);
1106 }
1107 #else
1108 #define check_rules_use_count(...)
1109 #endif /* INVARIANTS */
1110 
1111 /*
1112  * OSD destructor for slot 'osd_jail_slot'.
1113  *
1114  * Called with 'value' not NULL.  We have arranged that it is only ever called
1115  * when the corresponding jail goes down or at module unload.
1116  */
1117 static void
dealloc_jail_osd(void * const value)1118 dealloc_jail_osd(void *const value)
1119 {
1120 	struct rules *const rules = value;
1121 
1122 	/*
1123 	 * If called because the "holding" jail goes down, no one should be
1124 	 * using the rules but us at this point because no threads of that jail
1125 	 * (or its sub-jails) should currently be executing (in particular,
1126 	 * currently executing setcred()).  The case of module unload is more
1127 	 * complex.  Although the MAC framework takes care that no hook is
1128 	 * called while a module is unloading, the unload could happen between
1129 	 * two calls to MAC hooks in the course of, e.g., executing setcred(),
1130 	 * where the rules' reference count has been bumped to keep them alive
1131 	 * even if the rules on the "holding" jail has been concurrently
1132 	 * changed.  These other references are held in our thread OSD slot, so
1133 	 * we ensure that all thread's slots are freed first in mac_do_destroy()
1134 	 * to be able to check that only one reference remains.
1135 	 */
1136 	check_rules_use_count(rules, 1);
1137 	toast_rules(rules);
1138 }
1139 
1140 /*
1141  * Remove the rules specifically associated to a prison.
1142  *
1143  * In practice, this means that the rules become inherited (from the closest
1144  * ascendant that has some).
1145  *
1146  * Destroys the 'osd_jail_slot' slot of the passed jail.
1147  */
1148 static void
remove_rules(struct prison * const pr)1149 remove_rules(struct prison *const pr)
1150 {
1151 	struct rules *old_rules;
1152 	int error __unused;
1153 
1154 	prison_lock(pr);
1155 	/*
1156 	 * We go to the burden of extracting rules first instead of just letting
1157 	 * osd_jail_del() calling dealloc_jail_osd() as we want to decrement
1158 	 * their use count, and possibly free them, outside of the prison lock.
1159 	 */
1160 	old_rules = osd_jail_get(pr, osd_jail_slot);
1161 	error = osd_jail_set(pr, osd_jail_slot, NULL);
1162 	/* osd_set() never fails nor allocate memory when 'value' is NULL. */
1163 	MPASS(error == 0);
1164 	/*
1165 	 * This completely frees the OSD slot, but doesn't call the destructor
1166 	 * since we've just put NULL in the slot.
1167 	 */
1168 	osd_jail_del(pr, osd_jail_slot);
1169 	prison_unlock(pr);
1170 
1171 	if (old_rules != NULL)
1172 		drop_rules(old_rules);
1173 }
1174 
1175 /*
1176  * Assign already built rules to a jail.
1177  */
1178 static void
set_rules(struct prison * const pr,struct rules * const rules)1179 set_rules(struct prison *const pr, struct rules *const rules)
1180 {
1181 	struct rules *old_rules;
1182 	void **rsv;
1183 
1184 	check_rules_use_count(rules, 0);
1185 	hold_rules(rules);
1186 	rsv = osd_reserve(osd_jail_slot);
1187 
1188 	prison_lock(pr);
1189 	old_rules = osd_jail_get(pr, osd_jail_slot);
1190 	osd_jail_set_reserved(pr, osd_jail_slot, rsv, rules);
1191 	prison_unlock(pr);
1192 	if (old_rules != NULL)
1193 		drop_rules(old_rules);
1194 }
1195 
1196 /*
1197  * Assigns empty rules to a jail.
1198  */
1199 static void
set_empty_rules(struct prison * const pr)1200 set_empty_rules(struct prison *const pr)
1201 {
1202 	struct rules *const rules = alloc_rules();
1203 
1204 	set_rules(pr, rules);
1205 }
1206 
1207 /*
1208  * Parse a rules specification and assign them to a jail.
1209  *
1210  * Returns the same error code as parse_rules() (which see).
1211  */
1212 static int
parse_and_set_rules(struct prison * const pr,const char * rules_string,struct parse_error ** const parse_error)1213 parse_and_set_rules(struct prison *const pr, const char *rules_string,
1214     struct parse_error **const parse_error)
1215 {
1216 	struct rules *rules;
1217 	int error;
1218 
1219 	error = parse_rules(rules_string, &rules, parse_error);
1220 	if (error != 0)
1221 		return (error);
1222 	set_rules(pr, rules);
1223 	return (0);
1224 }
1225 
1226 static int
mac_do_sysctl_rules(SYSCTL_HANDLER_ARGS)1227 mac_do_sysctl_rules(SYSCTL_HANDLER_ARGS)
1228 {
1229 	char *const buf = malloc(MAC_RULE_STRING_LEN, M_DO, M_WAITOK);
1230 	struct prison *const td_pr = req->td->td_ucred->cr_prison;
1231 	struct prison *pr;
1232 	struct rules *rules;
1233 	struct parse_error *parse_error;
1234 	int error;
1235 
1236 	rules = find_rules(td_pr, &pr);
1237 	strlcpy(buf, rules->string, MAC_RULE_STRING_LEN);
1238 	prison_unlock(pr);
1239 
1240 	error = sysctl_handle_string(oidp, buf, MAC_RULE_STRING_LEN, req);
1241 	if (error != 0 || req->newptr == NULL)
1242 		goto out;
1243 
1244 	/* Set our prison's rules, not that of the jail we inherited from. */
1245 	error = parse_and_set_rules(td_pr, buf, &parse_error);
1246 	if (error != 0) {
1247 		if (print_parse_error)
1248 			printf("MAC/do: Parse error at index %zu: %s\n",
1249 			    parse_error->pos, parse_error->msg);
1250 		free_parse_error(parse_error);
1251 	}
1252 out:
1253 	free(buf, M_DO);
1254 	return (error);
1255 }
1256 
1257 SYSCTL_PROC(_security_mac_do, OID_AUTO, rules,
1258     CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_PRISON|CTLFLAG_MPSAFE,
1259     0, 0, mac_do_sysctl_rules, "A",
1260     "Rules");
1261 
1262 
1263 SYSCTL_JAIL_PARAM_SYS_SUBNODE(mac, do, CTLFLAG_RW, "Jail MAC/do parameters");
1264 SYSCTL_JAIL_PARAM_STRING(_mac_do, rules, CTLFLAG_RW, MAC_RULE_STRING_LEN,
1265     "Jail MAC/do rules");
1266 
1267 
1268 static int
mac_do_jail_create(void * obj,void * data __unused)1269 mac_do_jail_create(void *obj, void *data __unused)
1270 {
1271 	struct prison *const pr = obj;
1272 
1273 	set_empty_rules(pr);
1274 	return (0);
1275 }
1276 
1277 static int
mac_do_jail_get(void * obj,void * data)1278 mac_do_jail_get(void *obj, void *data)
1279 {
1280 	struct prison *ppr, *const pr = obj;
1281 	struct vfsoptlist *const opts = data;
1282 	struct rules *rules;
1283 	int jsys, error;
1284 
1285 	rules = find_rules(pr, &ppr);
1286 
1287 	jsys = pr == ppr ?
1288 	    (STAILQ_EMPTY(&rules->head) ? JAIL_SYS_DISABLE : JAIL_SYS_NEW) :
1289 	    JAIL_SYS_INHERIT;
1290 	error = vfs_setopt(opts, "mac.do", &jsys, sizeof(jsys));
1291 	if (error != 0 && error != ENOENT)
1292 		goto done;
1293 
1294 	error = vfs_setopts(opts, "mac.do.rules", rules->string);
1295 	if (error != 0 && error != ENOENT)
1296 		goto done;
1297 
1298 	error = 0;
1299 done:
1300 	prison_unlock(ppr);
1301 	return (error);
1302 }
1303 
1304 /*
1305  * -1 is used as a sentinel in mac_do_jail_check() and mac_do_jail_set() below.
1306  */
1307 _Static_assert(-1 != JAIL_SYS_DISABLE && -1 != JAIL_SYS_NEW &&
1308     -1 != JAIL_SYS_INHERIT,
1309     "mac_do(4) uses -1 as a sentinel for uninitialized 'jsys'.");
1310 
1311 /*
1312  * We perform only cheap checks here, i.e., we do not really parse the rules
1313  * specification string, if any.
1314  */
1315 static int
mac_do_jail_check(void * obj,void * data)1316 mac_do_jail_check(void *obj, void *data)
1317 {
1318 	struct vfsoptlist *opts = data;
1319 	char *rules_string;
1320 	int error, jsys, size;
1321 
1322 	error = vfs_copyopt(opts, "mac.do", &jsys, sizeof(jsys));
1323 	if (error == ENOENT)
1324 		jsys = -1;
1325 	else {
1326 		if (error != 0)
1327 			return (error);
1328 		if (jsys != JAIL_SYS_DISABLE && jsys != JAIL_SYS_NEW &&
1329 		    jsys != JAIL_SYS_INHERIT)
1330 			return (EINVAL);
1331 	}
1332 
1333 	/*
1334 	 * We use vfs_getopt() here instead of vfs_getopts() to get the length.
1335 	 * We perform the additional checks done by the latter here, even if
1336 	 * jail_set() calls vfs_getopts() itself later (they becoming
1337 	 * inconsistent wouldn't cause any security problem).
1338 	 */
1339 	error = vfs_getopt(opts, "mac.do.rules", (void**)&rules_string, &size);
1340 	if (error == ENOENT) {
1341 		/*
1342 		 * Default (in absence of "mac.do.rules") is to disable (and, in
1343 		 * particular, not inherit).
1344 		 */
1345 		if (jsys == -1)
1346 			jsys = JAIL_SYS_DISABLE;
1347 
1348 		if (jsys == JAIL_SYS_NEW) {
1349 			vfs_opterror(opts, "'mac.do.rules' must be specified "
1350 			    "given 'mac.do''s value");
1351 			return (EINVAL);
1352 		}
1353 
1354 		/* Absence of "mac.do.rules" at this point is OK. */
1355 		error = 0;
1356 	} else {
1357 		if (error != 0)
1358 			return (error);
1359 
1360 		/* Not a proper string. */
1361 		if (size == 0 || rules_string[size - 1] != '\0') {
1362 			vfs_opterror(opts, "'mac.do.rules' not a proper string");
1363 			return (EINVAL);
1364 		}
1365 
1366 		if (size > MAC_RULE_STRING_LEN) {
1367 			vfs_opterror(opts, "'mdo.rules' too long");
1368 			return (ENAMETOOLONG);
1369 		}
1370 
1371 		if (jsys == -1)
1372 			/* Default (if "mac.do.rules" is present). */
1373 			jsys = rules_string[0] == '\0' ? JAIL_SYS_DISABLE :
1374 			    JAIL_SYS_NEW;
1375 
1376 		/*
1377 		 * Be liberal and accept JAIL_SYS_DISABLE and JAIL_SYS_INHERIT
1378 		 * with an explicit empty rules specification.
1379 		 */
1380 		switch (jsys) {
1381 		case JAIL_SYS_DISABLE:
1382 		case JAIL_SYS_INHERIT:
1383 			if (rules_string[0] != '\0') {
1384 				vfs_opterror(opts, "'mac.do.rules' specified "
1385 				    "but should not given 'mac.do''s value");
1386 				return (EINVAL);
1387 			}
1388 			break;
1389 		}
1390 	}
1391 
1392 	return (error);
1393 }
1394 
1395 static int
mac_do_jail_set(void * obj,void * data)1396 mac_do_jail_set(void *obj, void *data)
1397 {
1398 	struct prison *pr = obj;
1399 	struct vfsoptlist *opts = data;
1400 	char *rules_string;
1401 	struct parse_error *parse_error;
1402 	int error, jsys;
1403 
1404 	/*
1405 	 * The invariants checks used below correspond to what has already been
1406 	 * checked in jail_check() above.
1407 	 */
1408 
1409 	error = vfs_copyopt(opts, "mac.do", &jsys, sizeof(jsys));
1410 	MPASS(error == 0 || error == ENOENT);
1411 	if (error != 0)
1412 		jsys = -1; /* Mark unfilled. */
1413 
1414 	rules_string = vfs_getopts(opts, "mac.do.rules", &error);
1415 	MPASS(error == 0 || error == ENOENT);
1416 	if (error == 0) {
1417 		MPASS(strlen(rules_string) < MAC_RULE_STRING_LEN);
1418 		if (jsys == -1)
1419 			/* Default (if "mac.do.rules" is present). */
1420 			jsys = rules_string[0] == '\0' ? JAIL_SYS_DISABLE :
1421 			    JAIL_SYS_NEW;
1422 		else
1423 			MPASS(jsys == JAIL_SYS_NEW ||
1424 			    ((jsys == JAIL_SYS_DISABLE ||
1425 			    jsys == JAIL_SYS_INHERIT) &&
1426 			    rules_string[0] == '\0'));
1427 	} else {
1428 		MPASS(jsys != JAIL_SYS_NEW);
1429 		if (jsys == -1)
1430 			/*
1431 			 * Default (in absence of "mac.do.rules") is to disable
1432 			 * (and, in particular, not inherit).
1433 			 */
1434 			jsys = JAIL_SYS_DISABLE;
1435 		/* If disabled, we'll store an empty rule specification. */
1436 		if (jsys == JAIL_SYS_DISABLE)
1437 			rules_string = "";
1438 	}
1439 
1440 	switch (jsys) {
1441 	case JAIL_SYS_INHERIT:
1442 		remove_rules(pr);
1443 		error = 0;
1444 		break;
1445 	case JAIL_SYS_DISABLE:
1446 	case JAIL_SYS_NEW:
1447 		error = parse_and_set_rules(pr, rules_string, &parse_error);
1448 		if (error != 0) {
1449 			vfs_opterror(opts,
1450 			    "MAC/do: Parse error at index %zu: %s\n",
1451 			    parse_error->pos, parse_error->msg);
1452 			free_parse_error(parse_error);
1453 		}
1454 		break;
1455 	default:
1456 		__assert_unreachable();
1457 	}
1458 	return (error);
1459 }
1460 
1461 /*
1462  * OSD jail methods.
1463  *
1464  * There is no PR_METHOD_REMOVE, as OSD storage is destroyed by the common jail
1465  * code (see prison_cleanup()), which triggers a run of our dealloc_jail_osd()
1466  * destructor.
1467  */
1468 static const osd_method_t osd_methods[PR_MAXMETHOD] = {
1469 	[PR_METHOD_CREATE] = mac_do_jail_create,
1470 	[PR_METHOD_GET] = mac_do_jail_get,
1471 	[PR_METHOD_CHECK] = mac_do_jail_check,
1472 	[PR_METHOD_SET] = mac_do_jail_set,
1473 };
1474 
1475 
1476 /*
1477  * Common header structure.
1478  *
1479  * Each structure that is used to pass information between some MAC check
1480  * function and priv_grant() must start with this header.
1481  */
1482 struct mac_do_data_header {
1483 	/* Size of the allocated buffer holding the containing structure. */
1484 	size_t		 allocated_size;
1485 	/* Full size of the containing structure. */
1486 	size_t		 size;
1487 	/*
1488 	 * For convenience, we use privilege numbers as an identifier for the
1489 	 * containing structure's type, since there is one distinct privilege
1490 	 * for each privilege changing function we are supporting.  0 in 'priv'
1491 	 * indicates this header is uninitialized.
1492 	 */
1493 	int		 priv;
1494 	/* Rules to apply. */
1495 	struct rules	*rules;
1496 };
1497 
1498 /*
1499  * The case of unusable or absent per-thread data can actually happen as nothing
1500  * prevents, e.g., priv_check*() with privilege 'priv' to be called standalone,
1501  * as it is currently by, e.g., the Linux emulator for PRIV_CRED_SETUID.  We
1502  * interpret such calls to priv_check*() as full, unrestricted requests for
1503  * 'priv', contrary to what we're doing here for selected operations, and
1504  * consequently will not grant the requested privilege.
1505  *
1506  * Also, we protect ourselves from a concurrent change of 'do_enabled' while
1507  * a call to setcred() is in progress by storing the rules per-thread
1508  * which is then consulted by each successive hook so that they all have
1509  * a coherent view of the specifications, and we empty the slot (actually, mark
1510  * it as empty) when MAC/do is disabled.
1511  */
1512 static int
check_data_usable(const void * const data,const size_t size,const int priv)1513 check_data_usable(const void *const data, const size_t size, const int priv)
1514 {
1515 	const struct mac_do_data_header *const hdr = data;
1516 
1517 	if (hdr == NULL || hdr->priv == 0)
1518 		return (ENOENT);
1519 	/*
1520 	 * Impacting changes in the protocols we are based on...  Don't crash in
1521 	 * production.
1522 	 */
1523 	if (hdr->priv != priv) {
1524 		MPASS(hdr->priv == priv);
1525 		return (EBUSY);
1526 	}
1527 	MPASS(hdr->size == size);
1528 	MPASS(hdr->size <= hdr->allocated_size);
1529 	return (0);
1530 }
1531 
1532 static void
clear_data(void * const data)1533 clear_data(void *const data)
1534 {
1535 	struct mac_do_data_header *const hdr = data;
1536 
1537 	if (hdr != NULL) {
1538 		drop_rules(hdr->rules);
1539 		/* We don't deallocate so as to save time on next access. */
1540 		hdr->priv = 0;
1541 	}
1542 }
1543 
1544 static void *
fetch_data(void)1545 fetch_data(void)
1546 {
1547 	return (osd_thread_get_unlocked(curthread, osd_thread_slot));
1548 }
1549 
1550 static bool
is_data_reusable(const void * const data,const size_t size)1551 is_data_reusable(const void *const data, const size_t size)
1552 {
1553 	const struct mac_do_data_header *const hdr = data;
1554 
1555 	return (hdr != NULL && size <= hdr->allocated_size);
1556 }
1557 
1558 static void
set_data_header(void * const data,const size_t size,const int priv,struct rules * const rules)1559 set_data_header(void *const data, const size_t size, const int priv,
1560     struct rules *const rules)
1561 {
1562 	struct mac_do_data_header *const hdr = data;
1563 
1564 	MPASS(hdr->priv == 0);
1565 	MPASS(priv != 0);
1566 	MPASS(size <= hdr->allocated_size);
1567 	hdr->size = size;
1568 	hdr->priv = priv;
1569 	hdr->rules = rules;
1570 }
1571 
1572 /* The proc lock (and any other non-sleepable lock) must not be held. */
1573 static void *
alloc_data(void * const data,const size_t size)1574 alloc_data(void *const data, const size_t size)
1575 {
1576 	struct mac_do_data_header *const hdr = realloc(data, size, M_DO,
1577 	    M_WAITOK);
1578 
1579 	MPASS(size >= sizeof(struct mac_do_data_header));
1580 	hdr->allocated_size = size;
1581 	hdr->priv = 0;
1582 	if (hdr != data) {
1583 		/*
1584 		 * This call either reuses the existing memory allocated for the
1585 		 * slot or tries to allocate some without blocking.
1586 		 */
1587 		int error = osd_thread_set(curthread, osd_thread_slot, hdr);
1588 
1589 		if (error != 0) {
1590 			/* Going to make a M_WAITOK allocation. */
1591 			void **const rsv = osd_reserve(osd_thread_slot);
1592 
1593 			error = osd_thread_set_reserved(curthread,
1594 			    osd_thread_slot, rsv, hdr);
1595 			MPASS(error == 0);
1596 		}
1597 	}
1598 	return (hdr);
1599 }
1600 
1601 /* Destructor for 'osd_thread_slot'. */
1602 static void
dealloc_thread_osd(void * const value)1603 dealloc_thread_osd(void *const value)
1604 {
1605 	free(value, M_DO);
1606 }
1607 
1608 /*
1609  * Whether to grant access to some primary group according to flags.
1610  *
1611  * The passed 'flags' must be those of a rule's matching GID, or the IT_GID type
1612  * flags when MDF_CURRENT has been matched.
1613  *
1614  * Return values:
1615  * - 0:			Access granted.
1616  * - EJUSTRETURN:	Flags are agnostic.
1617  */
1618 static int
grant_primary_group_from_flags(const flags_t flags)1619 grant_primary_group_from_flags(const flags_t flags)
1620 {
1621 	return ((flags & MDF_PRIMARY) != 0 ? 0 : EJUSTRETURN);
1622 }
1623 
1624 /*
1625  * Same as grant_primary_group_from_flags(), but for supplementary groups.
1626  *
1627  * Return values:
1628  * - 0:			Access granted.
1629  * - EJUSTRETURN:	Flags are agnostic.
1630  * - EPERM:		Access denied.
1631  */
1632 static int __unused
grant_supplementary_group_from_flags(const flags_t flags)1633 grant_supplementary_group_from_flags(const flags_t flags)
1634 {
1635 	if ((flags & MDF_SUPP_MASK) != 0)
1636 		return ((flags & MDF_SUPP_DONT) != 0 ? EPERM : 0);
1637 
1638 	return (EJUSTRETURN);
1639 }
1640 
1641 static int
rule_grant_supplementary_groups(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1642 rule_grant_supplementary_groups(const struct rule *const rule,
1643     const struct ucred *const old_cred, const struct ucred *const new_cred)
1644 {
1645 	const gid_t *const old_groups = old_cred->cr_groups;
1646 	const gid_t *const new_groups = new_cred->cr_groups;
1647 	const int old_ngroups = old_cred->cr_ngroups;
1648 	const int new_ngroups = new_cred->cr_ngroups;
1649 	const flags_t gid_flags = rule->gid_flags;
1650 	const bool current_has_supp = (gid_flags & MDF_CURRENT) != 0 &&
1651 	    (gid_flags & MDF_SUPP_MASK) != 0;
1652 	id_nb_t rule_idx = 0;
1653 	int old_idx = 1, new_idx = 1;
1654 
1655 	if ((gid_flags & MDF_ANY_SUPP) != 0 &&
1656 	    (gid_flags & MDF_MAY_REJ_SUPP) == 0)
1657 		/*
1658 		 * Any set of supplementary groups is accepted, no need to loop
1659 		 * over them.
1660 		 */
1661 		return (0);
1662 
1663 	for (; new_idx < new_ngroups; ++new_idx) {
1664 		const gid_t gid = new_groups[new_idx];
1665 		bool may_accept = false;
1666 
1667 		if ((gid_flags & MDF_ANY_SUPP) != 0)
1668 			may_accept = true;
1669 
1670 		/* Do we have to check for the current supplementary groups? */
1671 		if (current_has_supp) {
1672 			/*
1673 			 * Linear search, as both supplementary groups arrays
1674 			 * are sorted.  Advancing 'old_idx' with a binary search
1675 			 * on absence of MDF_SUPP_MUST doesn't seem worth it in
1676 			 * practice.
1677 			 */
1678 			for (; old_idx < old_ngroups; ++old_idx) {
1679 				const gid_t old_gid = old_groups[old_idx];
1680 
1681 				if (old_gid < gid) {
1682 					/* Mandatory but absent. */
1683 					if ((gid_flags & MDF_SUPP_MUST) != 0)
1684 						return (EPERM);
1685 				} else if (old_gid == gid) {
1686 					switch (gid_flags & MDF_SUPP_MASK) {
1687 					case MDF_SUPP_DONT:
1688 						/* Present but forbidden. */
1689 						return (EPERM);
1690 					case MDF_SUPP_ALLOW:
1691 					case MDF_SUPP_MUST:
1692 						may_accept = true;
1693 						break;
1694 					default:
1695 #ifdef INVARIANTS
1696 						__assert_unreachable();
1697 #else
1698 						/* Better be safe than sorry. */
1699 						return (EPERM);
1700 #endif
1701 					}
1702 					++old_idx;
1703 					break;
1704 				}
1705 				else
1706 					break;
1707 			}
1708 		}
1709 
1710 		/*
1711 		 * Search by GID for a corresponding 'struct id_spec'.
1712 		 *
1713 		 * Again, linear search, with same note on not using binary
1714 		 * search optimization as above (the trigger would be absence of
1715 		 * MDF_EXPLICIT_SUPP_MUST this time).
1716 		 */
1717 		for (; rule_idx < rule->gids_nb; ++rule_idx) {
1718 			const struct id_spec is = rule->gids[rule_idx];
1719 
1720 			if (is.id < gid) {
1721 				/* Mandatory but absent. */
1722 				if ((is.flags & MDF_SUPP_MUST) != 0)
1723 					return (EPERM);
1724 			} else if (is.id == gid) {
1725 				switch (is.flags & MDF_SUPP_MASK) {
1726 				case MDF_SUPP_DONT:
1727 					/* Present but forbidden. */
1728 					return (EPERM);
1729 				case MDF_SUPP_ALLOW:
1730 				case MDF_SUPP_MUST:
1731 					may_accept = true;
1732 					break;
1733 				case 0:
1734 					/* Primary group only. */
1735 					break;
1736 				default:
1737 #ifdef INVARIANTS
1738 					__assert_unreachable();
1739 #else
1740 					/* Better be safe than sorry. */
1741 					return (EPERM);
1742 #endif
1743 				}
1744 				++rule_idx;
1745 				break;
1746 			}
1747 			else
1748 				break;
1749 		}
1750 
1751 		/* 'gid' wasn't explicitly accepted. */
1752 		if (!may_accept)
1753 			return (EPERM);
1754 	}
1755 
1756 	/*
1757 	 * If we must have all current groups and we didn't browse all
1758 	 * of them at this point (because the remaining ones have GIDs
1759 	 * greater than the last requested group), we are simply missing
1760 	 * them.
1761 	 */
1762 	if ((gid_flags & MDF_CURRENT) != 0 &&
1763 	    (gid_flags & MDF_SUPP_MUST) != 0 &&
1764 	    old_idx < old_ngroups)
1765 		return (EPERM);
1766 	/*
1767 	 * Similarly, we have to finish browsing all GIDs from the rule
1768 	 * in case some are marked mandatory.
1769 	 */
1770 	if ((gid_flags & MDF_EXPLICIT_SUPP_MUST) != 0) {
1771 		for (; rule_idx < rule->gids_nb; ++rule_idx) {
1772 			const struct id_spec is = rule->gids[rule_idx];
1773 
1774 			if ((is.flags & MDF_SUPP_MUST) != 0)
1775 				return (EPERM);
1776 		}
1777 	}
1778 
1779 	return (0);
1780 }
1781 
1782 static int
rule_grant_primary_group(const struct rule * const rule,const struct ucred * const old_cred,const gid_t gid)1783 rule_grant_primary_group(const struct rule *const rule,
1784     const struct ucred *const old_cred, const gid_t gid)
1785 {
1786 	struct id_spec gid_is = {.flags = 0};
1787 	const struct id_spec *found_is;
1788 	int error;
1789 
1790 	if ((rule->gid_flags & MDF_ANY) != 0)
1791 		return (0);
1792 
1793 	/* Was MDF_CURRENT specified, and is 'gid' a current GID? */
1794 	if ((rule->gid_flags & MDF_CURRENT) != 0 &&
1795 	    group_is_primary(gid, old_cred)) {
1796 		error = grant_primary_group_from_flags(rule->gid_flags);
1797 		if (error == 0)
1798 			return (0);
1799 	}
1800 
1801 	/* Search by GID for a corresponding 'struct id_spec'. */
1802 	gid_is.id = gid;
1803 	found_is = bsearch(&gid_is, rule->gids, rule->gids_nb,
1804 	    sizeof(*rule->gids), id_spec_cmp);
1805 
1806 	if (found_is != NULL) {
1807 		error = grant_primary_group_from_flags(found_is->flags);
1808 		if (error == 0)
1809 			return (0);
1810 	}
1811 
1812 	return (EPERM);
1813 }
1814 
1815 static int
rule_grant_primary_groups(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1816 rule_grant_primary_groups(const struct rule *const rule,
1817     const struct ucred *const old_cred, const struct ucred *const new_cred)
1818 {
1819 	int error;
1820 
1821 	/* Shortcut. */
1822 	if ((rule->gid_flags & MDF_ANY) != 0)
1823 		return (0);
1824 
1825 	error = rule_grant_primary_group(rule, old_cred, new_cred->cr_gid);
1826 	if (error != 0)
1827 		return (error);
1828 	error = rule_grant_primary_group(rule, old_cred, new_cred->cr_rgid);
1829 	if (error != 0)
1830 		return (error);
1831 	error = rule_grant_primary_group(rule, old_cred, new_cred->cr_svgid);
1832 	if (error != 0)
1833 		return (error);
1834 	return (0);
1835 }
1836 
1837 static bool
user_is_current(const uid_t uid,const struct ucred * const old_cred)1838 user_is_current(const uid_t uid, const struct ucred *const old_cred)
1839 {
1840 	return (uid == old_cred->cr_uid || uid == old_cred->cr_ruid ||
1841 	    uid == old_cred->cr_svuid);
1842 }
1843 
1844 static int
rule_grant_user(const struct rule * const rule,const struct ucred * const old_cred,const uid_t uid)1845 rule_grant_user(const struct rule *const rule,
1846     const struct ucred *const old_cred, const uid_t uid)
1847 {
1848 	struct id_spec uid_is = {.flags = 0};
1849 	const struct id_spec *found_is;
1850 
1851 	if ((rule->uid_flags & MDF_ANY) != 0)
1852 		return (0);
1853 
1854 	/* Was MDF_CURRENT specified, and is 'uid' a current UID? */
1855 	if ((rule->uid_flags & MDF_CURRENT) != 0 &&
1856 	    user_is_current(uid, old_cred))
1857 		return (0);
1858 
1859 	/* Search by UID for a corresponding 'struct id_spec'. */
1860 	uid_is.id = uid;
1861 	found_is = bsearch(&uid_is, rule->uids, rule->uids_nb,
1862 	    sizeof(*rule->uids), id_spec_cmp);
1863 
1864 	if (found_is != NULL)
1865 		return (0);
1866 
1867 	return (EPERM);
1868 }
1869 
1870 static int
rule_grant_users(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1871 rule_grant_users(const struct rule *const rule,
1872     const struct ucred *const old_cred, const struct ucred *const new_cred)
1873 {
1874 	int error;
1875 
1876 	/* Shortcut. */
1877 	if ((rule->uid_flags & MDF_ANY) != 0)
1878 		return (0);
1879 
1880 	error = rule_grant_user(rule, old_cred, new_cred->cr_uid);
1881 	if (error != 0)
1882 		return (error);
1883 	error = rule_grant_user(rule, old_cred, new_cred->cr_ruid);
1884 	if (error != 0)
1885 		return (error);
1886 	error = rule_grant_user(rule, old_cred, new_cred->cr_svuid);
1887 	if (error != 0)
1888 		return (error);
1889 
1890 	return (0);
1891 }
1892 
1893 static int
rule_grant_setcred(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1894 rule_grant_setcred(const struct rule *const rule,
1895     const struct ucred *const old_cred, const struct ucred *const new_cred)
1896 {
1897 	int error;
1898 
1899 	error = rule_grant_users(rule, old_cred, new_cred);
1900 	if (error != 0)
1901 		return (error);
1902 	error = rule_grant_primary_groups(rule, old_cred, new_cred);
1903 	if (error != 0)
1904 		return (error);
1905 	error = rule_grant_supplementary_groups(rule, old_cred, new_cred);
1906 	if (error != 0)
1907 		return (error);
1908 
1909 	return (0);
1910 }
1911 
1912 static bool
rule_applies(const struct rule * const rule,const struct ucred * const cred)1913 rule_applies(const struct rule *const rule, const struct ucred *const cred)
1914 {
1915 	if (rule->from_type == IT_UID && rule->from_id == cred->cr_ruid)
1916 		return (true);
1917 	if (rule->from_type == IT_GID && realgroupmember(rule->from_id, cred))
1918 		return (true);
1919 	return (false);
1920 }
1921 
1922 /*
1923  * To pass data between check_setcred() and priv_grant() (on PRIV_CRED_SETCRED).
1924  */
1925 struct mac_do_setcred_data {
1926 	struct mac_do_data_header hdr;
1927 	const struct ucred *new_cred;
1928 	u_int setcred_flags;
1929 };
1930 
1931 static int
mac_do_priv_grant(struct ucred * cred,int priv)1932 mac_do_priv_grant(struct ucred *cred, int priv)
1933 {
1934 	struct mac_do_setcred_data *const data = fetch_data();
1935 	const struct rules *rules;
1936 	const struct ucred *new_cred;
1937 	const struct rule *rule;
1938 	u_int setcred_flags;
1939 	int error;
1940 
1941 	/* Bail out fast if we aren't concerned. */
1942 	if (priv != PRIV_CRED_SETCRED)
1943 		return (EPERM);
1944 
1945 	/*
1946 	 * Do we have to do something?
1947 	 */
1948 	if (check_data_usable(data, sizeof(*data), priv) != 0)
1949 		/* No. */
1950 		return (EPERM);
1951 
1952 	rules = data->hdr.rules;
1953 	new_cred = data->new_cred;
1954 	KASSERT(new_cred != NULL,
1955 	    ("priv_check*() called before mac_cred_check_setcred()"));
1956 	setcred_flags = data->setcred_flags;
1957 
1958 	/*
1959 	 * Explicitly check that only the flags we currently support are present
1960 	 * in order to avoid accepting transitions with other changes than those
1961 	 * we are actually going to check.  Currently, this rules out the
1962 	 * SETCREDF_MAC_LABEL flag.  This may be improved by adding code
1963 	 * actually checking whether the requested label and the current one
1964 	 * would differ.
1965 	 */
1966 	if ((setcred_flags & ~(SETCREDF_UID | SETCREDF_RUID | SETCREDF_SVUID |
1967 	    SETCREDF_GID | SETCREDF_RGID | SETCREDF_SVGID |
1968 	    SETCREDF_SUPP_GROUPS)) != 0)
1969 		return (EPERM);
1970 
1971 	/*
1972 	 * Browse rules, and for those that match the requestor, call specific
1973 	 * privilege granting functions interpreting the "to"/"target" part.
1974 	 */
1975 	error = EPERM;
1976 	STAILQ_FOREACH(rule, &rules->head, r_entries)
1977 	    if (rule_applies(rule, cred)) {
1978 		    error = rule_grant_setcred(rule, cred, new_cred);
1979 		    if (error != EPERM)
1980 			    break;
1981 	    }
1982 
1983 	return (error);
1984 }
1985 
1986 static int
check_proc(void)1987 check_proc(void)
1988 {
1989 	char *path, *to_free;
1990 	int error;
1991 
1992 	/*
1993 	 * Only grant privileges if requested by the right executable.
1994 	 *
1995 	 * XXXOC: We may want to base this check on a tunable path and/or
1996 	 * a specific MAC label.  Going even further, e.g., envisioning to
1997 	 * completely replace the path check with the latter, we would need to
1998 	 * install FreeBSD on a FS with multilabel enabled by default, which in
1999 	 * practice entails adding an option to ZFS to set MNT_MULTILABEL
2000 	 * automatically on mounts, ensuring that root (and more if using
2001 	 * different partitions) ZFS or UFS filesystems are created with
2002 	 * multilabel turned on, and having the installation procedure support
2003 	 * setting a MAC label per file (perhaps via additions to mtree(1)).  So
2004 	 * this probably isn't going to happen overnight, if ever.
2005 	 */
2006 	if (vn_fullpath(curproc->p_textvp, &path, &to_free) != 0)
2007 		return (EPERM);
2008 	error = strcmp(path, "/usr/bin/mdo") == 0 ? 0 : EPERM;
2009 	free(to_free, M_TEMP);
2010 	return (error);
2011 }
2012 
2013 static void
mac_do_setcred_enter(void)2014 mac_do_setcred_enter(void)
2015 {
2016 	struct rules *rules;
2017 	struct prison *pr;
2018 	struct mac_do_setcred_data * data;
2019 	int error;
2020 
2021 	/*
2022 	 * If not enabled, don't prepare data.  Other hooks will check for that
2023 	 * to know if they have to do something.
2024 	 */
2025 	if (do_enabled == 0)
2026 		return;
2027 
2028 	/*
2029 	 * MAC/do only applies to a process launched from a given executable.
2030 	 * For other processes, we just won't intervene (we don't deny requests,
2031 	 * nor do we grant privileges to them).
2032 	 */
2033 	error = check_proc();
2034 	if (error != 0)
2035 		return;
2036 
2037 	/*
2038 	 * Find the currently applicable rules.
2039 	 */
2040 	rules = find_rules(curproc->p_ucred->cr_prison, &pr);
2041 	hold_rules(rules);
2042 	prison_unlock(pr);
2043 
2044 	/*
2045 	 * Setup thread data to be used by other hooks.
2046 	 */
2047 	data = fetch_data();
2048 	if (!is_data_reusable(data, sizeof(*data)))
2049 		data = alloc_data(data, sizeof(*data));
2050 	set_data_header(data, sizeof(*data), PRIV_CRED_SETCRED, rules);
2051 	/* Not really necessary, but helps to catch programming errors. */
2052 	data->new_cred = NULL;
2053 	data->setcred_flags = 0;
2054 }
2055 
2056 static int
mac_do_check_setcred(u_int flags,const struct ucred * const old_cred,struct ucred * const new_cred)2057 mac_do_check_setcred(u_int flags, const struct ucred *const old_cred,
2058     struct ucred *const new_cred)
2059 {
2060 	struct mac_do_setcred_data *const data = fetch_data();
2061 
2062 	/*
2063 	 * Do we have to do something?
2064 	 */
2065 	if (check_data_usable(data, sizeof(*data), PRIV_CRED_SETCRED) != 0)
2066 		/* No. */
2067 		return (0);
2068 
2069 	/*
2070 	 * Keep track of the setcred() flags and the new credentials for
2071 	 * priv_check*().
2072 	 */
2073 	data->new_cred = new_cred;
2074 	data->setcred_flags = flags;
2075 
2076 	return (0);
2077 }
2078 
2079 static void
mac_do_setcred_exit(void)2080 mac_do_setcred_exit(void)
2081 {
2082 	struct mac_do_setcred_data *const data = fetch_data();
2083 
2084 	if (check_data_usable(data, sizeof(*data), PRIV_CRED_SETCRED) == 0)
2085 		/*
2086 		 * This doesn't deallocate the small per-thread data storage,
2087 		 * which can be reused on subsequent calls.  (That data is of
2088 		 * course deallocated as the current thread dies or this module
2089 		 * is unloaded.)
2090 		 */
2091 		clear_data(data);
2092 }
2093 
2094 static void
mac_do_init(struct mac_policy_conf * mpc)2095 mac_do_init(struct mac_policy_conf *mpc)
2096 {
2097 	struct prison *pr;
2098 
2099 	osd_jail_slot = osd_jail_register(dealloc_jail_osd, osd_methods);
2100 	set_empty_rules(&prison0);
2101 	sx_slock(&allprison_lock);
2102 	TAILQ_FOREACH(pr, &allprison, pr_list)
2103 	    set_empty_rules(pr);
2104 	sx_sunlock(&allprison_lock);
2105 
2106 	osd_thread_slot = osd_thread_register(dealloc_thread_osd);
2107 }
2108 
2109 static void
mac_do_destroy(struct mac_policy_conf * mpc)2110 mac_do_destroy(struct mac_policy_conf *mpc)
2111 {
2112 	/*
2113 	 * osd_thread_deregister() must be called before osd_jail_deregister(),
2114 	 * for the reason explained in dealloc_jail_osd().
2115 	 */
2116 	osd_thread_deregister(osd_thread_slot);
2117 	osd_jail_deregister(osd_jail_slot);
2118 }
2119 
2120 static struct mac_policy_ops do_ops = {
2121 	.mpo_init = mac_do_init,
2122 	.mpo_destroy = mac_do_destroy,
2123 	.mpo_cred_setcred_enter = mac_do_setcred_enter,
2124 	.mpo_cred_check_setcred = mac_do_check_setcred,
2125 	.mpo_cred_setcred_exit = mac_do_setcred_exit,
2126 	.mpo_priv_grant = mac_do_priv_grant,
2127 };
2128 
2129 MAC_POLICY_SET(&do_ops, mac_do, "MAC/do", MPC_LOADTIME_FLAG_UNLOADOK, NULL);
2130 MODULE_VERSION(mac_do, 1);
2131