1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AppArmor security module 4 * 5 * This file contains AppArmor mediation of files 6 * 7 * Copyright (C) 1998-2008 Novell/SUSE 8 * Copyright 2009-2017 Canonical Ltd. 9 */ 10 11 #include <linux/fs.h> 12 #include <linux/mount.h> 13 #include <linux/namei.h> 14 #include <uapi/linux/mount.h> 15 16 #include "include/apparmor.h" 17 #include "include/audit.h" 18 #include "include/cred.h" 19 #include "include/domain.h" 20 #include "include/file.h" 21 #include "include/match.h" 22 #include "include/mount.h" 23 #include "include/path.h" 24 #include "include/policy.h" 25 26 27 #define DEFINE_AUDIT_MOUNT(NAME, OP, CRED) \ 28 DEFINE_AUDIT_DATA(NAME, LSM_AUDIT_DATA_NONE, AA_CLASS_MOUNT, OP);\ 29 NAME.subj_cred = (CRED) 30 31 static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags) 32 { 33 if (flags & MS_RDONLY) 34 audit_log_format(ab, "ro"); 35 else 36 audit_log_format(ab, "rw"); 37 if (flags & MS_NOSUID) 38 audit_log_format(ab, ", nosuid"); 39 if (flags & MS_NODEV) 40 audit_log_format(ab, ", nodev"); 41 if (flags & MS_NOEXEC) 42 audit_log_format(ab, ", noexec"); 43 if (flags & MS_SYNCHRONOUS) 44 audit_log_format(ab, ", sync"); 45 if (flags & MS_REMOUNT) 46 audit_log_format(ab, ", remount"); 47 if (flags & MS_MANDLOCK) 48 audit_log_format(ab, ", mand"); 49 if (flags & MS_DIRSYNC) 50 audit_log_format(ab, ", dirsync"); 51 if (flags & MS_NOSYMFOLLOW) 52 audit_log_format(ab, ", nosymfollow"); 53 if (flags & MS_NOATIME) 54 audit_log_format(ab, ", noatime"); 55 if (flags & MS_NODIRATIME) 56 audit_log_format(ab, ", nodiratime"); 57 if (flags & MS_BIND) 58 audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind"); 59 if (flags & MS_MOVE) 60 audit_log_format(ab, ", move"); 61 if (flags & MS_SILENT) 62 audit_log_format(ab, ", silent"); 63 if (flags & MS_POSIXACL) 64 audit_log_format(ab, ", acl"); 65 if (flags & MS_UNBINDABLE) 66 audit_log_format(ab, flags & MS_REC ? ", runbindable" : 67 ", unbindable"); 68 if (flags & MS_PRIVATE) 69 audit_log_format(ab, flags & MS_REC ? ", rprivate" : 70 ", private"); 71 if (flags & MS_SLAVE) 72 audit_log_format(ab, flags & MS_REC ? ", rslave" : 73 ", slave"); 74 if (flags & MS_SHARED) 75 audit_log_format(ab, flags & MS_REC ? ", rshared" : 76 ", shared"); 77 if (flags & MS_RELATIME) 78 audit_log_format(ab, ", relatime"); 79 if (flags & MS_I_VERSION) 80 audit_log_format(ab, ", iversion"); 81 if (flags & MS_STRICTATIME) 82 audit_log_format(ab, ", strictatime"); 83 if (flags & MS_NOUSER) 84 audit_log_format(ab, ", nouser"); 85 } 86 87 /** 88 * audit_cb - call back for mount specific audit fields 89 * @ab: audit_buffer (NOT NULL) 90 * @va: audit struct to audit values of (NOT NULL) 91 */ 92 static void audit_cb(struct audit_buffer *ab, void *va) 93 { 94 struct common_audit_data *sa = va; 95 struct apparmor_audit_data *ad = aad(sa); 96 97 if (ad->mnt.type) { 98 audit_log_format(ab, " fstype="); 99 audit_log_untrustedstring(ab, ad->mnt.type); 100 } 101 if (ad->mnt.src_name) { 102 audit_log_format(ab, " srcname="); 103 audit_log_untrustedstring(ab, ad->mnt.src_name); 104 } 105 if (ad->mnt.trans) { 106 audit_log_format(ab, " trans="); 107 audit_log_untrustedstring(ab, ad->mnt.trans); 108 } 109 if (ad->mnt.flags) { 110 audit_log_format(ab, " flags=\""); 111 audit_mnt_flags(ab, ad->mnt.flags); 112 audit_log_format(ab, "\""); 113 } 114 if (ad->mnt.data) { 115 audit_log_format(ab, " options="); 116 audit_log_untrustedstring(ab, ad->mnt.data); 117 } 118 } 119 120 /** 121 * match_mnt_flags - Do an ordered match on mount flags 122 * @dfa: dfa to match against 123 * @state: state to start in 124 * @flags: mount flags to match against 125 * 126 * Mount flags are encoded as an ordered match. This is done instead of 127 * checking against a simple bitmask, to allow for logical operations 128 * on the flags. 129 * 130 * Returns: next state after flags match 131 */ 132 static aa_state_t match_mnt_flags(const struct aa_dfa *dfa, aa_state_t state, 133 unsigned long flags) 134 { 135 unsigned int i; 136 137 for (i = 0; i <= 31 ; ++i) { 138 if ((1 << i) & flags) 139 state = aa_dfa_next(dfa, state, i + 1); 140 } 141 142 return state; 143 } 144 145 static const char * const mnt_info_table[] = { 146 "match succeeded", 147 "failed mntpnt match", 148 "failed srcname match", 149 "failed type match", 150 "failed flags match", 151 "failed data match", 152 "failed perms check" 153 }; 154 155 /* 156 * Returns 0 on success else element that match failed in, this is the 157 * index into the mnt_info_table above 158 */ 159 static int do_match_mnt(struct aa_policydb *policy, aa_state_t start, 160 const char *mntpnt, const char *devname, 161 const char *type, unsigned long flags, 162 void *data, bool binary, struct aa_perms *perms) 163 { 164 aa_state_t state; 165 166 AA_BUG(!policy); 167 AA_BUG(!policy->dfa); 168 AA_BUG(!policy->perms); 169 AA_BUG(!perms); 170 171 state = aa_dfa_match(policy->dfa, start, mntpnt); 172 state = aa_dfa_null_transition(policy->dfa, state); 173 if (!state) 174 return 1; 175 176 if (devname) 177 state = aa_dfa_match(policy->dfa, state, devname); 178 state = aa_dfa_null_transition(policy->dfa, state); 179 if (!state) 180 return 2; 181 182 if (type) 183 state = aa_dfa_match(policy->dfa, state, type); 184 state = aa_dfa_null_transition(policy->dfa, state); 185 if (!state) 186 return 3; 187 188 state = match_mnt_flags(policy->dfa, state, flags); 189 if (!state) 190 return 4; 191 *perms = *aa_lookup_perms(policy, state); 192 if (perms->allow & AA_MAY_MOUNT) 193 return 0; 194 195 /* only match data if not binary and the DFA flags data is expected */ 196 if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) { 197 state = aa_dfa_null_transition(policy->dfa, state); 198 if (!state) 199 return 4; 200 201 state = aa_dfa_match(policy->dfa, state, data); 202 if (!state) 203 return 5; 204 *perms = *aa_lookup_perms(policy, state); 205 if (perms->allow & AA_MAY_MOUNT) 206 return 0; 207 } 208 209 /* failed at perms check, don't confuse with flags match */ 210 return 6; 211 } 212 213 214 static int path_flags(const struct aa_profile *profile, const struct path *path) 215 { 216 AA_BUG(!profile); 217 AA_BUG(!path); 218 219 return profile->path_flags | 220 (S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0); 221 } 222 223 /** 224 * match_mnt_path_str - handle path matching for mount 225 * @profile: the confining profile 226 * @mntpath: for the mntpnt (NOT NULL) 227 * @buffer: buffer to be used to lookup mntpath 228 * @devname: string for the devname/src_name (MAY BE NULL OR ERRPTR) 229 * @type: string for the dev type (MAYBE NULL) 230 * @flags: mount flags to match 231 * @data: fs mount data (MAYBE NULL) 232 * @binary: whether @data is binary 233 * @devinfo: error str if (IS_ERR(@devname)) 234 * @ad: apparmor audit data structure 235 * 236 * Returns: 0 on success else error 237 */ 238 static int match_mnt_path_str(struct aa_profile *profile, 239 const struct path *mntpath, char *buffer, 240 const char *devname, const char *type, 241 unsigned long flags, void *data, bool binary, 242 const char *devinfo, 243 struct apparmor_audit_data *ad) 244 { 245 struct aa_perms perms = { }; 246 const char *mntpnt = NULL; 247 struct aa_ruleset *rules = profile->label.rules[0]; 248 int pos, error; 249 250 AA_BUG(!profile); 251 AA_BUG(!mntpath); 252 AA_BUG(!buffer); 253 254 if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 255 return 0; 256 257 ad->mnt.type = type; 258 259 error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer, 260 &mntpnt, &ad->info, profile->disconnected); 261 if (error) 262 return aa_audit_perm_error(&profile->label, AA_MAY_MOUNT, 263 error, ad, audit_cb); 264 ad->name = mntpnt; 265 266 if (IS_ERR(devname)) { 267 error = PTR_ERR(devname); 268 ad->info = devinfo; 269 return aa_audit_perm_error(&profile->label, AA_MAY_MOUNT, 270 error, ad, audit_cb); 271 } 272 ad->mnt.src_name = devname; 273 274 pos = do_match_mnt(rules->policy, 275 rules->policy->start[AA_CLASS_MOUNT], 276 mntpnt, devname, type, flags, data, binary, &perms); 277 if (pos) 278 ad->info = mnt_info_table[pos]; 279 280 aa_apply_modes_to_perms(profile, &perms); 281 if (data && !binary && (perms.audit & AA_AUDIT_DATA)) 282 ad->mnt.data = data; 283 return aa_check_perms(profile, &perms, AA_MAY_MOUNT, ad, audit_cb); 284 } 285 286 /** 287 * match_mnt - handle path matching for mount 288 * @profile: the confining profile 289 * @path: for the mntpnt (NOT NULL) 290 * @buffer: buffer to be used to lookup mntpath 291 * @devpath: path devname/src_name (MAYBE NULL) 292 * @devbuffer: buffer to be used to lookup devname/src_name 293 * @type: string for the dev type (MAYBE NULL) 294 * @flags: mount flags to match 295 * @data: fs mount data (MAYBE NULL) 296 * @binary: whether @data is binary 297 * @ad: apparmor audit data structure 298 * 299 * Returns: 0 on success else error 300 */ 301 static int match_mnt(struct aa_profile *profile, const struct path *path, 302 char *buffer, const struct path *devpath, char *devbuffer, 303 const char *type, unsigned long flags, void *data, 304 bool binary, struct apparmor_audit_data *ad) 305 { 306 const char *devname = NULL, *info = NULL; 307 struct aa_ruleset *rules = profile->label.rules[0]; 308 int error = -EACCES; 309 310 AA_BUG(!profile); 311 AA_BUG(devpath && !devbuffer); 312 313 if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 314 return 0; 315 316 if (devpath) { 317 error = aa_path_name(devpath, path_flags(profile, devpath), 318 devbuffer, &devname, &info, 319 profile->disconnected); 320 if (error) 321 devname = ERR_PTR(error); 322 } 323 324 return match_mnt_path_str(profile, path, buffer, devname, 325 type, flags, data, binary, info, ad); 326 } 327 328 int aa_remount(const struct cred *subj_cred, 329 struct aa_label *label, const struct path *path, 330 unsigned long flags, void *data) 331 { 332 struct aa_profile *profile; 333 char *buffer = NULL; 334 bool binary; 335 int error; 336 DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred); 337 ad.mnt.flags = flags; 338 339 AA_BUG(!label); 340 AA_BUG(!path); 341 342 binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA; 343 344 buffer = aa_get_buffer(false); 345 if (!buffer) 346 return -ENOMEM; 347 error = fn_for_each(label, profile, 348 match_mnt(profile, path, buffer, NULL, NULL, NULL, 349 flags, data, binary, &ad)); 350 aa_put_buffer(buffer); 351 352 return error; 353 } 354 355 int aa_bind_mount(const struct cred *subj_cred, 356 struct aa_label *label, const struct path *path, 357 const char *dev_name, unsigned long flags) 358 { 359 struct aa_profile *profile; 360 char *buffer = NULL, *old_buffer = NULL; 361 struct path old_path; 362 int error; 363 DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred); 364 365 AA_BUG(!label); 366 AA_BUG(!path); 367 368 if (!dev_name || !*dev_name) 369 return -EINVAL; 370 371 flags &= MS_REC | MS_BIND; 372 ad.mnt.flags = flags; 373 374 error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); 375 if (error) 376 return aa_audit_perm_error(label, AA_MAY_MOUNT, error, &ad, 377 audit_cb); 378 379 buffer = aa_get_buffer(false); 380 old_buffer = aa_get_buffer(false); 381 error = -ENOMEM; 382 if (!buffer || !old_buffer) 383 goto out; 384 385 error = fn_for_each(label, profile, 386 match_mnt(profile, path, buffer, &old_path, 387 old_buffer, NULL, flags, NULL, false, &ad)); 388 out: 389 aa_put_buffer(buffer); 390 aa_put_buffer(old_buffer); 391 path_put(&old_path); 392 393 return error; 394 } 395 396 int aa_mount_change_type(const struct cred *subj_cred, 397 struct aa_label *label, const struct path *path, 398 unsigned long flags) 399 { 400 struct aa_profile *profile; 401 char *buffer = NULL; 402 int error; 403 DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred); 404 405 AA_BUG(!label); 406 AA_BUG(!path); 407 408 /* These are the flags allowed by do_change_type() */ 409 flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE | 410 MS_UNBINDABLE); 411 ad.mnt.flags = flags; 412 413 buffer = aa_get_buffer(false); 414 if (!buffer) 415 return -ENOMEM; 416 error = fn_for_each(label, profile, 417 match_mnt(profile, path, buffer, NULL, NULL, NULL, 418 flags, NULL, false, &ad)); 419 aa_put_buffer(buffer); 420 421 return error; 422 } 423 424 int aa_move_mount(const struct cred *subj_cred, 425 struct aa_label *label, const struct path *from_path, 426 const struct path *to_path) 427 { 428 struct aa_profile *profile; 429 char *to_buffer = NULL, *from_buffer = NULL; 430 int error; 431 DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred); 432 ad.mnt.flags = MS_MOVE; 433 434 AA_BUG(!label); 435 AA_BUG(!from_path); 436 AA_BUG(!to_path); 437 438 to_buffer = aa_get_buffer(false); 439 from_buffer = aa_get_buffer(false); 440 error = -ENOMEM; 441 if (!to_buffer || !from_buffer) 442 goto out; 443 444 if (!our_mnt(from_path->mnt)) 445 /* moving a mount detached from the namespace */ 446 from_path = NULL; 447 error = fn_for_each(label, profile, 448 match_mnt(profile, to_path, to_buffer, from_path, 449 from_buffer, NULL, MS_MOVE, NULL, false, 450 &ad)); 451 out: 452 aa_put_buffer(to_buffer); 453 aa_put_buffer(from_buffer); 454 455 return error; 456 } 457 458 int aa_move_mount_old(const struct cred *subj_cred, struct aa_label *label, 459 const struct path *path, const char *orig_name) 460 { 461 struct path old_path; 462 int error; 463 464 if (!orig_name || !*orig_name) 465 return -EINVAL; 466 error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path); 467 if (error) 468 return error; 469 470 error = aa_move_mount(subj_cred, label, &old_path, path); 471 path_put(&old_path); 472 473 return error; 474 } 475 476 int aa_new_mount(const struct cred *subj_cred, struct aa_label *label, 477 const char *dev_name, const struct path *path, 478 const char *type, unsigned long flags, void *data) 479 { 480 struct aa_profile *profile; 481 char *buffer = NULL, *dev_buffer = NULL; 482 bool binary = true; 483 int error; 484 int requires_dev = 0; 485 struct path tmp_path, *dev_path = NULL; 486 DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred); 487 ad.mnt.flags = flags; 488 489 AA_BUG(!label); 490 AA_BUG(!path); 491 492 if (type) { 493 struct file_system_type *fstype; 494 495 fstype = get_fs_type(type); 496 if (!fstype) 497 return -ENODEV; 498 binary = fstype->fs_flags & FS_BINARY_MOUNTDATA; 499 requires_dev = fstype->fs_flags & FS_REQUIRES_DEV; 500 put_filesystem(fstype); 501 502 if (requires_dev) { 503 if (!dev_name || !*dev_name) 504 return -ENOENT; 505 506 error = kern_path(dev_name, LOOKUP_FOLLOW, &tmp_path); 507 if (error) 508 return error; 509 dev_path = &tmp_path; 510 } 511 } 512 513 buffer = aa_get_buffer(false); 514 if (!buffer) { 515 error = -ENOMEM; 516 goto out; 517 } 518 if (dev_path) { 519 dev_buffer = aa_get_buffer(false); 520 if (!dev_buffer) { 521 error = -ENOMEM; 522 goto out; 523 } 524 error = fn_for_each(label, profile, 525 match_mnt(profile, path, buffer, dev_path, 526 dev_buffer, type, flags, data, 527 binary, &ad)); 528 } else { 529 error = fn_for_each(label, profile, 530 match_mnt_path_str(profile, path, buffer, 531 dev_name, type, flags, data, 532 binary, NULL, &ad)); 533 } 534 535 out: 536 aa_put_buffer(buffer); 537 aa_put_buffer(dev_buffer); 538 if (dev_path) 539 path_put(dev_path); 540 541 return error; 542 } 543 544 static int profile_umount(struct aa_profile *profile, const struct path *path, 545 char *buffer, struct apparmor_audit_data *ad) 546 { 547 struct aa_ruleset *rules = profile->label.rules[0]; 548 struct aa_perms perms = { }; 549 const char *name = NULL; 550 aa_state_t state; 551 int error; 552 553 AA_BUG(!profile); 554 AA_BUG(!path); 555 556 if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 557 return 0; 558 559 /* TODO: lift path_name, need to separate profile path_flags from 560 * the lookup 561 */ 562 error = aa_path_name(path, path_flags(profile, path), buffer, &name, 563 &ad->info, profile->disconnected); 564 if (error) 565 return aa_audit_perm_error(&profile->label, AA_MAY_UMOUNT, 566 error, ad, audit_cb); 567 568 ad->name = name; 569 state = aa_dfa_match(rules->policy->dfa, 570 rules->policy->start[AA_CLASS_MOUNT], 571 name); 572 perms = *aa_lookup_perms(rules->policy, state); 573 574 aa_apply_modes_to_perms(profile, &perms); 575 return aa_check_perms(profile, &perms, AA_MAY_UMOUNT, ad, audit_cb); 576 } 577 578 int aa_umount(const struct cred *subj_cred, struct aa_label *label, 579 struct vfsmount *mnt, int flags) 580 { 581 struct aa_profile *profile; 582 char *buffer = NULL; 583 int error; 584 struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; 585 DEFINE_AUDIT_MOUNT(ad, OP_UMOUNT, subj_cred); 586 587 AA_BUG(!label); 588 AA_BUG(!mnt); 589 590 buffer = aa_get_buffer(false); 591 if (!buffer) 592 return -ENOMEM; 593 594 error = fn_for_each(label, profile, 595 profile_umount(profile, &path, buffer, &ad)); 596 aa_put_buffer(buffer); 597 598 return error; 599 } 600 601 /* helper fn for transition on pivotroot 602 * 603 * Returns: label for transition or ERR_PTR. Does not return NULL 604 */ 605 static struct aa_label *build_pivotroot(struct aa_profile *profile, 606 const struct path *new_path, 607 char *new_buffer, 608 const struct path *old_path, 609 char *old_buffer, 610 struct apparmor_audit_data *ad) 611 { 612 struct aa_ruleset *rules = profile->label.rules[0]; 613 const char *old_name, *new_name = NULL; 614 struct aa_perms perms = { }; 615 aa_state_t state; 616 int error; 617 618 AA_BUG(!profile); 619 AA_BUG(!new_path); 620 AA_BUG(!old_path); 621 622 if (profile_unconfined(profile) || 623 !RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 624 return aa_get_newest_label(&profile->label); 625 626 error = aa_path_name(old_path, path_flags(profile, old_path), 627 old_buffer, &old_name, &ad->info, 628 profile->disconnected); 629 if (error) 630 goto err; 631 ad->mnt.src_name = old_name; 632 error = aa_path_name(new_path, path_flags(profile, new_path), 633 new_buffer, &new_name, &ad->info, 634 profile->disconnected); 635 if (error) 636 goto err; 637 ad->name = new_name; 638 639 state = aa_dfa_match(rules->policy->dfa, 640 rules->policy->start[AA_CLASS_MOUNT], 641 new_name); 642 state = aa_dfa_null_transition(rules->policy->dfa, state); 643 state = aa_dfa_match(rules->policy->dfa, state, old_name); 644 perms = *aa_lookup_perms(rules->policy, state); 645 /* todo: allow pivotroot to specify a transition other than profile */ 646 ad->mnt.trans = profile->label.hname; 647 648 aa_apply_modes_to_perms(profile, &perms); 649 error = aa_check_perms(profile, &perms, AA_MAY_PIVOTROOT, ad, audit_cb); 650 651 out: 652 if (error) 653 return ERR_PTR(error); 654 655 return aa_get_newest_label(&profile->label); 656 657 err: 658 error = aa_audit_perm_error(&profile->label, AA_MAY_PIVOTROOT, error, 659 ad, audit_cb); 660 goto out; 661 } 662 663 int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label, 664 const struct path *old_path, 665 const struct path *new_path) 666 { 667 struct aa_profile *profile; 668 struct aa_label *target = NULL; 669 char *old_buffer = NULL, *new_buffer = NULL; 670 int error; 671 DEFINE_AUDIT_MOUNT(ad, OP_PIVOTROOT, subj_cred); 672 673 AA_BUG(!label); 674 AA_BUG(!old_path); 675 AA_BUG(!new_path); 676 677 old_buffer = aa_get_buffer(false); 678 new_buffer = aa_get_buffer(false); 679 error = -ENOMEM; 680 if (!old_buffer || !new_buffer) 681 goto out; 682 target = fn_label_build(label, profile, GFP_KERNEL, 683 build_pivotroot(profile, new_path, new_buffer, 684 old_path, old_buffer, &ad)); 685 AA_BUG(!target); 686 if (!IS_ERR(target)) { 687 error = aa_replace_current_label(target); 688 if (error) 689 goto fail; 690 aa_put_label(target); 691 } else 692 /* already audited error in build_pivotroot */ 693 error = PTR_ERR(target); 694 out: 695 aa_put_buffer(old_buffer); 696 aa_put_buffer(new_buffer); 697 698 return error; 699 700 fail: 701 /* TODO: add back in auditing of new_name and old_name, 702 * needs lifting of name lookup out of profile cb 703 */ 704 ad.mnt.trans = target->hname; 705 error = aa_audit_perm_error(label, AA_MAY_PIVOTROOT, error, &ad, 706 audit_cb); 707 aa_put_label(target); 708 goto out; 709 } 710