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