Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

apparmor: add the profile introspection file to interface

Add the dynamic namespace relative profiles file to the interace, to allow
introspection of loaded profiles and their modes.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Kees Cook <kees@ubuntu.com>

+236
+236
security/apparmor/apparmorfs.c
··· 20 20 #include <linux/uaccess.h> 21 21 #include <linux/namei.h> 22 22 #include <linux/capability.h> 23 + #include <linux/rcupdate.h> 23 24 24 25 #include "include/apparmor.h" 25 26 #include "include/apparmorfs.h" ··· 513 512 } 514 513 515 514 515 + #define list_entry_next(pos, member) \ 516 + list_entry(pos->member.next, typeof(*pos), member) 517 + #define list_entry_is_head(pos, head, member) (&pos->member == (head)) 518 + 519 + /** 520 + * __next_namespace - find the next namespace to list 521 + * @root: root namespace to stop search at (NOT NULL) 522 + * @ns: current ns position (NOT NULL) 523 + * 524 + * Find the next namespace from @ns under @root and handle all locking needed 525 + * while switching current namespace. 526 + * 527 + * Returns: next namespace or NULL if at last namespace under @root 528 + * Requires: ns->parent->lock to be held 529 + * NOTE: will not unlock root->lock 530 + */ 531 + static struct aa_namespace *__next_namespace(struct aa_namespace *root, 532 + struct aa_namespace *ns) 533 + { 534 + struct aa_namespace *parent, *next; 535 + 536 + /* is next namespace a child */ 537 + if (!list_empty(&ns->sub_ns)) { 538 + next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list); 539 + mutex_lock(&next->lock); 540 + return next; 541 + } 542 + 543 + /* check if the next ns is a sibling, parent, gp, .. */ 544 + parent = ns->parent; 545 + while (parent) { 546 + mutex_unlock(&ns->lock); 547 + next = list_entry_next(ns, base.list); 548 + if (!list_entry_is_head(next, &parent->sub_ns, base.list)) { 549 + mutex_lock(&next->lock); 550 + return next; 551 + } 552 + if (parent == root) 553 + return NULL; 554 + ns = parent; 555 + parent = parent->parent; 556 + } 557 + 558 + return NULL; 559 + } 560 + 561 + /** 562 + * __first_profile - find the first profile in a namespace 563 + * @root: namespace that is root of profiles being displayed (NOT NULL) 564 + * @ns: namespace to start in (NOT NULL) 565 + * 566 + * Returns: unrefcounted profile or NULL if no profile 567 + * Requires: profile->ns.lock to be held 568 + */ 569 + static struct aa_profile *__first_profile(struct aa_namespace *root, 570 + struct aa_namespace *ns) 571 + { 572 + for (; ns; ns = __next_namespace(root, ns)) { 573 + if (!list_empty(&ns->base.profiles)) 574 + return list_first_entry(&ns->base.profiles, 575 + struct aa_profile, base.list); 576 + } 577 + return NULL; 578 + } 579 + 580 + /** 581 + * __next_profile - step to the next profile in a profile tree 582 + * @profile: current profile in tree (NOT NULL) 583 + * 584 + * Perform a depth first traversal on the profile tree in a namespace 585 + * 586 + * Returns: next profile or NULL if done 587 + * Requires: profile->ns.lock to be held 588 + */ 589 + static struct aa_profile *__next_profile(struct aa_profile *p) 590 + { 591 + struct aa_profile *parent; 592 + struct aa_namespace *ns = p->ns; 593 + 594 + /* is next profile a child */ 595 + if (!list_empty(&p->base.profiles)) 596 + return list_first_entry(&p->base.profiles, typeof(*p), 597 + base.list); 598 + 599 + /* is next profile a sibling, parent sibling, gp, sibling, .. */ 600 + parent = rcu_dereference_protected(p->parent, 601 + mutex_is_locked(&p->ns->lock)); 602 + while (parent) { 603 + p = list_entry_next(p, base.list); 604 + if (!list_entry_is_head(p, &parent->base.profiles, base.list)) 605 + return p; 606 + p = parent; 607 + parent = rcu_dereference_protected(parent->parent, 608 + mutex_is_locked(&parent->ns->lock)); 609 + } 610 + 611 + /* is next another profile in the namespace */ 612 + p = list_entry_next(p, base.list); 613 + if (!list_entry_is_head(p, &ns->base.profiles, base.list)) 614 + return p; 615 + 616 + return NULL; 617 + } 618 + 619 + /** 620 + * next_profile - step to the next profile in where ever it may be 621 + * @root: root namespace (NOT NULL) 622 + * @profile: current profile (NOT NULL) 623 + * 624 + * Returns: next profile or NULL if there isn't one 625 + */ 626 + static struct aa_profile *next_profile(struct aa_namespace *root, 627 + struct aa_profile *profile) 628 + { 629 + struct aa_profile *next = __next_profile(profile); 630 + if (next) 631 + return next; 632 + 633 + /* finished all profiles in namespace move to next namespace */ 634 + return __first_profile(root, __next_namespace(root, profile->ns)); 635 + } 636 + 637 + /** 638 + * p_start - start a depth first traversal of profile tree 639 + * @f: seq_file to fill 640 + * @pos: current position 641 + * 642 + * Returns: first profile under current namespace or NULL if none found 643 + * 644 + * acquires first ns->lock 645 + */ 646 + static void *p_start(struct seq_file *f, loff_t *pos) 647 + { 648 + struct aa_profile *profile = NULL; 649 + struct aa_namespace *root = aa_current_profile()->ns; 650 + loff_t l = *pos; 651 + f->private = aa_get_namespace(root); 652 + 653 + 654 + /* find the first profile */ 655 + mutex_lock(&root->lock); 656 + profile = __first_profile(root, root); 657 + 658 + /* skip to position */ 659 + for (; profile && l > 0; l--) 660 + profile = next_profile(root, profile); 661 + 662 + return profile; 663 + } 664 + 665 + /** 666 + * p_next - read the next profile entry 667 + * @f: seq_file to fill 668 + * @p: profile previously returned 669 + * @pos: current position 670 + * 671 + * Returns: next profile after @p or NULL if none 672 + * 673 + * may acquire/release locks in namespace tree as necessary 674 + */ 675 + static void *p_next(struct seq_file *f, void *p, loff_t *pos) 676 + { 677 + struct aa_profile *profile = p; 678 + struct aa_namespace *ns = f->private; 679 + (*pos)++; 680 + 681 + return next_profile(ns, profile); 682 + } 683 + 684 + /** 685 + * p_stop - stop depth first traversal 686 + * @f: seq_file we are filling 687 + * @p: the last profile writen 688 + * 689 + * Release all locking done by p_start/p_next on namespace tree 690 + */ 691 + static void p_stop(struct seq_file *f, void *p) 692 + { 693 + struct aa_profile *profile = p; 694 + struct aa_namespace *root = f->private, *ns; 695 + 696 + if (profile) { 697 + for (ns = profile->ns; ns && ns != root; ns = ns->parent) 698 + mutex_unlock(&ns->lock); 699 + } 700 + mutex_unlock(&root->lock); 701 + aa_put_namespace(root); 702 + } 703 + 704 + /** 705 + * seq_show_profile - show a profile entry 706 + * @f: seq_file to file 707 + * @p: current position (profile) (NOT NULL) 708 + * 709 + * Returns: error on failure 710 + */ 711 + static int seq_show_profile(struct seq_file *f, void *p) 712 + { 713 + struct aa_profile *profile = (struct aa_profile *)p; 714 + struct aa_namespace *root = f->private; 715 + 716 + if (profile->ns != root) 717 + seq_printf(f, ":%s://", aa_ns_name(root, profile->ns)); 718 + seq_printf(f, "%s (%s)\n", profile->base.hname, 719 + aa_profile_mode_names[profile->mode]); 720 + 721 + return 0; 722 + } 723 + 724 + static const struct seq_operations aa_fs_profiles_op = { 725 + .start = p_start, 726 + .next = p_next, 727 + .stop = p_stop, 728 + .show = seq_show_profile, 729 + }; 730 + 731 + static int profiles_open(struct inode *inode, struct file *file) 732 + { 733 + return seq_open(file, &aa_fs_profiles_op); 734 + } 735 + 736 + static int profiles_release(struct inode *inode, struct file *file) 737 + { 738 + return seq_release(inode, file); 739 + } 740 + 741 + static const struct file_operations aa_fs_profiles_fops = { 742 + .open = profiles_open, 743 + .read = seq_read, 744 + .llseek = seq_lseek, 745 + .release = profiles_release, 746 + }; 747 + 748 + 516 749 /** Base file system setup **/ 517 750 static struct aa_fs_entry aa_fs_entry_file[] = { 518 751 AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \ ··· 780 545 AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), 781 546 AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), 782 547 AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), 548 + AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops), 783 549 AA_FS_DIR("features", aa_fs_entry_features), 784 550 { } 785 551 };