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