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