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