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/stdarg.h>
28 #include <sys/sx.h>
29 #include <sys/sysctl.h>
30 #include <sys/ucred.h>
31 #include <sys/vnode.h>
32
33 #include <security/mac/mac_policy.h>
34
35 static SYSCTL_NODE(_security_mac, OID_AUTO, do,
36 CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "mac_do policy controls");
37
38 static int do_enabled = 1;
39 SYSCTL_INT(_security_mac_do, OID_AUTO, enabled, CTLFLAG_RWTUN,
40 &do_enabled, 0, "Enforce do policy");
41
42 static int print_parse_error = 1;
43 SYSCTL_INT(_security_mac_do, OID_AUTO, print_parse_error, CTLFLAG_RWTUN,
44 &print_parse_error, 0, "Print parse errors on setting rules "
45 "(via sysctl(8)).");
46
47 static MALLOC_DEFINE(M_MAC_DO, "mac_do", "mac_do(4) security module");
48
49 #define MAC_RULE_STRING_LEN 1024
50
51 static unsigned osd_jail_slot;
52 static unsigned osd_thread_slot;
53
54 #define IT_INVALID 0 /* Must stay 0. */
55 #define IT_UID 1
56 #define IT_GID 2
57 #define IT_ANY 3
58 #define IT_LAST IT_ANY
59
60 static const char *id_type_to_str[] = {
61 [IT_INVALID] = "invalid",
62 [IT_UID] = "uid",
63 [IT_GID] = "gid",
64 /* See also parse_id_type(). */
65 [IT_ANY] = "*",
66 };
67
68 #define PARSE_ERROR_SIZE 256
69
70 struct parse_error {
71 size_t pos;
72 char msg[PARSE_ERROR_SIZE];
73 };
74
75 /*
76 * We assume that 'uid_t' and 'gid_t' are aliases to 'u_int' in conversions
77 * required for parsing rules specification strings.
78 */
79 _Static_assert(sizeof(uid_t) == sizeof(u_int) && (uid_t)-1 >= 0 &&
80 sizeof(gid_t) == sizeof(u_int) && (gid_t)-1 >= 0,
81 "mac_do(4) assumes that 'uid_t' and 'gid_t' are aliases to 'u_int'");
82
83 /*
84 * Internal flags.
85 *
86 * They either apply as per-type (t) or per-ID (i) but are conflated because all
87 * per-ID flags are also valid as per-type ones to qualify the "current" (".")
88 * per-type flag. Also, some of them are in fact exclusive, but we use one-hot
89 * encoding for simplicity.
90 *
91 * There is currently room for "only" 16 bits. As these flags are purely
92 * internal, they can be renumbered and/or their type changed as needed.
93 *
94 * See also the check_*() functions below.
95 */
96 typedef uint16_t flags_t;
97
98 /* (i,gid) Specification concerns primary groups. */
99 #define MDF_PRIMARY (1u << 0)
100 /* (i,gid) Specification concerns supplementary groups. */
101 #define MDF_SUPP_ALLOW (1u << 1)
102 /* (i,gid) Group must appear as a supplementary group. */
103 #define MDF_SUPP_MUST (1u << 2)
104 /* (i,gid) Group must not appear as a supplementary group. */
105 #define MDF_SUPP_DONT (1u << 3)
106 #define MDF_SUPP_MASK (MDF_SUPP_ALLOW | MDF_SUPP_MUST | MDF_SUPP_DONT)
107 #define MDF_ID_MASK (MDF_PRIMARY | MDF_SUPP_MASK)
108
109 /*
110 * (t) All IDs allowed.
111 *
112 * For GIDs, MDF_ANY only concerns primary groups. The MDF_PRIMARY and
113 * MDF_SUPP_* flags never apply to MDF_ANY, but can be present if MDF_CURRENT is
114 * present also, as usual.
115 */
116 #define MDF_ANY (1u << 8)
117 /* (t) Current IDs allowed. */
118 #define MDF_CURRENT (1u << 9)
119 #define MDF_TYPE_COMMON_MASK (MDF_ANY | MDF_CURRENT)
120 /* (t,gid) All IDs allowed as supplementary groups. */
121 #define MDF_ANY_SUPP (1u << 10)
122 /* (t,gid) Some ID or MDF_CURRENT has MDF_SUPP_MUST or MDF_SUPP_DONT. */
123 #define MDF_MAY_REJ_SUPP (1u << 11)
124 /* (t,gid) Some explicit ID (not MDF_CURRENT) has MDF_SUPP_MUST. */
125 #define MDF_EXPLICIT_SUPP_MUST (1u << 12)
126 /* (t,gid) Whether any target clause is about primary groups. Used during
127 * parsing only. */
128 #define MDF_HAS_PRIMARY_CLAUSE (1u << 13)
129 /* (t,gid) Whether any target clause is about supplementary groups. Used during
130 * parsing only. */
131 #define MDF_HAS_SUPP_CLAUSE (1u << 14)
132 #define MDF_TYPE_GID_MASK (MDF_ANY_SUPP | MDF_MAY_REJ_SUPP | \
133 MDF_EXPLICIT_SUPP_MUST | MDF_HAS_PRIMARY_CLAUSE | MDF_HAS_SUPP_CLAUSE)
134 #define MDF_TYPE_MASK (MDF_TYPE_COMMON_MASK | MDF_TYPE_GID_MASK)
135
136 /*
137 * Persistent structures.
138 */
139
140 struct id_spec {
141 u_int id;
142 flags_t flags; /* See MDF_* above. */
143 };
144
145 /*
146 * This limits the number of target clauses per type to 65535. With the current
147 * value of MAC_RULE_STRING_LEN (1024), this is way more than enough anyway.
148 */
149 typedef uint16_t id_nb_t;
150 /* We only have a few IT_* types. */
151 typedef uint16_t id_type_t;
152
153 struct rule {
154 STAILQ_ENTRY(rule) r_entries;
155 id_type_t from_type;
156 u_int from_id;
157 flags_t uid_flags; /* See MDF_* above. */
158 id_nb_t uids_nb;
159 flags_t gid_flags; /* See MDF_* above. */
160 id_nb_t gids_nb;
161 struct id_spec *uids;
162 struct id_spec *gids;
163 };
164
165 STAILQ_HEAD(rulehead, rule);
166
167 struct rules {
168 char string[MAC_RULE_STRING_LEN];
169 struct rulehead head;
170 volatile u_int use_count __aligned(CACHE_LINE_SIZE);
171 };
172
173 /*
174 * Temporary structures used to build a 'struct rule' above.
175 */
176
177 struct id_elem {
178 STAILQ_ENTRY(id_elem) ie_entries;
179 struct id_spec spec;
180 };
181
182 STAILQ_HEAD(id_list, id_elem);
183
184 #ifdef INVARIANTS
185 static void
check_type(const id_type_t type)186 check_type(const id_type_t type)
187 {
188 if (type > IT_LAST)
189 panic("Invalid type number %u", type);
190 }
191
192 static void
panic_for_unexpected_flags(const id_type_t type,const flags_t flags,const char * const str)193 panic_for_unexpected_flags(const id_type_t type, const flags_t flags,
194 const char *const str)
195 {
196 panic("ID type %s: Unexpected flags %u (%s), ", id_type_to_str[type],
197 flags, str);
198 }
199
200 static void
check_type_and_id_flags(const id_type_t type,const flags_t flags)201 check_type_and_id_flags(const id_type_t type, const flags_t flags)
202 {
203 const char *str;
204
205 check_type(type);
206 switch (type) {
207 case IT_UID:
208 if (flags != 0) {
209 str = "only 0 allowed";
210 goto unexpected_flags;
211 }
212 break;
213 case IT_GID:
214 if ((flags & ~MDF_ID_MASK) != 0) {
215 str = "only bits in MDF_ID_MASK allowed";
216 goto unexpected_flags;
217 }
218 if (!powerof2(flags & MDF_SUPP_MASK)) {
219 str = "only a single flag in MDF_SUPP_MASK allowed";
220 goto unexpected_flags;
221 }
222 break;
223 default:
224 __assert_unreachable();
225 }
226 return;
227
228 unexpected_flags:
229 panic_for_unexpected_flags(type, flags, str);
230 }
231
232 static void
check_type_and_id_spec(const id_type_t type,const struct id_spec * const is)233 check_type_and_id_spec(const id_type_t type, const struct id_spec *const is)
234 {
235 check_type_and_id_flags(type, is->flags);
236 }
237
238 static void
check_type_and_type_flags(const id_type_t type,const flags_t flags)239 check_type_and_type_flags(const id_type_t type, const flags_t flags)
240 {
241 const char *str;
242
243 check_type_and_id_flags(type, flags & MDF_ID_MASK);
244 if ((flags & ~MDF_ID_MASK & ~MDF_TYPE_MASK) != 0) {
245 str = "only MDF_ID_MASK | MDF_TYPE_MASK bits allowed";
246 goto unexpected_flags;
247 }
248 if ((flags & MDF_ANY) != 0 && (flags & MDF_CURRENT) != 0 &&
249 (type == IT_UID || (flags & MDF_PRIMARY) != 0)) {
250 str = "MDF_ANY and MDF_CURRENT are exclusive for UIDs "
251 "or primary group GIDs";
252 goto unexpected_flags;
253 }
254 if ((flags & MDF_ANY_SUPP) != 0 && (flags & MDF_CURRENT) != 0 &&
255 (flags & MDF_SUPP_MASK) != 0) {
256 str = "MDF_SUPP_ANY and MDF_CURRENT with supplementary "
257 "groups specification are exclusive";
258 goto unexpected_flags;
259 }
260 if (type == IT_GID &&
261 ((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_MAC_DO);
323 free(rule->gids, M_MAC_DO);
324 free(rule, M_MAC_DO);
325 }
326 free(rules, M_MAC_DO);
327 }
328
329 static struct rules *
alloc_rules(void)330 alloc_rules(void)
331 {
332 struct rules *const rules = malloc(sizeof(*rules), M_MAC_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_MAC_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_MAC_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_MAC_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_MAC_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_MAC_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_MAC_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_MAC_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_MAC_DO);
973 free(new->uids, M_MAC_DO);
974 free(new, M_MAC_DO);
975 STAILQ_FOREACH_SAFE(ie, &gid_list, ie_entries, ie_next)
976 free(ie, M_MAC_DO);
977 STAILQ_FOREACH_SAFE(ie, &uid_list, ie_entries, ie_next)
978 free(ie, M_MAC_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_MAC_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_MAC_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 burden ourselves with extracting rules first instead of just
1157 * letting osd_jail_del() call dealloc_jail_osd() as we want to
1158 * decrement their use count, and possibly free them, outside of the
1159 * prison lock.
1160 */
1161 old_rules = osd_jail_get(pr, osd_jail_slot);
1162 error = osd_jail_set(pr, osd_jail_slot, NULL);
1163 /* osd_set() never allocates memory when 'value' is NULL, nor fails. */
1164 MPASS(error == 0);
1165 /*
1166 * This completely frees the OSD slot, but doesn't call the destructor
1167 * since we've just put NULL in the slot.
1168 */
1169 osd_jail_del(pr, osd_jail_slot);
1170 prison_unlock(pr);
1171
1172 if (old_rules != NULL)
1173 drop_rules(old_rules);
1174 }
1175
1176 /*
1177 * Assign already built rules to a jail.
1178 */
1179 static void
set_rules(struct prison * const pr,struct rules * const rules)1180 set_rules(struct prison *const pr, struct rules *const rules)
1181 {
1182 struct rules *old_rules;
1183 void **rsv;
1184
1185 check_rules_use_count(rules, 0);
1186 hold_rules(rules);
1187 rsv = osd_reserve(osd_jail_slot);
1188
1189 prison_lock(pr);
1190 old_rules = osd_jail_get(pr, osd_jail_slot);
1191 osd_jail_set_reserved(pr, osd_jail_slot, rsv, rules);
1192 prison_unlock(pr);
1193 if (old_rules != NULL)
1194 drop_rules(old_rules);
1195 }
1196
1197 /*
1198 * Assigns empty rules to a jail.
1199 */
1200 static void
set_empty_rules(struct prison * const pr)1201 set_empty_rules(struct prison *const pr)
1202 {
1203 struct rules *const rules = alloc_rules();
1204
1205 set_rules(pr, rules);
1206 }
1207
1208 /*
1209 * Parse a rules specification and assign them to a jail.
1210 *
1211 * Returns the same error code as parse_rules() (which see).
1212 */
1213 static int
parse_and_set_rules(struct prison * const pr,const char * rules_string,struct parse_error ** const parse_error)1214 parse_and_set_rules(struct prison *const pr, const char *rules_string,
1215 struct parse_error **const parse_error)
1216 {
1217 struct rules *rules;
1218 int error;
1219
1220 error = parse_rules(rules_string, &rules, parse_error);
1221 if (error != 0)
1222 return (error);
1223 set_rules(pr, rules);
1224 return (0);
1225 }
1226
1227 static int
mac_do_sysctl_rules(SYSCTL_HANDLER_ARGS)1228 mac_do_sysctl_rules(SYSCTL_HANDLER_ARGS)
1229 {
1230 char *const buf = malloc(MAC_RULE_STRING_LEN, M_MAC_DO, M_WAITOK);
1231 struct prison *const td_pr = req->td->td_ucred->cr_prison;
1232 struct prison *pr;
1233 struct rules *rules;
1234 struct parse_error *parse_error;
1235 int error;
1236
1237 rules = find_rules(td_pr, &pr);
1238 strlcpy(buf, rules->string, MAC_RULE_STRING_LEN);
1239 prison_unlock(pr);
1240
1241 error = sysctl_handle_string(oidp, buf, MAC_RULE_STRING_LEN, req);
1242 if (error != 0 || req->newptr == NULL)
1243 goto out;
1244
1245 /* Set our prison's rules, not that of the jail we inherited from. */
1246 error = parse_and_set_rules(td_pr, buf, &parse_error);
1247 if (error != 0) {
1248 if (print_parse_error)
1249 printf("MAC/do: Parse error at index %zu: %s\n",
1250 parse_error->pos, parse_error->msg);
1251 free_parse_error(parse_error);
1252 }
1253 out:
1254 free(buf, M_MAC_DO);
1255 return (error);
1256 }
1257
1258 SYSCTL_PROC(_security_mac_do, OID_AUTO, rules,
1259 CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_PRISON|CTLFLAG_MPSAFE,
1260 0, 0, mac_do_sysctl_rules, "A",
1261 "Rules");
1262
1263
1264 SYSCTL_JAIL_PARAM_SYS_SUBNODE(mac, do, CTLFLAG_RW, "Jail MAC/do parameters");
1265 SYSCTL_JAIL_PARAM_STRING(_mac_do, rules, CTLFLAG_RW, MAC_RULE_STRING_LEN,
1266 "Jail MAC/do rules");
1267
1268
1269 static int
mac_do_jail_create(void * obj,void * data __unused)1270 mac_do_jail_create(void *obj, void *data __unused)
1271 {
1272 struct prison *const pr = obj;
1273
1274 set_empty_rules(pr);
1275 return (0);
1276 }
1277
1278 static int
mac_do_jail_get(void * obj,void * data)1279 mac_do_jail_get(void *obj, void *data)
1280 {
1281 struct prison *ppr, *const pr = obj;
1282 struct vfsoptlist *const opts = data;
1283 struct rules *rules;
1284 int jsys, error;
1285
1286 rules = find_rules(pr, &ppr);
1287
1288 jsys = pr == ppr ?
1289 (STAILQ_EMPTY(&rules->head) ? JAIL_SYS_DISABLE : JAIL_SYS_NEW) :
1290 JAIL_SYS_INHERIT;
1291 error = vfs_setopt(opts, "mac.do", &jsys, sizeof(jsys));
1292 if (error != 0 && error != ENOENT)
1293 goto done;
1294
1295 error = vfs_setopts(opts, "mac.do.rules", rules->string);
1296 if (error != 0 && error != ENOENT)
1297 goto done;
1298
1299 error = 0;
1300 done:
1301 prison_unlock(ppr);
1302 return (error);
1303 }
1304
1305 /*
1306 * -1 is used as a sentinel in mac_do_jail_check() and mac_do_jail_set() below.
1307 */
1308 _Static_assert(-1 != JAIL_SYS_DISABLE && -1 != JAIL_SYS_NEW &&
1309 -1 != JAIL_SYS_INHERIT,
1310 "mac_do(4) uses -1 as a sentinel for uninitialized 'jsys'.");
1311
1312 /*
1313 * We perform only cheap checks here, i.e., we do not really parse the rules
1314 * specification string, if any.
1315 */
1316 static int
mac_do_jail_check(void * obj,void * data)1317 mac_do_jail_check(void *obj, void *data)
1318 {
1319 struct vfsoptlist *opts = data;
1320 char *rules_string;
1321 int error, jsys, size;
1322
1323 error = vfs_copyopt(opts, "mac.do", &jsys, sizeof(jsys));
1324 if (error == ENOENT)
1325 jsys = -1;
1326 else {
1327 if (error != 0)
1328 return (error);
1329 if (jsys != JAIL_SYS_DISABLE && jsys != JAIL_SYS_NEW &&
1330 jsys != JAIL_SYS_INHERIT)
1331 return (EINVAL);
1332 }
1333
1334 /*
1335 * We use vfs_getopt() here instead of vfs_getopts() to get the length.
1336 * We perform the additional checks done by the latter here, even if
1337 * jail_set() calls vfs_getopts() itself later (they becoming
1338 * inconsistent wouldn't cause any security problem).
1339 */
1340 error = vfs_getopt(opts, "mac.do.rules", (void**)&rules_string, &size);
1341 if (error == ENOENT) {
1342 /*
1343 * Default (in absence of "mac.do.rules") is to disable (and, in
1344 * particular, not inherit).
1345 */
1346 if (jsys == -1)
1347 jsys = JAIL_SYS_DISABLE;
1348
1349 if (jsys == JAIL_SYS_NEW) {
1350 vfs_opterror(opts, "'mac.do.rules' must be specified "
1351 "given 'mac.do''s value");
1352 return (EINVAL);
1353 }
1354
1355 /* Absence of "mac.do.rules" at this point is OK. */
1356 error = 0;
1357 } else {
1358 if (error != 0)
1359 return (error);
1360
1361 /* Not a proper string. */
1362 if (size == 0 || rules_string[size - 1] != '\0') {
1363 vfs_opterror(opts, "'mac.do.rules' not a proper string");
1364 return (EINVAL);
1365 }
1366
1367 if (size > MAC_RULE_STRING_LEN) {
1368 vfs_opterror(opts, "'mdo.rules' too long");
1369 return (ENAMETOOLONG);
1370 }
1371
1372 if (jsys == -1)
1373 /* Default (if "mac.do.rules" is present). */
1374 jsys = rules_string[0] == '\0' ? JAIL_SYS_DISABLE :
1375 JAIL_SYS_NEW;
1376
1377 /*
1378 * Be liberal and accept JAIL_SYS_DISABLE and JAIL_SYS_INHERIT
1379 * with an explicit empty rules specification.
1380 */
1381 switch (jsys) {
1382 case JAIL_SYS_DISABLE:
1383 case JAIL_SYS_INHERIT:
1384 if (rules_string[0] != '\0') {
1385 vfs_opterror(opts, "'mac.do.rules' specified "
1386 "but should not given 'mac.do''s value");
1387 return (EINVAL);
1388 }
1389 break;
1390 }
1391 }
1392
1393 return (error);
1394 }
1395
1396 static int
mac_do_jail_set(void * obj,void * data)1397 mac_do_jail_set(void *obj, void *data)
1398 {
1399 struct prison *pr = obj;
1400 struct vfsoptlist *opts = data;
1401 char *rules_string;
1402 struct parse_error *parse_error;
1403 int error, jsys;
1404
1405 /*
1406 * The invariants checks used below correspond to what has already been
1407 * checked in jail_check() above.
1408 */
1409
1410 error = vfs_copyopt(opts, "mac.do", &jsys, sizeof(jsys));
1411 MPASS(error == 0 || error == ENOENT);
1412 if (error != 0)
1413 jsys = -1; /* Mark unfilled. */
1414
1415 rules_string = vfs_getopts(opts, "mac.do.rules", &error);
1416 MPASS(error == 0 || error == ENOENT);
1417 if (error == 0) {
1418 MPASS(strlen(rules_string) < MAC_RULE_STRING_LEN);
1419 if (jsys == -1)
1420 /* Default (if "mac.do.rules" is present). */
1421 jsys = rules_string[0] == '\0' ? JAIL_SYS_DISABLE :
1422 JAIL_SYS_NEW;
1423 else
1424 MPASS(jsys == JAIL_SYS_NEW ||
1425 ((jsys == JAIL_SYS_DISABLE ||
1426 jsys == JAIL_SYS_INHERIT) &&
1427 rules_string[0] == '\0'));
1428 } else {
1429 MPASS(jsys != JAIL_SYS_NEW);
1430 if (jsys == -1)
1431 /*
1432 * Default (in absence of "mac.do.rules") is to disable
1433 * (and, in particular, not inherit).
1434 */
1435 jsys = JAIL_SYS_DISABLE;
1436 /* If disabled, we'll store an empty rule specification. */
1437 if (jsys == JAIL_SYS_DISABLE)
1438 rules_string = "";
1439 }
1440
1441 switch (jsys) {
1442 case JAIL_SYS_INHERIT:
1443 remove_rules(pr);
1444 error = 0;
1445 break;
1446 case JAIL_SYS_DISABLE:
1447 case JAIL_SYS_NEW:
1448 error = parse_and_set_rules(pr, rules_string, &parse_error);
1449 if (error != 0) {
1450 vfs_opterror(opts,
1451 "MAC/do: Parse error at index %zu: %s\n",
1452 parse_error->pos, parse_error->msg);
1453 free_parse_error(parse_error);
1454 }
1455 break;
1456 default:
1457 __assert_unreachable();
1458 }
1459 return (error);
1460 }
1461
1462 /*
1463 * OSD jail methods.
1464 *
1465 * There is no PR_METHOD_REMOVE, as OSD storage is destroyed by the common jail
1466 * code (see prison_cleanup()), which triggers a run of our dealloc_jail_osd()
1467 * destructor.
1468 */
1469 static const osd_method_t osd_methods[PR_MAXMETHOD] = {
1470 [PR_METHOD_CREATE] = mac_do_jail_create,
1471 [PR_METHOD_GET] = mac_do_jail_get,
1472 [PR_METHOD_CHECK] = mac_do_jail_check,
1473 [PR_METHOD_SET] = mac_do_jail_set,
1474 };
1475
1476
1477 /*
1478 * Common header structure.
1479 *
1480 * Each structure that is used to pass information between some MAC check
1481 * function and priv_grant() must start with this header.
1482 */
1483 struct mac_do_data_header {
1484 /* Size of the allocated buffer holding the containing structure. */
1485 size_t allocated_size;
1486 /* Full size of the containing structure. */
1487 size_t size;
1488 /*
1489 * For convenience, we use privilege numbers as an identifier for the
1490 * containing structure's type, since there is one distinct privilege
1491 * for each privilege changing function we are supporting. 0 in 'priv'
1492 * indicates this header is uninitialized.
1493 */
1494 int priv;
1495 /* Rules to apply. */
1496 struct rules *rules;
1497 };
1498
1499 /*
1500 * The case of unusable or absent per-thread data can actually happen as nothing
1501 * prevents, e.g., priv_check*() with privilege 'priv' to be called standalone,
1502 * as it is currently by, e.g., the Linux emulator for PRIV_CRED_SETUID. We
1503 * interpret such calls to priv_check*() as full, unrestricted requests for
1504 * 'priv', contrary to what we're doing here for selected operations, and
1505 * consequently will not grant the requested privilege.
1506 *
1507 * Also, we protect ourselves from a concurrent change of 'do_enabled' while
1508 * a call to setcred() is in progress by storing the rules per-thread
1509 * which is then consulted by each successive hook so that they all have
1510 * a coherent view of the specifications, and we empty the slot (actually, mark
1511 * it as empty) when MAC/do is disabled.
1512 */
1513 static int
check_data_usable(const void * const data,const size_t size,const int priv)1514 check_data_usable(const void *const data, const size_t size, const int priv)
1515 {
1516 const struct mac_do_data_header *const hdr = data;
1517
1518 if (hdr == NULL || hdr->priv == 0)
1519 return (ENOENT);
1520 /*
1521 * Impacting changes in the protocols we are based on... Don't crash in
1522 * production.
1523 */
1524 if (hdr->priv != priv) {
1525 MPASS(hdr->priv == priv);
1526 return (EBUSY);
1527 }
1528 MPASS(hdr->size == size);
1529 MPASS(hdr->size <= hdr->allocated_size);
1530 return (0);
1531 }
1532
1533 static void
clear_data(void * const data)1534 clear_data(void *const data)
1535 {
1536 struct mac_do_data_header *const hdr = data;
1537
1538 if (hdr != NULL) {
1539 drop_rules(hdr->rules);
1540 /* We don't deallocate so as to save time on next access. */
1541 hdr->priv = 0;
1542 }
1543 }
1544
1545 static void *
fetch_data(void)1546 fetch_data(void)
1547 {
1548 return (osd_thread_get_unlocked(curthread, osd_thread_slot));
1549 }
1550
1551 static bool
is_data_reusable(const void * const data,const size_t size)1552 is_data_reusable(const void *const data, const size_t size)
1553 {
1554 const struct mac_do_data_header *const hdr = data;
1555
1556 return (hdr != NULL && size <= hdr->allocated_size);
1557 }
1558
1559 static void
set_data_header(void * const data,const size_t size,const int priv,struct rules * const rules)1560 set_data_header(void *const data, const size_t size, const int priv,
1561 struct rules *const rules)
1562 {
1563 struct mac_do_data_header *const hdr = data;
1564
1565 MPASS(hdr->priv == 0);
1566 MPASS(priv != 0);
1567 MPASS(size <= hdr->allocated_size);
1568 hdr->size = size;
1569 hdr->priv = priv;
1570 hdr->rules = rules;
1571 }
1572
1573 /* The proc lock (and any other non-sleepable lock) must not be held. */
1574 static void *
alloc_data(void * const data,const size_t size)1575 alloc_data(void *const data, const size_t size)
1576 {
1577 struct mac_do_data_header *const hdr = realloc(data, size, M_MAC_DO,
1578 M_WAITOK);
1579
1580 MPASS(size >= sizeof(struct mac_do_data_header));
1581 hdr->allocated_size = size;
1582 hdr->priv = 0;
1583 if (hdr != data) {
1584 /*
1585 * This call either reuses the existing memory allocated for the
1586 * slot or tries to allocate some without blocking.
1587 */
1588 int error = osd_thread_set(curthread, osd_thread_slot, hdr);
1589
1590 if (error != 0) {
1591 /* Going to make a M_WAITOK allocation. */
1592 void **const rsv = osd_reserve(osd_thread_slot);
1593
1594 error = osd_thread_set_reserved(curthread,
1595 osd_thread_slot, rsv, hdr);
1596 MPASS(error == 0);
1597 }
1598 }
1599 return (hdr);
1600 }
1601
1602 /* Destructor for 'osd_thread_slot'. */
1603 static void
dealloc_thread_osd(void * const value)1604 dealloc_thread_osd(void *const value)
1605 {
1606 free(value, M_MAC_DO);
1607 }
1608
1609 /*
1610 * Whether to grant access to some primary group according to flags.
1611 *
1612 * The passed 'flags' must be those of a rule's matching GID, or the IT_GID type
1613 * flags when MDF_CURRENT has been matched.
1614 *
1615 * Return values:
1616 * - 0: Access granted.
1617 * - EJUSTRETURN: Flags are agnostic.
1618 */
1619 static int
grant_primary_group_from_flags(const flags_t flags)1620 grant_primary_group_from_flags(const flags_t flags)
1621 {
1622 return ((flags & MDF_PRIMARY) != 0 ? 0 : EJUSTRETURN);
1623 }
1624
1625 /*
1626 * Same as grant_primary_group_from_flags(), but for supplementary groups.
1627 *
1628 * Return values:
1629 * - 0: Access granted.
1630 * - EJUSTRETURN: Flags are agnostic.
1631 * - EPERM: Access denied.
1632 */
1633 static int __unused
grant_supplementary_group_from_flags(const flags_t flags)1634 grant_supplementary_group_from_flags(const flags_t flags)
1635 {
1636 if ((flags & MDF_SUPP_MASK) != 0)
1637 return ((flags & MDF_SUPP_DONT) != 0 ? EPERM : 0);
1638
1639 return (EJUSTRETURN);
1640 }
1641
1642 static int
rule_grant_supplementary_groups(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1643 rule_grant_supplementary_groups(const struct rule *const rule,
1644 const struct ucred *const old_cred, const struct ucred *const new_cred)
1645 {
1646 const gid_t *const old_groups = old_cred->cr_groups;
1647 const gid_t *const new_groups = new_cred->cr_groups;
1648 const int old_ngroups = old_cred->cr_ngroups;
1649 const int new_ngroups = new_cred->cr_ngroups;
1650 const flags_t gid_flags = rule->gid_flags;
1651 const bool current_has_supp = (gid_flags & MDF_CURRENT) != 0 &&
1652 (gid_flags & MDF_SUPP_MASK) != 0;
1653 id_nb_t rule_idx = 0;
1654 int old_idx = 0, new_idx = 0;
1655
1656 if ((gid_flags & MDF_ANY_SUPP) != 0 &&
1657 (gid_flags & MDF_MAY_REJ_SUPP) == 0)
1658 /*
1659 * Any set of supplementary groups is accepted, no need to loop
1660 * over them.
1661 */
1662 return (0);
1663
1664 for (; new_idx < new_ngroups; ++new_idx) {
1665 const gid_t gid = new_groups[new_idx];
1666 bool may_accept = false;
1667
1668 if ((gid_flags & MDF_ANY_SUPP) != 0)
1669 may_accept = true;
1670
1671 /* Do we have to check for the current supplementary groups? */
1672 if (current_has_supp) {
1673 /*
1674 * Linear search, as both supplementary groups arrays
1675 * are sorted. Advancing 'old_idx' with a binary search
1676 * on absence of MDF_SUPP_MUST doesn't seem worth it in
1677 * practice.
1678 */
1679 for (; old_idx < old_ngroups; ++old_idx) {
1680 const gid_t old_gid = old_groups[old_idx];
1681
1682 if (old_gid < gid) {
1683 /* Mandatory but absent. */
1684 if ((gid_flags & MDF_SUPP_MUST) != 0)
1685 return (EPERM);
1686 } else if (old_gid == gid) {
1687 switch (gid_flags & MDF_SUPP_MASK) {
1688 case MDF_SUPP_DONT:
1689 /* Present but forbidden. */
1690 return (EPERM);
1691 case MDF_SUPP_ALLOW:
1692 case MDF_SUPP_MUST:
1693 may_accept = true;
1694 break;
1695 default:
1696 #ifdef INVARIANTS
1697 __assert_unreachable();
1698 #else
1699 /* Better be safe than sorry. */
1700 return (EPERM);
1701 #endif
1702 }
1703 ++old_idx;
1704 break;
1705 }
1706 else
1707 break;
1708 }
1709 }
1710
1711 /*
1712 * Search by GID for a corresponding 'struct id_spec'.
1713 *
1714 * Again, linear search, with same note on not using binary
1715 * search optimization as above (the trigger would be absence of
1716 * MDF_EXPLICIT_SUPP_MUST this time).
1717 */
1718 for (; rule_idx < rule->gids_nb; ++rule_idx) {
1719 const struct id_spec is = rule->gids[rule_idx];
1720
1721 if (is.id < gid) {
1722 /* Mandatory but absent. */
1723 if ((is.flags & MDF_SUPP_MUST) != 0)
1724 return (EPERM);
1725 } else if (is.id == gid) {
1726 switch (is.flags & MDF_SUPP_MASK) {
1727 case MDF_SUPP_DONT:
1728 /* Present but forbidden. */
1729 return (EPERM);
1730 case MDF_SUPP_ALLOW:
1731 case MDF_SUPP_MUST:
1732 may_accept = true;
1733 break;
1734 case 0:
1735 /* Primary group only. */
1736 break;
1737 default:
1738 #ifdef INVARIANTS
1739 __assert_unreachable();
1740 #else
1741 /* Better be safe than sorry. */
1742 return (EPERM);
1743 #endif
1744 }
1745 ++rule_idx;
1746 break;
1747 }
1748 else
1749 break;
1750 }
1751
1752 /* 'gid' wasn't explicitly accepted. */
1753 if (!may_accept)
1754 return (EPERM);
1755 }
1756
1757 /*
1758 * If we must have all current groups and we didn't browse all
1759 * of them at this point (because the remaining ones have GIDs
1760 * greater than the last requested group), we are simply missing
1761 * them.
1762 */
1763 if ((gid_flags & MDF_CURRENT) != 0 &&
1764 (gid_flags & MDF_SUPP_MUST) != 0 &&
1765 old_idx < old_ngroups)
1766 return (EPERM);
1767 /*
1768 * Similarly, we have to finish browsing all GIDs from the rule
1769 * in case some are marked mandatory.
1770 */
1771 if ((gid_flags & MDF_EXPLICIT_SUPP_MUST) != 0) {
1772 for (; rule_idx < rule->gids_nb; ++rule_idx) {
1773 const struct id_spec is = rule->gids[rule_idx];
1774
1775 if ((is.flags & MDF_SUPP_MUST) != 0)
1776 return (EPERM);
1777 }
1778 }
1779
1780 return (0);
1781 }
1782
1783 static int
rule_grant_primary_group(const struct rule * const rule,const struct ucred * const old_cred,const gid_t gid)1784 rule_grant_primary_group(const struct rule *const rule,
1785 const struct ucred *const old_cred, const gid_t gid)
1786 {
1787 struct id_spec gid_is = {.flags = 0};
1788 const struct id_spec *found_is;
1789 int error;
1790
1791 if ((rule->gid_flags & MDF_ANY) != 0)
1792 return (0);
1793
1794 /* Was MDF_CURRENT specified, and is 'gid' a current GID? */
1795 if ((rule->gid_flags & MDF_CURRENT) != 0 &&
1796 group_is_primary(gid, old_cred)) {
1797 error = grant_primary_group_from_flags(rule->gid_flags);
1798 if (error == 0)
1799 return (0);
1800 }
1801
1802 /* Search by GID for a corresponding 'struct id_spec'. */
1803 gid_is.id = gid;
1804 found_is = bsearch(&gid_is, rule->gids, rule->gids_nb,
1805 sizeof(*rule->gids), id_spec_cmp);
1806
1807 if (found_is != NULL) {
1808 error = grant_primary_group_from_flags(found_is->flags);
1809 if (error == 0)
1810 return (0);
1811 }
1812
1813 return (EPERM);
1814 }
1815
1816 static int
rule_grant_primary_groups(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1817 rule_grant_primary_groups(const struct rule *const rule,
1818 const struct ucred *const old_cred, const struct ucred *const new_cred)
1819 {
1820 int error;
1821
1822 /* Shortcut. */
1823 if ((rule->gid_flags & MDF_ANY) != 0)
1824 return (0);
1825
1826 error = rule_grant_primary_group(rule, old_cred, new_cred->cr_gid);
1827 if (error != 0)
1828 return (error);
1829 error = rule_grant_primary_group(rule, old_cred, new_cred->cr_rgid);
1830 if (error != 0)
1831 return (error);
1832 error = rule_grant_primary_group(rule, old_cred, new_cred->cr_svgid);
1833 if (error != 0)
1834 return (error);
1835 return (0);
1836 }
1837
1838 static bool
user_is_current(const uid_t uid,const struct ucred * const old_cred)1839 user_is_current(const uid_t uid, const struct ucred *const old_cred)
1840 {
1841 return (uid == old_cred->cr_uid || uid == old_cred->cr_ruid ||
1842 uid == old_cred->cr_svuid);
1843 }
1844
1845 static int
rule_grant_user(const struct rule * const rule,const struct ucred * const old_cred,const uid_t uid)1846 rule_grant_user(const struct rule *const rule,
1847 const struct ucred *const old_cred, const uid_t uid)
1848 {
1849 struct id_spec uid_is = {.flags = 0};
1850 const struct id_spec *found_is;
1851
1852 if ((rule->uid_flags & MDF_ANY) != 0)
1853 return (0);
1854
1855 /* Was MDF_CURRENT specified, and is 'uid' a current UID? */
1856 if ((rule->uid_flags & MDF_CURRENT) != 0 &&
1857 user_is_current(uid, old_cred))
1858 return (0);
1859
1860 /* Search by UID for a corresponding 'struct id_spec'. */
1861 uid_is.id = uid;
1862 found_is = bsearch(&uid_is, rule->uids, rule->uids_nb,
1863 sizeof(*rule->uids), id_spec_cmp);
1864
1865 if (found_is != NULL)
1866 return (0);
1867
1868 return (EPERM);
1869 }
1870
1871 static int
rule_grant_users(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1872 rule_grant_users(const struct rule *const rule,
1873 const struct ucred *const old_cred, const struct ucred *const new_cred)
1874 {
1875 int error;
1876
1877 /* Shortcut. */
1878 if ((rule->uid_flags & MDF_ANY) != 0)
1879 return (0);
1880
1881 error = rule_grant_user(rule, old_cred, new_cred->cr_uid);
1882 if (error != 0)
1883 return (error);
1884 error = rule_grant_user(rule, old_cred, new_cred->cr_ruid);
1885 if (error != 0)
1886 return (error);
1887 error = rule_grant_user(rule, old_cred, new_cred->cr_svuid);
1888 if (error != 0)
1889 return (error);
1890
1891 return (0);
1892 }
1893
1894 static int
rule_grant_setcred(const struct rule * const rule,const struct ucred * const old_cred,const struct ucred * const new_cred)1895 rule_grant_setcred(const struct rule *const rule,
1896 const struct ucred *const old_cred, const struct ucred *const new_cred)
1897 {
1898 int error;
1899
1900 error = rule_grant_users(rule, old_cred, new_cred);
1901 if (error != 0)
1902 return (error);
1903 error = rule_grant_primary_groups(rule, old_cred, new_cred);
1904 if (error != 0)
1905 return (error);
1906 error = rule_grant_supplementary_groups(rule, old_cred, new_cred);
1907 if (error != 0)
1908 return (error);
1909
1910 return (0);
1911 }
1912
1913 static bool
rule_applies(const struct rule * const rule,const struct ucred * const cred)1914 rule_applies(const struct rule *const rule, const struct ucred *const cred)
1915 {
1916 if (rule->from_type == IT_UID && rule->from_id == cred->cr_ruid)
1917 return (true);
1918 if (rule->from_type == IT_GID && realgroupmember(rule->from_id, cred))
1919 return (true);
1920 return (false);
1921 }
1922
1923 /*
1924 * To pass data between check_setcred() and priv_grant() (on PRIV_CRED_SETCRED).
1925 */
1926 struct mac_do_setcred_data {
1927 struct mac_do_data_header hdr;
1928 const struct ucred *new_cred;
1929 u_int setcred_flags;
1930 };
1931
1932 static int
mac_do_priv_grant(struct ucred * cred,int priv)1933 mac_do_priv_grant(struct ucred *cred, int priv)
1934 {
1935 struct mac_do_setcred_data *const data = fetch_data();
1936 const struct rules *rules;
1937 const struct ucred *new_cred;
1938 const struct rule *rule;
1939 u_int setcred_flags;
1940 int error;
1941
1942 /* Bail out fast if we aren't concerned. */
1943 if (priv != PRIV_CRED_SETCRED)
1944 return (EPERM);
1945
1946 /*
1947 * Do we have to do something?
1948 */
1949 if (check_data_usable(data, sizeof(*data), priv) != 0)
1950 /* No. */
1951 return (EPERM);
1952
1953 rules = data->hdr.rules;
1954 new_cred = data->new_cred;
1955 KASSERT(new_cred != NULL,
1956 ("priv_check*() called before mac_cred_check_setcred()"));
1957 setcred_flags = data->setcred_flags;
1958
1959 /*
1960 * Explicitly check that only the flags we currently support are present
1961 * in order to avoid accepting transitions with other changes than those
1962 * we are actually going to check. Currently, this rules out the
1963 * SETCREDF_MAC_LABEL flag. This may be improved by adding code
1964 * actually checking whether the requested label and the current one
1965 * would differ.
1966 */
1967 if ((setcred_flags & ~(SETCREDF_UID | SETCREDF_RUID | SETCREDF_SVUID |
1968 SETCREDF_GID | SETCREDF_RGID | SETCREDF_SVGID |
1969 SETCREDF_SUPP_GROUPS)) != 0)
1970 return (EPERM);
1971
1972 /*
1973 * Browse rules, and for those that match the requestor, call specific
1974 * privilege granting functions interpreting the "to"/"target" part.
1975 */
1976 error = EPERM;
1977 STAILQ_FOREACH(rule, &rules->head, r_entries)
1978 if (rule_applies(rule, cred)) {
1979 error = rule_grant_setcred(rule, cred, new_cred);
1980 if (error != EPERM)
1981 break;
1982 }
1983
1984 return (error);
1985 }
1986
1987 static int
check_proc(void)1988 check_proc(void)
1989 {
1990 char *path, *to_free;
1991 int error;
1992
1993 /*
1994 * Only grant privileges if requested by the right executable.
1995 *
1996 * As MAC/do configuration is per-jail, in order to avoid confused
1997 * deputy situations in chroots (privileged or unprivileged), make sure
1998 * to check the path from the current jail's root.
1999 *
2000 * XXXOC: We may want to base this check on a tunable path and/or
2001 * a specific MAC label. Going even further, e.g., envisioning to
2002 * completely replace the path check with the latter, we would need to
2003 * install FreeBSD on a FS with multilabel enabled by default, which in
2004 * practice entails adding an option to ZFS to set MNT_MULTILABEL
2005 * automatically on mounts, ensuring that root (and more if using
2006 * different partitions) ZFS or UFS filesystems are created with
2007 * multilabel turned on, and having the installation procedure support
2008 * setting a MAC label per file (perhaps via additions to mtree(1)). So
2009 * this probably isn't going to happen overnight, if ever.
2010 */
2011 if (vn_fullpath_jail(curproc->p_textvp, &path, &to_free) != 0)
2012 return (EPERM);
2013 error = strcmp(path, "/usr/bin/mdo") == 0 ? 0 : EPERM;
2014 free(to_free, M_TEMP);
2015 return (error);
2016 }
2017
2018 static void
mac_do_setcred_enter(void)2019 mac_do_setcred_enter(void)
2020 {
2021 struct rules *rules;
2022 struct prison *pr;
2023 struct mac_do_setcred_data * data;
2024 int error;
2025
2026 /*
2027 * If not enabled, don't prepare data. Other hooks will check for that
2028 * to know if they have to do something.
2029 */
2030 if (do_enabled == 0)
2031 return;
2032
2033 /*
2034 * MAC/do only applies to a process launched from a given executable.
2035 * For other processes, we just won't intervene (we don't deny requests,
2036 * nor do we grant privileges to them).
2037 */
2038 error = check_proc();
2039 if (error != 0)
2040 return;
2041
2042 /*
2043 * Find the currently applicable rules.
2044 */
2045 rules = find_rules(curproc->p_ucred->cr_prison, &pr);
2046 hold_rules(rules);
2047 prison_unlock(pr);
2048
2049 /*
2050 * Setup thread data to be used by other hooks.
2051 */
2052 data = fetch_data();
2053 if (!is_data_reusable(data, sizeof(*data)))
2054 data = alloc_data(data, sizeof(*data));
2055 set_data_header(data, sizeof(*data), PRIV_CRED_SETCRED, rules);
2056 /* Not really necessary, but helps to catch programming errors. */
2057 data->new_cred = NULL;
2058 data->setcred_flags = 0;
2059 }
2060
2061 static int
mac_do_check_setcred(u_int flags,const struct ucred * const old_cred,struct ucred * const new_cred)2062 mac_do_check_setcred(u_int flags, const struct ucred *const old_cred,
2063 struct ucred *const new_cred)
2064 {
2065 struct mac_do_setcred_data *const data = fetch_data();
2066
2067 /*
2068 * Do we have to do something?
2069 */
2070 if (check_data_usable(data, sizeof(*data), PRIV_CRED_SETCRED) != 0)
2071 /* No. */
2072 return (0);
2073
2074 /*
2075 * Keep track of the setcred() flags and the new credentials for
2076 * priv_check*().
2077 */
2078 data->new_cred = new_cred;
2079 data->setcred_flags = flags;
2080
2081 return (0);
2082 }
2083
2084 static void
mac_do_setcred_exit(void)2085 mac_do_setcred_exit(void)
2086 {
2087 struct mac_do_setcred_data *const data = fetch_data();
2088
2089 if (check_data_usable(data, sizeof(*data), PRIV_CRED_SETCRED) == 0)
2090 /*
2091 * This doesn't deallocate the small per-thread data storage,
2092 * which can be reused on subsequent calls. (That data is of
2093 * course deallocated as the current thread dies or this module
2094 * is unloaded.)
2095 */
2096 clear_data(data);
2097 }
2098
2099 static void
mac_do_init(struct mac_policy_conf * mpc)2100 mac_do_init(struct mac_policy_conf *mpc)
2101 {
2102 struct prison *pr;
2103
2104 osd_jail_slot = osd_jail_register(dealloc_jail_osd, osd_methods);
2105 set_empty_rules(&prison0);
2106 sx_slock(&allprison_lock);
2107 TAILQ_FOREACH(pr, &allprison, pr_list)
2108 set_empty_rules(pr);
2109 sx_sunlock(&allprison_lock);
2110
2111 osd_thread_slot = osd_thread_register(dealloc_thread_osd);
2112 }
2113
2114 static void
mac_do_destroy(struct mac_policy_conf * mpc)2115 mac_do_destroy(struct mac_policy_conf *mpc)
2116 {
2117 /*
2118 * osd_thread_deregister() must be called before osd_jail_deregister(),
2119 * for the reason explained in dealloc_jail_osd().
2120 */
2121 osd_thread_deregister(osd_thread_slot);
2122 osd_jail_deregister(osd_jail_slot);
2123 }
2124
2125 static struct mac_policy_ops do_ops = {
2126 .mpo_init = mac_do_init,
2127 .mpo_destroy = mac_do_destroy,
2128 .mpo_cred_setcred_enter = mac_do_setcred_enter,
2129 .mpo_cred_check_setcred = mac_do_check_setcred,
2130 .mpo_cred_setcred_exit = mac_do_setcred_exit,
2131 .mpo_priv_grant = mac_do_priv_grant,
2132 };
2133
2134 MAC_POLICY_SET(&do_ops, mac_do, "MAC/do", MPC_LOADTIME_FLAG_UNLOADOK, NULL);
2135 MODULE_VERSION(mac_do, 1);
2136