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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'apparmor-pr-2021-11-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor

Pull apparmor updates from John Johansen:
"Features
- use per file locks for transactional queries
- update policy management capability checks to work with LSM stacking

Bug Fixes:
- check/put label on apparmor_sk_clone_security()
- fix error check on update of label hname
- fix introspection of of task mode for unconfined tasks

Cleanups:
- avoid -Wempty-body warning
- remove duplicated 'Returns:' comments
- fix doc warning
- remove unneeded one-line hook wrappers
- use struct_size() helper in kzalloc()
- fix zero-length compiler warning in AA_BUG()
- file.h: delete duplicated word
- delete repeated words in comments
- remove repeated declaration"

* tag 'apparmor-pr-2021-11-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor:
apparmor: remove duplicated 'Returns:' comments
apparmor: remove unneeded one-line hook wrappers
apparmor: Use struct_size() helper in kzalloc()
apparmor: fix zero-length compiler warning in AA_BUG()
apparmor: use per file locks for transactional queries
apparmor: fix doc warning
apparmor: Remove the repeated declaration
apparmor: avoid -Wempty-body warning
apparmor: Fix internal policy capable check for policy management
apparmor: fix error check
security: apparmor: delete repeated words in comments
security: apparmor: file.h: delete duplicated word
apparmor: switch to apparmor to internal capable check for policy management
apparmor: update policy capable checks to use a label
apparmor: fix introspection of of task mode for unconfined tasks
apparmor: check/put label on apparmor_sk_clone_security()

+90 -66
+8 -9
security/apparmor/apparmorfs.c
··· 812 812 }; 813 813 814 814 #define MULTI_TRANSACTION_LIMIT (PAGE_SIZE - sizeof(struct multi_transaction)) 815 - /* TODO: replace with per file lock */ 816 - static DEFINE_SPINLOCK(multi_transaction_lock); 817 815 818 816 static void multi_transaction_kref(struct kref *kref) 819 817 { ··· 845 847 AA_BUG(n > MULTI_TRANSACTION_LIMIT); 846 848 847 849 new->size = n; 848 - spin_lock(&multi_transaction_lock); 850 + spin_lock(&file->f_lock); 849 851 old = (struct multi_transaction *) file->private_data; 850 852 file->private_data = new; 851 - spin_unlock(&multi_transaction_lock); 853 + spin_unlock(&file->f_lock); 852 854 put_multi_transaction(old); 853 855 } 854 856 ··· 877 879 struct multi_transaction *t; 878 880 ssize_t ret; 879 881 880 - spin_lock(&multi_transaction_lock); 882 + spin_lock(&file->f_lock); 881 883 t = get_multi_transaction(file->private_data); 882 - spin_unlock(&multi_transaction_lock); 884 + spin_unlock(&file->f_lock); 885 + 883 886 if (!t) 884 887 return 0; 885 888 ··· 1357 1358 struct aa_loaddata *loaddata; 1358 1359 struct rawdata_f_data *private; 1359 1360 1360 - if (!policy_view_capable(NULL)) 1361 + if (!aa_current_policy_view_capable(NULL)) 1361 1362 return -EACCES; 1362 1363 1363 1364 loaddata = __aa_get_loaddata(inode->i_private); ··· 2113 2114 2114 2115 /** 2115 2116 * __next_profile - step to the next profile in a profile tree 2116 - * @profile: current profile in tree (NOT NULL) 2117 + * @p: current profile in tree (NOT NULL) 2117 2118 * 2118 2119 * Perform a depth first traversal on the profile tree in a namespace 2119 2120 * ··· 2264 2265 2265 2266 static int profiles_open(struct inode *inode, struct file *file) 2266 2267 { 2267 - if (!policy_view_capable(NULL)) 2268 + if (!aa_current_policy_view_capable(NULL)) 2268 2269 return -EACCES; 2269 2270 2270 2271 return seq_open(file, &aa_sfs_profiles_op);
+1 -1
security/apparmor/include/file.h
··· 167 167 * @perms: permission table indexed by the matched state accept entry of @dfa 168 168 * @trans: transition table for indexed by named x transitions 169 169 * 170 - * File permission are determined by matching a path against @dfa and then 170 + * File permission are determined by matching a path against @dfa and 171 171 * then using the value of the accept entry for the matching state as 172 172 * an index into @perms. If a named exec transition is required it is 173 173 * looked up in the transition table.
+1 -4
security/apparmor/include/label.h
··· 77 77 #define __labelset_for_each(LS, N) \ 78 78 for ((N) = rb_first(&(LS)->root); (N); (N) = rb_next(N)) 79 79 80 - void aa_labelset_destroy(struct aa_labelset *ls); 81 - void aa_labelset_init(struct aa_labelset *ls); 82 - 83 - 84 80 enum label_flags { 85 81 FLAG_HAT = 1, /* profile is a hat */ 86 82 FLAG_UNCONFINED = 2, /* label unconfined only if all */ ··· 144 148 #define __label_make_stale(X) ((X)->flags |= FLAG_STALE) 145 149 #define labels_ns(X) (vec_ns(&((X)->vec[0]), (X)->size)) 146 150 #define labels_set(X) (&labels_ns(X)->labels) 151 + #define labels_view(X) labels_ns(X) 147 152 #define labels_profile(X) ((X)->vec[(X)->size - 1]) 148 153 149 154
+7 -2
security/apparmor/include/lib.h
··· 31 31 32 32 #define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X) 33 33 34 - #define AA_BUG(X, args...) AA_BUG_FMT((X), "" args) 34 + #define AA_BUG(X, args...) \ 35 + do { \ 36 + _Pragma("GCC diagnostic ignored \"-Wformat-zero-length\""); \ 37 + AA_BUG_FMT((X), "" args); \ 38 + _Pragma("GCC diagnostic warning \"-Wformat-zero-length\""); \ 39 + } while (0) 35 40 #ifdef CONFIG_SECURITY_APPARMOR_DEBUG_ASSERTS 36 41 #define AA_BUG_FMT(X, fmt, args...) \ 37 42 WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __func__, ##args) 38 43 #else 39 - #define AA_BUG_FMT(X, fmt, args...) 44 + #define AA_BUG_FMT(X, fmt, args...) no_printk(fmt, ##args) 40 45 #endif 41 46 42 47 #define AA_ERROR(fmt, args...) \
+4 -2
security/apparmor/include/policy.h
··· 301 301 return profile->audit; 302 302 } 303 303 304 - bool policy_view_capable(struct aa_ns *ns); 305 - bool policy_admin_capable(struct aa_ns *ns); 304 + bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns); 305 + bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns); 306 306 int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, 307 307 u32 mask); 308 + bool aa_current_policy_view_capable(struct aa_ns *ns); 309 + bool aa_current_policy_admin_capable(struct aa_ns *ns); 308 310 309 311 #endif /* __AA_POLICY_H */
+3 -4
security/apparmor/label.c
··· 425 425 AA_BUG(size < 1); 426 426 427 427 /* + 1 for null terminator entry on vec */ 428 - new = kzalloc(sizeof(*new) + sizeof(struct aa_profile *) * (size + 1), 429 - gfp); 428 + new = kzalloc(struct_size(new, vec, size + 1), gfp); 430 429 AA_DEBUG("%s (%p)\n", __func__, new); 431 430 if (!new) 432 431 goto fail; ··· 1453 1454 if (label->hname || labels_ns(label) != ns) 1454 1455 return res; 1455 1456 1456 - if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) == -1) 1457 + if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) < 0) 1457 1458 return res; 1458 1459 1459 1460 ls = labels_set(label); ··· 1703 1704 1704 1705 /** 1705 1706 * aa_label_acntsxprint - allocate a __counted string buffer and print label 1706 - * @strp: buffer to write to. (MAY BE NULL if @size == 0) 1707 + * @strp: buffer to write to. 1707 1708 * @ns: namespace profile is being viewed from 1708 1709 * @label: label to view (NOT NULL) 1709 1710 * @flags: flags controlling what label info is printed
+13 -29
security/apparmor/lsm.c
··· 1402 1402 { 1403 1403 if (!apparmor_enabled) 1404 1404 return -EINVAL; 1405 - if (apparmor_initialized && !policy_admin_capable(NULL)) 1405 + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 1406 1406 return -EPERM; 1407 1407 return param_set_bool(val, kp); 1408 1408 } ··· 1411 1411 { 1412 1412 if (!apparmor_enabled) 1413 1413 return -EINVAL; 1414 - if (apparmor_initialized && !policy_view_capable(NULL)) 1414 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1415 1415 return -EPERM; 1416 1416 return param_get_bool(buffer, kp); 1417 1417 } ··· 1420 1420 { 1421 1421 if (!apparmor_enabled) 1422 1422 return -EINVAL; 1423 - if (apparmor_initialized && !policy_admin_capable(NULL)) 1423 + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 1424 1424 return -EPERM; 1425 1425 return param_set_bool(val, kp); 1426 1426 } ··· 1429 1429 { 1430 1430 if (!apparmor_enabled) 1431 1431 return -EINVAL; 1432 - if (apparmor_initialized && !policy_view_capable(NULL)) 1432 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1433 1433 return -EPERM; 1434 1434 return param_get_bool(buffer, kp); 1435 1435 } ··· 1455 1455 { 1456 1456 if (!apparmor_enabled) 1457 1457 return -EINVAL; 1458 - if (apparmor_initialized && !policy_view_capable(NULL)) 1458 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1459 1459 return -EPERM; 1460 1460 return param_get_uint(buffer, kp); 1461 1461 } ··· 1526 1526 { 1527 1527 if (!apparmor_enabled) 1528 1528 return -EINVAL; 1529 - if (apparmor_initialized && !policy_view_capable(NULL)) 1529 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1530 1530 return -EPERM; 1531 1531 return param_get_int(buffer, kp); 1532 1532 } ··· 1535 1535 { 1536 1536 if (!apparmor_enabled) 1537 1537 return -EINVAL; 1538 - if (apparmor_initialized && !policy_view_capable(NULL)) 1538 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1539 1539 return -EPERM; 1540 1540 return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); 1541 1541 } ··· 1548 1548 return -EINVAL; 1549 1549 if (!val) 1550 1550 return -EINVAL; 1551 - if (apparmor_initialized && !policy_admin_capable(NULL)) 1551 + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 1552 1552 return -EPERM; 1553 1553 1554 1554 i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val); ··· 1563 1563 { 1564 1564 if (!apparmor_enabled) 1565 1565 return -EINVAL; 1566 - if (apparmor_initialized && !policy_view_capable(NULL)) 1566 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1567 1567 return -EPERM; 1568 1568 1569 1569 return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); ··· 1577 1577 return -EINVAL; 1578 1578 if (!val) 1579 1579 return -EINVAL; 1580 - if (apparmor_initialized && !policy_admin_capable(NULL)) 1580 + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 1581 1581 return -EPERM; 1582 1582 1583 1583 i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX, ··· 1713 1713 static int apparmor_dointvec(struct ctl_table *table, int write, 1714 1714 void *buffer, size_t *lenp, loff_t *ppos) 1715 1715 { 1716 - if (!policy_admin_capable(NULL)) 1716 + if (!aa_current_policy_admin_capable(NULL)) 1717 1717 return -EPERM; 1718 1718 if (!apparmor_enabled) 1719 1719 return -EINVAL; ··· 1773 1773 1774 1774 } 1775 1775 1776 - static unsigned int apparmor_ipv4_postroute(void *priv, 1777 - struct sk_buff *skb, 1778 - const struct nf_hook_state *state) 1779 - { 1780 - return apparmor_ip_postroute(priv, skb, state); 1781 - } 1782 - 1783 - #if IS_ENABLED(CONFIG_IPV6) 1784 - static unsigned int apparmor_ipv6_postroute(void *priv, 1785 - struct sk_buff *skb, 1786 - const struct nf_hook_state *state) 1787 - { 1788 - return apparmor_ip_postroute(priv, skb, state); 1789 - } 1790 - #endif 1791 - 1792 1776 static const struct nf_hook_ops apparmor_nf_ops[] = { 1793 1777 { 1794 - .hook = apparmor_ipv4_postroute, 1778 + .hook = apparmor_ip_postroute, 1795 1779 .pf = NFPROTO_IPV4, 1796 1780 .hooknum = NF_INET_POST_ROUTING, 1797 1781 .priority = NF_IP_PRI_SELINUX_FIRST, 1798 1782 }, 1799 1783 #if IS_ENABLED(CONFIG_IPV6) 1800 1784 { 1801 - .hook = apparmor_ipv6_postroute, 1785 + .hook = apparmor_ip_postroute, 1802 1786 .pf = NFPROTO_IPV6, 1803 1787 .hooknum = NF_INET_POST_ROUTING, 1804 1788 .priority = NF_IP6_PRI_SELINUX_FIRST,
+1 -1
security/apparmor/path.c
··· 83 83 * 84 84 * Returns: %0 else error code if path lookup fails 85 85 * When no error the path name is returned in @name which points to 86 - * to a position in @buf 86 + * a position in @buf 87 87 */ 88 88 static int d_namespace_path(const struct path *path, char *buf, char **name, 89 89 int flags, const char *disconnected)
+51 -11
security/apparmor/policy.c
··· 260 260 struct aa_profile *profile; 261 261 262 262 /* freed by free_profile - usually through aa_put_profile */ 263 - profile = kzalloc(sizeof(*profile) + sizeof(struct aa_profile *) * 2, 264 - gfp); 263 + profile = kzalloc(struct_size(profile, label.vec, 2), gfp); 265 264 if (!profile) 266 265 return NULL; 267 266 ··· 631 632 return error; 632 633 } 633 634 635 + /* don't call out to other LSMs in the stack for apparmor policy admin 636 + * permissions 637 + */ 638 + static int policy_ns_capable(struct aa_label *label, 639 + struct user_namespace *userns, int cap) 640 + { 641 + int err; 642 + 643 + /* check for MAC_ADMIN cap in cred */ 644 + err = cap_capable(current_cred(), userns, cap, CAP_OPT_NONE); 645 + if (!err) 646 + err = aa_capable(label, cap, CAP_OPT_NONE); 647 + 648 + return err; 649 + } 650 + 634 651 /** 635 - * policy_view_capable - check if viewing policy in at @ns is allowed 636 - * ns: namespace being viewed by current task (may be NULL) 652 + * aa_policy_view_capable - check if viewing policy in at @ns is allowed 653 + * label: label that is trying to view policy in ns 654 + * ns: namespace being viewed by @label (may be NULL if @label's ns) 637 655 * Returns: true if viewing policy is allowed 638 656 * 639 657 * If @ns is NULL then the namespace being viewed is assumed to be the 640 658 * tasks current namespace. 641 659 */ 642 - bool policy_view_capable(struct aa_ns *ns) 660 + bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns) 643 661 { 644 662 struct user_namespace *user_ns = current_user_ns(); 645 - struct aa_ns *view_ns = aa_get_current_ns(); 663 + struct aa_ns *view_ns = labels_view(label); 646 664 bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) || 647 665 in_egroup_p(make_kgid(user_ns, 0)); 648 666 bool response = false; ··· 671 655 (unprivileged_userns_apparmor_policy != 0 && 672 656 user_ns->level == view_ns->level))) 673 657 response = true; 674 - aa_put_ns(view_ns); 675 658 676 659 return response; 677 660 } 678 661 679 - bool policy_admin_capable(struct aa_ns *ns) 662 + bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns) 680 663 { 681 664 struct user_namespace *user_ns = current_user_ns(); 682 - bool capable = ns_capable(user_ns, CAP_MAC_ADMIN); 665 + bool capable = policy_ns_capable(label, user_ns, CAP_MAC_ADMIN) == 0; 683 666 684 667 AA_DEBUG("cap_mac_admin? %d\n", capable); 685 668 AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); 686 669 687 - return policy_view_capable(ns) && capable && !aa_g_lock_policy; 670 + return aa_policy_view_capable(label, ns) && capable && 671 + !aa_g_lock_policy; 672 + } 673 + 674 + bool aa_current_policy_view_capable(struct aa_ns *ns) 675 + { 676 + struct aa_label *label; 677 + bool res; 678 + 679 + label = __begin_current_label_crit_section(); 680 + res = aa_policy_view_capable(label, ns); 681 + __end_current_label_crit_section(label); 682 + 683 + return res; 684 + } 685 + 686 + bool aa_current_policy_admin_capable(struct aa_ns *ns) 687 + { 688 + struct aa_label *label; 689 + bool res; 690 + 691 + label = __begin_current_label_crit_section(); 692 + res = aa_policy_admin_capable(label, ns); 693 + __end_current_label_crit_section(label); 694 + 695 + return res; 688 696 } 689 697 690 698 /** ··· 734 694 return audit_policy(label, op, NULL, NULL, "policy_locked", 735 695 -EACCES); 736 696 737 - if (!policy_admin_capable(ns)) 697 + if (!aa_policy_admin_capable(label, ns)) 738 698 return audit_policy(label, op, NULL, NULL, "not policy admin", 739 699 -EACCES); 740 700
+1 -1
security/apparmor/policy_unpack.c
··· 39 39 40 40 /* 41 41 * The AppArmor interface treats data as a type byte followed by the 42 - * actual data. The interface has the notion of a a named entry 42 + * actual data. The interface has the notion of a named entry 43 43 * which has a name (AA_NAME typecode followed by name string) followed by 44 44 * the entries typecode and data. Named types allow for optional 45 45 * elements and extensions to be added and tested for without breaking
-2
security/apparmor/procattr.c
··· 21 21 * @profile: the profile to print profile info about (NOT NULL) 22 22 * @string: Returns - string containing the profile info (NOT NULL) 23 23 * 24 - * Returns: length of @string on success else error on failure 25 - * 26 24 * Requires: profile != NULL 27 25 * 28 26 * Creates a string containing the namespace_name://profile_name for