1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AppArmor security module 4 * 5 * This file contains AppArmor policy attachment and domain transitions 6 * 7 * Copyright (C) 2002-2008 Novell/SUSE 8 * Copyright 2009-2010 Canonical Ltd. 9 */ 10 11 #include <linux/errno.h> 12 #include <linux/fdtable.h> 13 #include <linux/fs.h> 14 #include <linux/file.h> 15 #include <linux/mount.h> 16 #include <linux/syscalls.h> 17 #include <linux/personality.h> 18 #include <linux/xattr.h> 19 #include <linux/user_namespace.h> 20 21 #include "include/audit.h" 22 #include "include/apparmorfs.h" 23 #include "include/cred.h" 24 #include "include/domain.h" 25 #include "include/file.h" 26 #include "include/ipc.h" 27 #include "include/match.h" 28 #include "include/path.h" 29 #include "include/policy.h" 30 #include "include/policy_ns.h" 31 32 /** 33 * may_change_ptraced_domain - check if can change profile on ptraced task 34 * @to_label: profile to change to (NOT NULL) 35 * @info: message if there is an error 36 * 37 * Check if current is ptraced and if so if the tracing task is allowed 38 * to trace the new domain 39 * 40 * Returns: %0 or error if change not allowed 41 */ 42 static int may_change_ptraced_domain(struct aa_label *to_label, 43 const char **info) 44 { 45 struct task_struct *tracer; 46 struct aa_label *tracerl = NULL; 47 int error = 0; 48 49 rcu_read_lock(); 50 tracer = ptrace_parent(current); 51 if (tracer) 52 /* released below */ 53 tracerl = aa_get_task_label(tracer); 54 55 /* not ptraced */ 56 if (!tracer || unconfined(tracerl)) 57 goto out; 58 59 error = aa_may_ptrace(tracerl, to_label, PTRACE_MODE_ATTACH); 60 61 out: 62 rcu_read_unlock(); 63 aa_put_label(tracerl); 64 65 if (error) 66 *info = "ptrace prevents transition"; 67 return error; 68 } 69 70 /**** TODO: dedup to aa_label_match - needs perm and dfa, merging 71 * specifically this is an exact copy of aa_label_match except 72 * aa_compute_perms is replaced with aa_compute_fperms 73 * and policy.dfa with file.dfa 74 ****/ 75 /* match a profile and its associated ns component if needed 76 * Assumes visibility test has already been done. 77 * If a subns profile is not to be matched should be prescreened with 78 * visibility test. 79 */ 80 static inline aa_state_t match_component(struct aa_profile *profile, 81 struct aa_profile *tp, 82 bool stack, aa_state_t state) 83 { 84 struct aa_ruleset *rules = list_first_entry(&profile->rules, 85 typeof(*rules), list); 86 const char *ns_name; 87 88 if (stack) 89 state = aa_dfa_match(rules->file.dfa, state, "&"); 90 if (profile->ns == tp->ns) 91 return aa_dfa_match(rules->file.dfa, state, tp->base.hname); 92 93 /* try matching with namespace name and then profile */ 94 ns_name = aa_ns_name(profile->ns, tp->ns, true); 95 state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); 96 state = aa_dfa_match(rules->file.dfa, state, ns_name); 97 state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); 98 return aa_dfa_match(rules->file.dfa, state, tp->base.hname); 99 } 100 101 /** 102 * label_compound_match - find perms for full compound label 103 * @profile: profile to find perms for 104 * @label: label to check access permissions for 105 * @stack: whether this is a stacking request 106 * @state: state to start match in 107 * @subns: whether to do permission checks on components in a subns 108 * @request: permissions to request 109 * @perms: perms struct to set 110 * 111 * Returns: 0 on success else ERROR 112 * 113 * For the label A//&B//&C this does the perm match for A//&B//&C 114 * @perms should be preinitialized with allperms OR a previous permission 115 * check to be stacked. 116 */ 117 static int label_compound_match(struct aa_profile *profile, 118 struct aa_label *label, bool stack, 119 aa_state_t state, bool subns, u32 request, 120 struct aa_perms *perms) 121 { 122 struct aa_ruleset *rules = list_first_entry(&profile->rules, 123 typeof(*rules), list); 124 struct aa_profile *tp; 125 struct label_it i; 126 struct path_cond cond = { }; 127 128 /* find first subcomponent that is visible */ 129 label_for_each(i, label, tp) { 130 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 131 continue; 132 state = match_component(profile, tp, stack, state); 133 if (!state) 134 goto fail; 135 goto next; 136 } 137 138 /* no component visible */ 139 *perms = allperms; 140 return 0; 141 142 next: 143 label_for_each_cont(i, label, tp) { 144 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 145 continue; 146 state = aa_dfa_match(rules->file.dfa, state, "//&"); 147 state = match_component(profile, tp, false, state); 148 if (!state) 149 goto fail; 150 } 151 *perms = *(aa_lookup_fperms(&(rules->file), state, &cond)); 152 aa_apply_modes_to_perms(profile, perms); 153 if ((perms->allow & request) != request) 154 return -EACCES; 155 156 return 0; 157 158 fail: 159 *perms = nullperms; 160 return -EACCES; 161 } 162 163 /** 164 * label_components_match - find perms for all subcomponents of a label 165 * @profile: profile to find perms for 166 * @label: label to check access permissions for 167 * @stack: whether this is a stacking request 168 * @start: state to start match in 169 * @subns: whether to do permission checks on components in a subns 170 * @request: permissions to request 171 * @perms: an initialized perms struct to add accumulation to 172 * 173 * Returns: 0 on success else ERROR 174 * 175 * For the label A//&B//&C this does the perm match for each of A and B and C 176 * @perms should be preinitialized with allperms OR a previous permission 177 * check to be stacked. 178 */ 179 static int label_components_match(struct aa_profile *profile, 180 struct aa_label *label, bool stack, 181 aa_state_t start, bool subns, u32 request, 182 struct aa_perms *perms) 183 { 184 struct aa_ruleset *rules = list_first_entry(&profile->rules, 185 typeof(*rules), list); 186 struct aa_profile *tp; 187 struct label_it i; 188 struct aa_perms tmp; 189 struct path_cond cond = { }; 190 aa_state_t state = 0; 191 192 /* find first subcomponent to test */ 193 label_for_each(i, label, tp) { 194 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 195 continue; 196 state = match_component(profile, tp, stack, start); 197 if (!state) 198 goto fail; 199 goto next; 200 } 201 202 /* no subcomponents visible - no change in perms */ 203 return 0; 204 205 next: 206 tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 207 aa_apply_modes_to_perms(profile, &tmp); 208 aa_perms_accum(perms, &tmp); 209 label_for_each_cont(i, label, tp) { 210 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 211 continue; 212 state = match_component(profile, tp, stack, start); 213 if (!state) 214 goto fail; 215 tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 216 aa_apply_modes_to_perms(profile, &tmp); 217 aa_perms_accum(perms, &tmp); 218 } 219 220 if ((perms->allow & request) != request) 221 return -EACCES; 222 223 return 0; 224 225 fail: 226 *perms = nullperms; 227 return -EACCES; 228 } 229 230 /** 231 * label_match - do a multi-component label match 232 * @profile: profile to match against (NOT NULL) 233 * @label: label to match (NOT NULL) 234 * @stack: whether this is a stacking request 235 * @state: state to start in 236 * @subns: whether to match subns components 237 * @request: permission request 238 * @perms: Returns computed perms (NOT NULL) 239 * 240 * Returns: the state the match finished in, may be the none matching state 241 */ 242 static int label_match(struct aa_profile *profile, struct aa_label *label, 243 bool stack, aa_state_t state, bool subns, u32 request, 244 struct aa_perms *perms) 245 { 246 int error; 247 248 *perms = nullperms; 249 error = label_compound_match(profile, label, stack, state, subns, 250 request, perms); 251 if (!error) 252 return error; 253 254 *perms = allperms; 255 return label_components_match(profile, label, stack, state, subns, 256 request, perms); 257 } 258 259 /******* end TODO: dedup *****/ 260 261 /** 262 * change_profile_perms - find permissions for change_profile 263 * @profile: the current profile (NOT NULL) 264 * @target: label to transition to (NOT NULL) 265 * @stack: whether this is a stacking request 266 * @request: requested perms 267 * @start: state to start matching in 268 * 269 * 270 * Returns: permission set 271 * 272 * currently only matches full label A//&B//&C or individual components A, B, C 273 * not arbitrary combinations. Eg. A//&B, C 274 */ 275 static int change_profile_perms(struct aa_profile *profile, 276 struct aa_label *target, bool stack, 277 u32 request, aa_state_t start, 278 struct aa_perms *perms) 279 { 280 if (profile_unconfined(profile)) { 281 perms->allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC; 282 perms->audit = perms->quiet = perms->kill = 0; 283 return 0; 284 } 285 286 /* TODO: add profile in ns screening */ 287 return label_match(profile, target, stack, start, true, request, perms); 288 } 289 290 /** 291 * aa_xattrs_match - check whether a file matches the xattrs defined in profile 292 * @bprm: binprm struct for the process to validate 293 * @profile: profile to match against (NOT NULL) 294 * @state: state to start match in 295 * 296 * Returns: number of extended attributes that matched, or < 0 on error 297 */ 298 static int aa_xattrs_match(const struct linux_binprm *bprm, 299 struct aa_profile *profile, aa_state_t state) 300 { 301 int i; 302 struct dentry *d; 303 char *value = NULL; 304 struct aa_attachment *attach = &profile->attach; 305 int size, value_size = 0, ret = attach->xattr_count; 306 307 if (!bprm || !attach->xattr_count) 308 return 0; 309 might_sleep(); 310 311 /* transition from exec match to xattr set */ 312 state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); 313 d = bprm->file->f_path.dentry; 314 315 for (i = 0; i < attach->xattr_count; i++) { 316 size = vfs_getxattr_alloc(&init_user_ns, d, attach->xattrs[i], 317 &value, value_size, GFP_KERNEL); 318 if (size >= 0) { 319 u32 index, perm; 320 321 /* 322 * Check the xattr presence before value. This ensure 323 * that not present xattr can be distinguished from a 0 324 * length value or rule that matches any value 325 */ 326 state = aa_dfa_null_transition(attach->xmatch.dfa, 327 state); 328 /* Check xattr value */ 329 state = aa_dfa_match_len(attach->xmatch.dfa, state, 330 value, size); 331 index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; 332 perm = attach->xmatch.perms[index].allow; 333 if (!(perm & MAY_EXEC)) { 334 ret = -EINVAL; 335 goto out; 336 } 337 } 338 /* transition to next element */ 339 state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); 340 if (size < 0) { 341 /* 342 * No xattr match, so verify if transition to 343 * next element was valid. IFF so the xattr 344 * was optional. 345 */ 346 if (!state) { 347 ret = -EINVAL; 348 goto out; 349 } 350 /* don't count missing optional xattr as matched */ 351 ret--; 352 } 353 } 354 355 out: 356 kfree(value); 357 return ret; 358 } 359 360 /** 361 * find_attach - do attachment search for unconfined processes 362 * @bprm - binprm structure of transitioning task 363 * @ns: the current namespace (NOT NULL) 364 * @head - profile list to walk (NOT NULL) 365 * @name - to match against (NOT NULL) 366 * @info - info message if there was an error (NOT NULL) 367 * 368 * Do a linear search on the profiles in the list. There is a matching 369 * preference where an exact match is preferred over a name which uses 370 * expressions to match, and matching expressions with the greatest 371 * xmatch_len are preferred. 372 * 373 * Requires: @head not be shared or have appropriate locks held 374 * 375 * Returns: label or NULL if no match found 376 */ 377 static struct aa_label *find_attach(const struct linux_binprm *bprm, 378 struct aa_ns *ns, struct list_head *head, 379 const char *name, const char **info) 380 { 381 int candidate_len = 0, candidate_xattrs = 0; 382 bool conflict = false; 383 struct aa_profile *profile, *candidate = NULL; 384 385 AA_BUG(!name); 386 AA_BUG(!head); 387 388 rcu_read_lock(); 389 restart: 390 list_for_each_entry_rcu(profile, head, base.list) { 391 struct aa_attachment *attach = &profile->attach; 392 393 if (profile->label.flags & FLAG_NULL && 394 &profile->label == ns_unconfined(profile->ns)) 395 continue; 396 397 /* Find the "best" matching profile. Profiles must 398 * match the path and extended attributes (if any) 399 * associated with the file. A more specific path 400 * match will be preferred over a less specific one, 401 * and a match with more matching extended attributes 402 * will be preferred over one with fewer. If the best 403 * match has both the same level of path specificity 404 * and the same number of matching extended attributes 405 * as another profile, signal a conflict and refuse to 406 * match. 407 */ 408 if (attach->xmatch.dfa) { 409 unsigned int count; 410 aa_state_t state; 411 u32 index, perm; 412 413 state = aa_dfa_leftmatch(attach->xmatch.dfa, 414 attach->xmatch.start[AA_CLASS_XMATCH], 415 name, &count); 416 index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; 417 perm = attach->xmatch.perms[index].allow; 418 /* any accepting state means a valid match. */ 419 if (perm & MAY_EXEC) { 420 int ret = 0; 421 422 if (count < candidate_len) 423 continue; 424 425 if (bprm && attach->xattr_count) { 426 long rev = READ_ONCE(ns->revision); 427 428 if (!aa_get_profile_not0(profile)) 429 goto restart; 430 rcu_read_unlock(); 431 ret = aa_xattrs_match(bprm, profile, 432 state); 433 rcu_read_lock(); 434 aa_put_profile(profile); 435 if (rev != 436 READ_ONCE(ns->revision)) 437 /* policy changed */ 438 goto restart; 439 /* 440 * Fail matching if the xattrs don't 441 * match 442 */ 443 if (ret < 0) 444 continue; 445 } 446 /* 447 * TODO: allow for more flexible best match 448 * 449 * The new match isn't more specific 450 * than the current best match 451 */ 452 if (count == candidate_len && 453 ret <= candidate_xattrs) { 454 /* Match is equivalent, so conflict */ 455 if (ret == candidate_xattrs) 456 conflict = true; 457 continue; 458 } 459 460 /* Either the same length with more matching 461 * xattrs, or a longer match 462 */ 463 candidate = profile; 464 candidate_len = max(count, attach->xmatch_len); 465 candidate_xattrs = ret; 466 conflict = false; 467 } 468 } else if (!strcmp(profile->base.name, name)) { 469 /* 470 * old exact non-re match, without conditionals such 471 * as xattrs. no more searching required 472 */ 473 candidate = profile; 474 goto out; 475 } 476 } 477 478 if (!candidate || conflict) { 479 if (conflict) 480 *info = "conflicting profile attachments"; 481 rcu_read_unlock(); 482 return NULL; 483 } 484 485 out: 486 candidate = aa_get_newest_profile(candidate); 487 rcu_read_unlock(); 488 489 return &candidate->label; 490 } 491 492 static const char *next_name(int xtype, const char *name) 493 { 494 return NULL; 495 } 496 497 /** 498 * x_table_lookup - lookup an x transition name via transition table 499 * @profile: current profile (NOT NULL) 500 * @xindex: index into x transition table 501 * @name: returns: name tested to find label (NOT NULL) 502 * 503 * Returns: refcounted label, or NULL on failure (MAYBE NULL) 504 */ 505 struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, 506 const char **name) 507 { 508 struct aa_ruleset *rules = list_first_entry(&profile->rules, 509 typeof(*rules), list); 510 struct aa_label *label = NULL; 511 u32 xtype = xindex & AA_X_TYPE_MASK; 512 int index = xindex & AA_X_INDEX_MASK; 513 514 AA_BUG(!name); 515 516 /* index is guaranteed to be in range, validated at load time */ 517 /* TODO: move lookup parsing to unpack time so this is a straight 518 * index into the resultant label 519 */ 520 for (*name = rules->file.trans.table[index]; !label && *name; 521 *name = next_name(xtype, *name)) { 522 if (xindex & AA_X_CHILD) { 523 struct aa_profile *new_profile; 524 /* release by caller */ 525 new_profile = aa_find_child(profile, *name); 526 if (new_profile) 527 label = &new_profile->label; 528 continue; 529 } 530 label = aa_label_parse(&profile->label, *name, GFP_KERNEL, 531 true, false); 532 if (IS_ERR(label)) 533 label = NULL; 534 } 535 536 /* released by caller */ 537 538 return label; 539 } 540 541 /** 542 * x_to_label - get target label for a given xindex 543 * @profile: current profile (NOT NULL) 544 * @bprm: binprm structure of transitioning task 545 * @name: name to lookup (NOT NULL) 546 * @xindex: index into x transition table 547 * @lookupname: returns: name used in lookup if one was specified (NOT NULL) 548 * 549 * find label for a transition index 550 * 551 * Returns: refcounted label or NULL if not found available 552 */ 553 static struct aa_label *x_to_label(struct aa_profile *profile, 554 const struct linux_binprm *bprm, 555 const char *name, u32 xindex, 556 const char **lookupname, 557 const char **info) 558 { 559 struct aa_ruleset *rules = list_first_entry(&profile->rules, 560 typeof(*rules), list); 561 struct aa_label *new = NULL; 562 struct aa_ns *ns = profile->ns; 563 u32 xtype = xindex & AA_X_TYPE_MASK; 564 const char *stack = NULL; 565 566 switch (xtype) { 567 case AA_X_NONE: 568 /* fail exec unless ix || ux fallback - handled by caller */ 569 *lookupname = NULL; 570 break; 571 case AA_X_TABLE: 572 /* TODO: fix when perm mapping done at unload */ 573 stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK]; 574 if (*stack != '&') { 575 /* released by caller */ 576 new = x_table_lookup(profile, xindex, lookupname); 577 stack = NULL; 578 break; 579 } 580 fallthrough; /* to X_NAME */ 581 case AA_X_NAME: 582 if (xindex & AA_X_CHILD) 583 /* released by caller */ 584 new = find_attach(bprm, ns, &profile->base.profiles, 585 name, info); 586 else 587 /* released by caller */ 588 new = find_attach(bprm, ns, &ns->base.profiles, 589 name, info); 590 *lookupname = name; 591 break; 592 } 593 594 if (!new) { 595 if (xindex & AA_X_INHERIT) { 596 /* (p|c|n)ix - don't change profile but do 597 * use the newest version 598 */ 599 *info = "ix fallback"; 600 /* no profile && no error */ 601 new = aa_get_newest_label(&profile->label); 602 } else if (xindex & AA_X_UNCONFINED) { 603 new = aa_get_newest_label(ns_unconfined(profile->ns)); 604 *info = "ux fallback"; 605 } 606 } 607 608 if (new && stack) { 609 /* base the stack on post domain transition */ 610 struct aa_label *base = new; 611 612 new = aa_label_parse(base, stack, GFP_KERNEL, true, false); 613 if (IS_ERR(new)) 614 new = NULL; 615 aa_put_label(base); 616 } 617 618 /* released by caller */ 619 return new; 620 } 621 622 static struct aa_label *profile_transition(struct aa_profile *profile, 623 const struct linux_binprm *bprm, 624 char *buffer, struct path_cond *cond, 625 bool *secure_exec) 626 { 627 struct aa_ruleset *rules = list_first_entry(&profile->rules, 628 typeof(*rules), list); 629 struct aa_label *new = NULL; 630 const char *info = NULL, *name = NULL, *target = NULL; 631 aa_state_t state = rules->file.start[AA_CLASS_FILE]; 632 struct aa_perms perms = {}; 633 bool nonewprivs = false; 634 int error = 0; 635 636 AA_BUG(!profile); 637 AA_BUG(!bprm); 638 AA_BUG(!buffer); 639 640 error = aa_path_name(&bprm->file->f_path, profile->path_flags, buffer, 641 &name, &info, profile->disconnected); 642 if (error) { 643 if (profile_unconfined(profile) || 644 (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) { 645 AA_DEBUG("name lookup ix on error"); 646 error = 0; 647 new = aa_get_newest_label(&profile->label); 648 } 649 name = bprm->filename; 650 goto audit; 651 } 652 653 if (profile_unconfined(profile)) { 654 new = find_attach(bprm, profile->ns, 655 &profile->ns->base.profiles, name, &info); 656 if (new) { 657 AA_DEBUG("unconfined attached to new label"); 658 return new; 659 } 660 AA_DEBUG("unconfined exec no attachment"); 661 return aa_get_newest_label(&profile->label); 662 } 663 664 /* find exec permissions for name */ 665 state = aa_str_perms(&(rules->file), state, name, cond, &perms); 666 if (perms.allow & MAY_EXEC) { 667 /* exec permission determine how to transition */ 668 new = x_to_label(profile, bprm, name, perms.xindex, &target, 669 &info); 670 if (new && new->proxy == profile->label.proxy && info) { 671 /* hack ix fallback - improve how this is detected */ 672 goto audit; 673 } else if (!new) { 674 error = -EACCES; 675 info = "profile transition not found"; 676 /* remove MAY_EXEC to audit as failure */ 677 perms.allow &= ~MAY_EXEC; 678 } 679 } else if (COMPLAIN_MODE(profile)) { 680 /* no exec permission - learning mode */ 681 struct aa_profile *new_profile = NULL; 682 683 new_profile = aa_new_learning_profile(profile, false, name, 684 GFP_KERNEL); 685 if (!new_profile) { 686 error = -ENOMEM; 687 info = "could not create null profile"; 688 } else { 689 error = -EACCES; 690 new = &new_profile->label; 691 } 692 perms.xindex |= AA_X_UNSAFE; 693 } else 694 /* fail exec */ 695 error = -EACCES; 696 697 if (!new) 698 goto audit; 699 700 701 if (!(perms.xindex & AA_X_UNSAFE)) { 702 if (DEBUG_ON) { 703 dbg_printk("apparmor: scrubbing environment variables" 704 " for %s profile=", name); 705 aa_label_printk(new, GFP_KERNEL); 706 dbg_printk("\n"); 707 } 708 *secure_exec = true; 709 } 710 711 audit: 712 aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, target, new, 713 cond->uid, info, error); 714 if (!new || nonewprivs) { 715 aa_put_label(new); 716 return ERR_PTR(error); 717 } 718 719 return new; 720 } 721 722 static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec, 723 bool stack, const struct linux_binprm *bprm, 724 char *buffer, struct path_cond *cond, 725 bool *secure_exec) 726 { 727 struct aa_ruleset *rules = list_first_entry(&profile->rules, 728 typeof(*rules), list); 729 aa_state_t state = rules->file.start[AA_CLASS_FILE]; 730 struct aa_perms perms = {}; 731 const char *xname = NULL, *info = "change_profile onexec"; 732 int error = -EACCES; 733 734 AA_BUG(!profile); 735 AA_BUG(!onexec); 736 AA_BUG(!bprm); 737 AA_BUG(!buffer); 738 739 if (profile_unconfined(profile)) { 740 /* change_profile on exec already granted */ 741 /* 742 * NOTE: Domain transitions from unconfined are allowed 743 * even when no_new_privs is set because this aways results 744 * in a further reduction of permissions. 745 */ 746 return 0; 747 } 748 749 error = aa_path_name(&bprm->file->f_path, profile->path_flags, buffer, 750 &xname, &info, profile->disconnected); 751 if (error) { 752 if (profile_unconfined(profile) || 753 (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) { 754 AA_DEBUG("name lookup ix on error"); 755 error = 0; 756 } 757 xname = bprm->filename; 758 goto audit; 759 } 760 761 /* find exec permissions for name */ 762 state = aa_str_perms(&(rules->file), state, xname, cond, &perms); 763 if (!(perms.allow & AA_MAY_ONEXEC)) { 764 info = "no change_onexec valid for executable"; 765 goto audit; 766 } 767 /* test if this exec can be paired with change_profile onexec. 768 * onexec permission is linked to exec with a standard pairing 769 * exec\0change_profile 770 */ 771 state = aa_dfa_null_transition(rules->file.dfa, state); 772 error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC, 773 state, &perms); 774 if (error) { 775 perms.allow &= ~AA_MAY_ONEXEC; 776 goto audit; 777 } 778 779 if (!(perms.xindex & AA_X_UNSAFE)) { 780 if (DEBUG_ON) { 781 dbg_printk("apparmor: scrubbing environment " 782 "variables for %s label=", xname); 783 aa_label_printk(onexec, GFP_KERNEL); 784 dbg_printk("\n"); 785 } 786 *secure_exec = true; 787 } 788 789 audit: 790 return aa_audit_file(profile, &perms, OP_EXEC, AA_MAY_ONEXEC, xname, 791 NULL, onexec, cond->uid, info, error); 792 } 793 794 /* ensure none ns domain transitions are correctly applied with onexec */ 795 796 static struct aa_label *handle_onexec(struct aa_label *label, 797 struct aa_label *onexec, bool stack, 798 const struct linux_binprm *bprm, 799 char *buffer, struct path_cond *cond, 800 bool *unsafe) 801 { 802 struct aa_profile *profile; 803 struct aa_label *new; 804 int error; 805 806 AA_BUG(!label); 807 AA_BUG(!onexec); 808 AA_BUG(!bprm); 809 AA_BUG(!buffer); 810 811 if (!stack) { 812 error = fn_for_each_in_ns(label, profile, 813 profile_onexec(profile, onexec, stack, 814 bprm, buffer, cond, unsafe)); 815 if (error) 816 return ERR_PTR(error); 817 new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 818 aa_get_newest_label(onexec), 819 profile_transition(profile, bprm, buffer, 820 cond, unsafe)); 821 822 } else { 823 /* TODO: determine how much we want to loosen this */ 824 error = fn_for_each_in_ns(label, profile, 825 profile_onexec(profile, onexec, stack, bprm, 826 buffer, cond, unsafe)); 827 if (error) 828 return ERR_PTR(error); 829 new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 830 aa_label_merge(&profile->label, onexec, 831 GFP_KERNEL), 832 profile_transition(profile, bprm, buffer, 833 cond, unsafe)); 834 } 835 836 if (new) 837 return new; 838 839 /* TODO: get rid of GLOBAL_ROOT_UID */ 840 error = fn_for_each_in_ns(label, profile, 841 aa_audit_file(profile, &nullperms, OP_CHANGE_ONEXEC, 842 AA_MAY_ONEXEC, bprm->filename, NULL, 843 onexec, GLOBAL_ROOT_UID, 844 "failed to build target label", -ENOMEM)); 845 return ERR_PTR(error); 846 } 847 848 /** 849 * apparmor_bprm_creds_for_exec - Update the new creds on the bprm struct 850 * @bprm: binprm for the exec (NOT NULL) 851 * 852 * Returns: %0 or error on failure 853 * 854 * TODO: once the other paths are done see if we can't refactor into a fn 855 */ 856 int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) 857 { 858 struct aa_task_ctx *ctx; 859 struct aa_label *label, *new = NULL; 860 struct aa_profile *profile; 861 char *buffer = NULL; 862 const char *info = NULL; 863 int error = 0; 864 bool unsafe = false; 865 vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(bprm->file), 866 file_inode(bprm->file)); 867 struct path_cond cond = { 868 vfsuid_into_kuid(vfsuid), 869 file_inode(bprm->file)->i_mode 870 }; 871 872 ctx = task_ctx(current); 873 AA_BUG(!cred_label(bprm->cred)); 874 AA_BUG(!ctx); 875 876 label = aa_get_newest_label(cred_label(bprm->cred)); 877 878 /* 879 * Detect no new privs being set, and store the label it 880 * occurred under. Ideally this would happen when nnp 881 * is set but there isn't a good way to do that yet. 882 * 883 * Testing for unconfined must be done before the subset test 884 */ 885 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && !unconfined(label) && 886 !ctx->nnp) 887 ctx->nnp = aa_get_label(label); 888 889 /* buffer freed below, name is pointer into buffer */ 890 buffer = aa_get_buffer(false); 891 if (!buffer) { 892 error = -ENOMEM; 893 goto done; 894 } 895 896 /* Test for onexec first as onexec override other x transitions. */ 897 if (ctx->onexec) 898 new = handle_onexec(label, ctx->onexec, ctx->token, 899 bprm, buffer, &cond, &unsafe); 900 else 901 new = fn_label_build(label, profile, GFP_KERNEL, 902 profile_transition(profile, bprm, buffer, 903 &cond, &unsafe)); 904 905 AA_BUG(!new); 906 if (IS_ERR(new)) { 907 error = PTR_ERR(new); 908 goto done; 909 } else if (!new) { 910 error = -ENOMEM; 911 goto done; 912 } 913 914 /* Policy has specified a domain transitions. If no_new_privs and 915 * confined ensure the transition is to confinement that is subset 916 * of the confinement when the task entered no new privs. 917 * 918 * NOTE: Domain transitions from unconfined and to stacked 919 * subsets are allowed even when no_new_privs is set because this 920 * aways results in a further reduction of permissions. 921 */ 922 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && 923 !unconfined(label) && 924 !aa_label_is_unconfined_subset(new, ctx->nnp)) { 925 error = -EPERM; 926 info = "no new privs"; 927 goto audit; 928 } 929 930 if (bprm->unsafe & LSM_UNSAFE_SHARE) { 931 /* FIXME: currently don't mediate shared state */ 932 ; 933 } 934 935 if (bprm->unsafe & (LSM_UNSAFE_PTRACE)) { 936 /* TODO: test needs to be profile of label to new */ 937 error = may_change_ptraced_domain(new, &info); 938 if (error) 939 goto audit; 940 } 941 942 if (unsafe) { 943 if (DEBUG_ON) { 944 dbg_printk("scrubbing environment variables for %s " 945 "label=", bprm->filename); 946 aa_label_printk(new, GFP_KERNEL); 947 dbg_printk("\n"); 948 } 949 bprm->secureexec = 1; 950 } 951 952 if (label->proxy != new->proxy) { 953 /* when transitioning clear unsafe personality bits */ 954 if (DEBUG_ON) { 955 dbg_printk("apparmor: clearing unsafe personality " 956 "bits. %s label=", bprm->filename); 957 aa_label_printk(new, GFP_KERNEL); 958 dbg_printk("\n"); 959 } 960 bprm->per_clear |= PER_CLEAR_ON_SETID; 961 } 962 aa_put_label(cred_label(bprm->cred)); 963 /* transfer reference, released when cred is freed */ 964 set_cred_label(bprm->cred, new); 965 966 done: 967 aa_put_label(label); 968 aa_put_buffer(buffer); 969 970 return error; 971 972 audit: 973 error = fn_for_each(label, profile, 974 aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC, 975 bprm->filename, NULL, new, 976 vfsuid_into_kuid(vfsuid), info, error)); 977 aa_put_label(new); 978 goto done; 979 } 980 981 /* 982 * Functions for self directed profile change 983 */ 984 985 986 /* helper fn for change_hat 987 * 988 * Returns: label for hat transition OR ERR_PTR. Does NOT return NULL 989 */ 990 static struct aa_label *build_change_hat(struct aa_profile *profile, 991 const char *name, bool sibling) 992 { 993 struct aa_profile *root, *hat = NULL; 994 const char *info = NULL; 995 int error = 0; 996 997 if (sibling && PROFILE_IS_HAT(profile)) { 998 root = aa_get_profile_rcu(&profile->parent); 999 } else if (!sibling && !PROFILE_IS_HAT(profile)) { 1000 root = aa_get_profile(profile); 1001 } else { 1002 info = "conflicting target types"; 1003 error = -EPERM; 1004 goto audit; 1005 } 1006 1007 hat = aa_find_child(root, name); 1008 if (!hat) { 1009 error = -ENOENT; 1010 if (COMPLAIN_MODE(profile)) { 1011 hat = aa_new_learning_profile(profile, true, name, 1012 GFP_KERNEL); 1013 if (!hat) { 1014 info = "failed null profile create"; 1015 error = -ENOMEM; 1016 } 1017 } 1018 } 1019 aa_put_profile(root); 1020 1021 audit: 1022 aa_audit_file(profile, &nullperms, OP_CHANGE_HAT, AA_MAY_CHANGEHAT, 1023 name, hat ? hat->base.hname : NULL, 1024 hat ? &hat->label : NULL, GLOBAL_ROOT_UID, info, 1025 error); 1026 if (!hat || (error && error != -ENOENT)) 1027 return ERR_PTR(error); 1028 /* if hat && error - complain mode, already audited and we adjust for 1029 * complain mode allow by returning hat->label 1030 */ 1031 return &hat->label; 1032 } 1033 1034 /* helper fn for changing into a hat 1035 * 1036 * Returns: label for hat transition or ERR_PTR. Does not return NULL 1037 */ 1038 static struct aa_label *change_hat(struct aa_label *label, const char *hats[], 1039 int count, int flags) 1040 { 1041 struct aa_profile *profile, *root, *hat = NULL; 1042 struct aa_label *new; 1043 struct label_it it; 1044 bool sibling = false; 1045 const char *name, *info = NULL; 1046 int i, error; 1047 1048 AA_BUG(!label); 1049 AA_BUG(!hats); 1050 AA_BUG(count < 1); 1051 1052 if (PROFILE_IS_HAT(labels_profile(label))) 1053 sibling = true; 1054 1055 /*find first matching hat */ 1056 for (i = 0; i < count && !hat; i++) { 1057 name = hats[i]; 1058 label_for_each_in_ns(it, labels_ns(label), label, profile) { 1059 if (sibling && PROFILE_IS_HAT(profile)) { 1060 root = aa_get_profile_rcu(&profile->parent); 1061 } else if (!sibling && !PROFILE_IS_HAT(profile)) { 1062 root = aa_get_profile(profile); 1063 } else { /* conflicting change type */ 1064 info = "conflicting targets types"; 1065 error = -EPERM; 1066 goto fail; 1067 } 1068 hat = aa_find_child(root, name); 1069 aa_put_profile(root); 1070 if (!hat) { 1071 if (!COMPLAIN_MODE(profile)) 1072 goto outer_continue; 1073 /* complain mode succeed as if hat */ 1074 } else if (!PROFILE_IS_HAT(hat)) { 1075 info = "target not hat"; 1076 error = -EPERM; 1077 aa_put_profile(hat); 1078 goto fail; 1079 } 1080 aa_put_profile(hat); 1081 } 1082 /* found a hat for all profiles in ns */ 1083 goto build; 1084 outer_continue: 1085 ; 1086 } 1087 /* no hats that match, find appropriate error 1088 * 1089 * In complain mode audit of the failure is based off of the first 1090 * hat supplied. This is done due how userspace interacts with 1091 * change_hat. 1092 */ 1093 name = NULL; 1094 label_for_each_in_ns(it, labels_ns(label), label, profile) { 1095 if (!list_empty(&profile->base.profiles)) { 1096 info = "hat not found"; 1097 error = -ENOENT; 1098 goto fail; 1099 } 1100 } 1101 info = "no hats defined"; 1102 error = -ECHILD; 1103 1104 fail: 1105 label_for_each_in_ns(it, labels_ns(label), label, profile) { 1106 /* 1107 * no target as it has failed to be found or built 1108 * 1109 * change_hat uses probing and should not log failures 1110 * related to missing hats 1111 */ 1112 /* TODO: get rid of GLOBAL_ROOT_UID */ 1113 if (count > 1 || COMPLAIN_MODE(profile)) { 1114 aa_audit_file(profile, &nullperms, OP_CHANGE_HAT, 1115 AA_MAY_CHANGEHAT, name, NULL, NULL, 1116 GLOBAL_ROOT_UID, info, error); 1117 } 1118 } 1119 return ERR_PTR(error); 1120 1121 build: 1122 new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 1123 build_change_hat(profile, name, sibling), 1124 aa_get_label(&profile->label)); 1125 if (!new) { 1126 info = "label build failed"; 1127 error = -ENOMEM; 1128 goto fail; 1129 } /* else if (IS_ERR) build_change_hat has logged error so return new */ 1130 1131 return new; 1132 } 1133 1134 /** 1135 * aa_change_hat - change hat to/from subprofile 1136 * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0) 1137 * @count: number of hat names in @hats 1138 * @token: magic value to validate the hat change 1139 * @flags: flags affecting behavior of the change 1140 * 1141 * Returns %0 on success, error otherwise. 1142 * 1143 * Change to the first profile specified in @hats that exists, and store 1144 * the @hat_magic in the current task context. If the count == 0 and the 1145 * @token matches that stored in the current task context, return to the 1146 * top level profile. 1147 * 1148 * change_hat only applies to profiles in the current ns, and each profile 1149 * in the ns must make the same transition otherwise change_hat will fail. 1150 */ 1151 int aa_change_hat(const char *hats[], int count, u64 token, int flags) 1152 { 1153 const struct cred *cred; 1154 struct aa_task_ctx *ctx = task_ctx(current); 1155 struct aa_label *label, *previous, *new = NULL, *target = NULL; 1156 struct aa_profile *profile; 1157 struct aa_perms perms = {}; 1158 const char *info = NULL; 1159 int error = 0; 1160 1161 /* released below */ 1162 cred = get_current_cred(); 1163 label = aa_get_newest_cred_label(cred); 1164 previous = aa_get_newest_label(ctx->previous); 1165 1166 /* 1167 * Detect no new privs being set, and store the label it 1168 * occurred under. Ideally this would happen when nnp 1169 * is set but there isn't a good way to do that yet. 1170 * 1171 * Testing for unconfined must be done before the subset test 1172 */ 1173 if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp) 1174 ctx->nnp = aa_get_label(label); 1175 1176 if (unconfined(label)) { 1177 info = "unconfined can not change_hat"; 1178 error = -EPERM; 1179 goto fail; 1180 } 1181 1182 if (count) { 1183 new = change_hat(label, hats, count, flags); 1184 AA_BUG(!new); 1185 if (IS_ERR(new)) { 1186 error = PTR_ERR(new); 1187 new = NULL; 1188 /* already audited */ 1189 goto out; 1190 } 1191 1192 error = may_change_ptraced_domain(new, &info); 1193 if (error) 1194 goto fail; 1195 1196 /* 1197 * no new privs prevents domain transitions that would 1198 * reduce restrictions. 1199 */ 1200 if (task_no_new_privs(current) && !unconfined(label) && 1201 !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1202 /* not an apparmor denial per se, so don't log it */ 1203 AA_DEBUG("no_new_privs - change_hat denied"); 1204 error = -EPERM; 1205 goto out; 1206 } 1207 1208 if (flags & AA_CHANGE_TEST) 1209 goto out; 1210 1211 target = new; 1212 error = aa_set_current_hat(new, token); 1213 if (error == -EACCES) 1214 /* kill task in case of brute force attacks */ 1215 goto kill; 1216 } else if (previous && !(flags & AA_CHANGE_TEST)) { 1217 /* 1218 * no new privs prevents domain transitions that would 1219 * reduce restrictions. 1220 */ 1221 if (task_no_new_privs(current) && !unconfined(label) && 1222 !aa_label_is_unconfined_subset(previous, ctx->nnp)) { 1223 /* not an apparmor denial per se, so don't log it */ 1224 AA_DEBUG("no_new_privs - change_hat denied"); 1225 error = -EPERM; 1226 goto out; 1227 } 1228 1229 /* Return to saved label. Kill task if restore fails 1230 * to avoid brute force attacks 1231 */ 1232 target = previous; 1233 error = aa_restore_previous_label(token); 1234 if (error) { 1235 if (error == -EACCES) 1236 goto kill; 1237 goto fail; 1238 } 1239 } /* else ignore @flags && restores when there is no saved profile */ 1240 1241 out: 1242 aa_put_label(new); 1243 aa_put_label(previous); 1244 aa_put_label(label); 1245 put_cred(cred); 1246 1247 return error; 1248 1249 kill: 1250 info = "failed token match"; 1251 perms.kill = AA_MAY_CHANGEHAT; 1252 1253 fail: 1254 fn_for_each_in_ns(label, profile, 1255 aa_audit_file(profile, &perms, OP_CHANGE_HAT, 1256 AA_MAY_CHANGEHAT, NULL, NULL, target, 1257 GLOBAL_ROOT_UID, info, error)); 1258 1259 goto out; 1260 } 1261 1262 1263 static int change_profile_perms_wrapper(const char *op, const char *name, 1264 struct aa_profile *profile, 1265 struct aa_label *target, bool stack, 1266 u32 request, struct aa_perms *perms) 1267 { 1268 struct aa_ruleset *rules = list_first_entry(&profile->rules, 1269 typeof(*rules), list); 1270 const char *info = NULL; 1271 int error = 0; 1272 1273 if (!error) 1274 error = change_profile_perms(profile, target, stack, request, 1275 rules->file.start[AA_CLASS_FILE], 1276 perms); 1277 if (error) 1278 error = aa_audit_file(profile, perms, op, request, name, 1279 NULL, target, GLOBAL_ROOT_UID, info, 1280 error); 1281 1282 return error; 1283 } 1284 1285 /** 1286 * aa_change_profile - perform a one-way profile transition 1287 * @fqname: name of profile may include namespace (NOT NULL) 1288 * @flags: flags affecting change behavior 1289 * 1290 * Change to new profile @name. Unlike with hats, there is no way 1291 * to change back. If @name isn't specified the current profile name is 1292 * used. 1293 * If @onexec then the transition is delayed until 1294 * the next exec. 1295 * 1296 * Returns %0 on success, error otherwise. 1297 */ 1298 int aa_change_profile(const char *fqname, int flags) 1299 { 1300 struct aa_label *label, *new = NULL, *target = NULL; 1301 struct aa_profile *profile; 1302 struct aa_perms perms = {}; 1303 const char *info = NULL; 1304 const char *auditname = fqname; /* retain leading & if stack */ 1305 bool stack = flags & AA_CHANGE_STACK; 1306 struct aa_task_ctx *ctx = task_ctx(current); 1307 int error = 0; 1308 char *op; 1309 u32 request; 1310 1311 label = aa_get_current_label(); 1312 1313 /* 1314 * Detect no new privs being set, and store the label it 1315 * occurred under. Ideally this would happen when nnp 1316 * is set but there isn't a good way to do that yet. 1317 * 1318 * Testing for unconfined must be done before the subset test 1319 */ 1320 if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp) 1321 ctx->nnp = aa_get_label(label); 1322 1323 if (!fqname || !*fqname) { 1324 aa_put_label(label); 1325 AA_DEBUG("no profile name"); 1326 return -EINVAL; 1327 } 1328 1329 if (flags & AA_CHANGE_ONEXEC) { 1330 request = AA_MAY_ONEXEC; 1331 if (stack) 1332 op = OP_STACK_ONEXEC; 1333 else 1334 op = OP_CHANGE_ONEXEC; 1335 } else { 1336 request = AA_MAY_CHANGE_PROFILE; 1337 if (stack) 1338 op = OP_STACK; 1339 else 1340 op = OP_CHANGE_PROFILE; 1341 } 1342 1343 if (*fqname == '&') { 1344 stack = true; 1345 /* don't have label_parse() do stacking */ 1346 fqname++; 1347 } 1348 target = aa_label_parse(label, fqname, GFP_KERNEL, true, false); 1349 if (IS_ERR(target)) { 1350 struct aa_profile *tprofile; 1351 1352 info = "label not found"; 1353 error = PTR_ERR(target); 1354 target = NULL; 1355 /* 1356 * TODO: fixme using labels_profile is not right - do profile 1357 * per complain profile 1358 */ 1359 if ((flags & AA_CHANGE_TEST) || 1360 !COMPLAIN_MODE(labels_profile(label))) 1361 goto audit; 1362 /* released below */ 1363 tprofile = aa_new_learning_profile(labels_profile(label), false, 1364 fqname, GFP_KERNEL); 1365 if (!tprofile) { 1366 info = "failed null profile create"; 1367 error = -ENOMEM; 1368 goto audit; 1369 } 1370 target = &tprofile->label; 1371 goto check; 1372 } 1373 1374 /* 1375 * self directed transitions only apply to current policy ns 1376 * TODO: currently requiring perms for stacking and straight change 1377 * stacking doesn't strictly need this. Determine how much 1378 * we want to loosen this restriction for stacking 1379 * 1380 * if (!stack) { 1381 */ 1382 error = fn_for_each_in_ns(label, profile, 1383 change_profile_perms_wrapper(op, auditname, 1384 profile, target, stack, 1385 request, &perms)); 1386 if (error) 1387 /* auditing done in change_profile_perms_wrapper */ 1388 goto out; 1389 1390 /* } */ 1391 1392 check: 1393 /* check if tracing task is allowed to trace target domain */ 1394 error = may_change_ptraced_domain(target, &info); 1395 if (error && !fn_for_each_in_ns(label, profile, 1396 COMPLAIN_MODE(profile))) 1397 goto audit; 1398 1399 /* TODO: add permission check to allow this 1400 * if ((flags & AA_CHANGE_ONEXEC) && !current_is_single_threaded()) { 1401 * info = "not a single threaded task"; 1402 * error = -EACCES; 1403 * goto audit; 1404 * } 1405 */ 1406 if (flags & AA_CHANGE_TEST) 1407 goto out; 1408 1409 /* stacking is always a subset, so only check the nonstack case */ 1410 if (!stack) { 1411 new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 1412 aa_get_label(target), 1413 aa_get_label(&profile->label)); 1414 /* 1415 * no new privs prevents domain transitions that would 1416 * reduce restrictions. 1417 */ 1418 if (task_no_new_privs(current) && !unconfined(label) && 1419 !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1420 /* not an apparmor denial per se, so don't log it */ 1421 AA_DEBUG("no_new_privs - change_hat denied"); 1422 error = -EPERM; 1423 goto out; 1424 } 1425 } 1426 1427 if (!(flags & AA_CHANGE_ONEXEC)) { 1428 /* only transition profiles in the current ns */ 1429 if (stack) 1430 new = aa_label_merge(label, target, GFP_KERNEL); 1431 if (IS_ERR_OR_NULL(new)) { 1432 info = "failed to build target label"; 1433 if (!new) 1434 error = -ENOMEM; 1435 else 1436 error = PTR_ERR(new); 1437 new = NULL; 1438 perms.allow = 0; 1439 goto audit; 1440 } 1441 error = aa_replace_current_label(new); 1442 } else { 1443 if (new) { 1444 aa_put_label(new); 1445 new = NULL; 1446 } 1447 1448 /* full transition will be built in exec path */ 1449 error = aa_set_current_onexec(target, stack); 1450 } 1451 1452 audit: 1453 error = fn_for_each_in_ns(label, profile, 1454 aa_audit_file(profile, &perms, op, request, auditname, 1455 NULL, new ? new : target, 1456 GLOBAL_ROOT_UID, info, error)); 1457 1458 out: 1459 aa_put_label(new); 1460 aa_put_label(target); 1461 aa_put_label(label); 1462 1463 return error; 1464 } 1465