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