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

apparmor: make export of raw binary profile to userspace optional

Embedded systems have limited space and don't need the introspection
or checkpoint restore capability provided by exporting the raw
profile binary data so make it so make it a config option.

This will reduce run time memory use and also speed up policy loads.

Signed-off-by: John Johansen <john.johansen@canonical.com>

+110 -51
+50 -28
security/apparmor/Kconfig
··· 6 6 select SECURITY_PATH 7 7 select SECURITYFS 8 8 select SECURITY_NETWORK 9 - select ZLIB_INFLATE 10 - select ZLIB_DEFLATE 11 9 default n 12 10 help 13 11 This enables the AppArmor security module. ··· 14 16 http://apparmor.wiki.kernel.org 15 17 16 18 If you are unsure how to answer this question, answer N. 17 - 18 - config SECURITY_APPARMOR_HASH 19 - bool "Enable introspection of sha1 hashes for loaded profiles" 20 - depends on SECURITY_APPARMOR 21 - select CRYPTO 22 - select CRYPTO_SHA1 23 - default y 24 - help 25 - This option selects whether introspection of loaded policy 26 - hashes is available to userspace via the apparmor 27 - filesystem. This option provides a light weight means of 28 - checking loaded policy. This option adds to policy load 29 - time and can be disabled for small embedded systems. 30 - 31 - config SECURITY_APPARMOR_HASH_DEFAULT 32 - bool "Enable policy hash introspection by default" 33 - depends on SECURITY_APPARMOR_HASH 34 - default y 35 - help 36 - This option selects whether sha1 hashing of loaded policy 37 - is enabled by default. The generation of sha1 hashes for 38 - loaded policy provide system administrators a quick way 39 - to verify that policy in the kernel matches what is expected, 40 - however it can slow down policy load on some devices. In 41 - these cases policy hashing can be disabled by default and 42 - enabled only if needed. 43 19 44 20 config SECURITY_APPARMOR_DEBUG 45 21 bool "Build AppArmor with debug code" ··· 43 71 Set the default value of the apparmor.debug kernel parameter. 44 72 When enabled, various debug messages will be logged to 45 73 the kernel message buffer. 74 + 75 + config SECURITY_APPARMOR_INTROSPECT_POLICY 76 + bool "Allow loaded policy to be introspected" 77 + depends on SECURITY_APPARMOR 78 + default y 79 + help 80 + This option selects whether introspection of loaded policy 81 + is available to userspace via the apparmor filesystem. This 82 + adds to kernel memory usage. It is required for introspection 83 + of loaded policy, and check point and restore support. It 84 + can be disabled for embedded systems where reducing memory and 85 + cpu is paramount. 86 + 87 + config SECURITY_APPARMOR_HASH 88 + bool "Enable introspection of sha1 hashes for loaded profiles" 89 + depends on SECURITY_APPARMOR_INTROSPECT_POLICY 90 + select CRYPTO 91 + select CRYPTO_SHA1 92 + default y 93 + help 94 + This option selects whether introspection of loaded policy 95 + hashes is available to userspace via the apparmor 96 + filesystem. This option provides a light weight means of 97 + checking loaded policy. This option adds to policy load 98 + time and can be disabled for small embedded systems. 99 + 100 + config SECURITY_APPARMOR_HASH_DEFAULT 101 + bool "Enable policy hash introspection by default" 102 + depends on SECURITY_APPARMOR_HASH 103 + default y 104 + help 105 + This option selects whether sha1 hashing of loaded policy 106 + is enabled by default. The generation of sha1 hashes for 107 + loaded policy provide system administrators a quick way 108 + to verify that policy in the kernel matches what is expected, 109 + however it can slow down policy load on some devices. In 110 + these cases policy hashing can be disabled by default and 111 + enabled only if needed. 112 + 113 + config SECURITY_APPARMOR_EXPORT_BINARY 114 + bool "Allow exporting the raw binary policy" 115 + depends on SECURITY_APPARMOR_INTROSPECT_POLICY 116 + select ZLIB_INFLATE 117 + select ZLIB_DEFLATE 118 + default y 119 + help 120 + This option allows reading back binary policy as it was loaded. 121 + It increases the amount of kernel memory needed by policy and 122 + also increases policy load time. This option is required for 123 + checkpoint and restore support, and debugging of loaded policy. 46 124 47 125 config SECURITY_APPARMOR_KUNIT_TEST 48 126 bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
+9 -2
security/apparmor/apparmorfs.c
··· 70 70 struct aa_loaddata *loaddata; 71 71 }; 72 72 73 + #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 73 74 #define RAWDATA_F_DATA_BUF(p) (char *)(p + 1) 74 75 75 76 static void rawdata_f_data_free(struct rawdata_f_data *private) ··· 95 94 96 95 return ret; 97 96 } 97 + #endif 98 98 99 99 /** 100 100 * aa_mangle_name - mangle a profile name to std profile layout form ··· 1203 1201 1204 1202 1205 1203 /* policy/raw_data/ * file ops */ 1206 - 1204 + #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 1207 1205 #define SEQ_RAWDATA_FOPS(NAME) \ 1208 1206 static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\ 1209 1207 { \ ··· 1494 1492 1495 1493 return PTR_ERR(dent); 1496 1494 } 1495 + #endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ 1496 + 1497 1497 1498 1498 /** fns to setup dynamic per profile/namespace files **/ 1499 1499 ··· 1561 1557 return dent; 1562 1558 } 1563 1559 1560 + #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 1564 1561 static int profile_depth(struct aa_profile *profile) 1565 1562 { 1566 1563 int depth = 0; ··· 1663 1658 static const struct inode_operations rawdata_link_data_iops = { 1664 1659 .get_link = rawdata_get_link_data, 1665 1660 }; 1666 - 1661 + #endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ 1667 1662 1668 1663 /* 1669 1664 * Requires: @profile->ns->lock held ··· 1734 1729 profile->dents[AAFS_PROF_HASH] = dent; 1735 1730 } 1736 1731 1732 + #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 1737 1733 if (profile->rawdata) { 1738 1734 dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir, 1739 1735 profile->label.proxy, NULL, NULL, ··· 1760 1754 aa_get_proxy(profile->label.proxy); 1761 1755 profile->dents[AAFS_PROF_RAW_DATA] = dent; 1762 1756 } 1757 + #endif /*CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ 1763 1758 1764 1759 list_for_each_entry(child, &profile->base.profiles, base.list) { 1765 1760 error = __aafs_profile_mkdir(child, prof_child_dir(profile));
+1
security/apparmor/include/apparmor.h
··· 36 36 extern bool aa_g_audit_header; 37 37 extern bool aa_g_debug; 38 38 extern bool aa_g_hash_policy; 39 + extern bool aa_g_export_binary; 39 40 extern int aa_g_rawdata_compression_level; 40 41 extern bool aa_g_lock_policy; 41 42 extern bool aa_g_logsyscall;
+14
security/apparmor/include/apparmorfs.h
··· 114 114 struct dentry *dent); 115 115 116 116 struct aa_loaddata; 117 + 118 + #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 117 119 void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata); 118 120 int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata); 121 + #else 122 + static inline void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata) 123 + { 124 + /* empty stub */ 125 + } 126 + 127 + static inline int __aa_fs_create_rawdata(struct aa_ns *ns, 128 + struct aa_loaddata *rawdata) 129 + { 130 + return 0; 131 + } 132 + #endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ 119 133 120 134 #endif /* __AA_APPARMORFS_H */
+6
security/apparmor/lsm.c
··· 1357 1357 module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); 1358 1358 #endif 1359 1359 1360 + /* whether policy exactly as loaded is retained for debug and checkpointing */ 1361 + bool aa_g_export_binary = IS_ENABLED(CONFIG_SECURITY_APPARMOR_EXPORT_BINARY); 1362 + #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 1363 + module_param_named(export_binary, aa_g_export_binary, aabool, 0600); 1364 + #endif 1365 + 1360 1366 /* policy loaddata compression level */ 1361 1367 int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION; 1362 1368 module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
+18 -13
security/apparmor/policy.c
··· 952 952 953 953 mutex_lock_nested(&ns->lock, ns->level); 954 954 /* check for duplicate rawdata blobs: space and file dedup */ 955 - list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { 956 - if (aa_rawdata_eq(rawdata_ent, udata)) { 957 - struct aa_loaddata *tmp; 955 + if (!list_empty(&ns->rawdata_list)) { 956 + list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { 957 + if (aa_rawdata_eq(rawdata_ent, udata)) { 958 + struct aa_loaddata *tmp; 958 959 959 - tmp = __aa_get_loaddata(rawdata_ent); 960 - /* check we didn't fail the race */ 961 - if (tmp) { 962 - aa_put_loaddata(udata); 963 - udata = tmp; 964 - break; 960 + tmp = __aa_get_loaddata(rawdata_ent); 961 + /* check we didn't fail the race */ 962 + if (tmp) { 963 + aa_put_loaddata(udata); 964 + udata = tmp; 965 + break; 966 + } 965 967 } 966 968 } 967 969 } ··· 971 969 list_for_each_entry(ent, &lh, list) { 972 970 struct aa_policy *policy; 973 971 974 - ent->new->rawdata = aa_get_loaddata(udata); 972 + if (aa_g_export_binary) 973 + ent->new->rawdata = aa_get_loaddata(udata); 975 974 error = __lookup_replace(ns, ent->new->base.hname, 976 975 !(mask & AA_MAY_REPLACE_POLICY), 977 976 &ent->old, &info); ··· 1012 1009 } 1013 1010 1014 1011 /* create new fs entries for introspection if needed */ 1015 - if (!udata->dents[AAFS_LOADDATA_DIR]) { 1012 + if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) { 1016 1013 error = __aa_fs_create_rawdata(ns, udata); 1017 1014 if (error) { 1018 1015 info = "failed to create raw_data dir and files"; ··· 1040 1037 1041 1038 /* Done with checks that may fail - do actual replacement */ 1042 1039 __aa_bump_ns_revision(ns); 1043 - __aa_loaddata_update(udata, ns->revision); 1040 + if (aa_g_export_binary) 1041 + __aa_loaddata_update(udata, ns->revision); 1044 1042 list_for_each_entry_safe(ent, tmp, &lh, list) { 1045 1043 list_del_init(&ent->list); 1046 1044 op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; 1047 1045 1048 - if (ent->old && ent->old->rawdata == ent->new->rawdata) { 1046 + if (ent->old && ent->old->rawdata == ent->new->rawdata && 1047 + ent->new->rawdata) { 1049 1048 /* dedup actual profile replacement */ 1050 1049 audit_policy(label, op, ns_name, ent->new->base.hname, 1051 1050 "same as current profile, skipping",
+12 -8
security/apparmor/policy_unpack.c
··· 125 125 { 126 126 AA_BUG(!data); 127 127 AA_BUG(!data->ns); 128 - AA_BUG(!data->dents[AAFS_LOADDATA_REVISION]); 129 128 AA_BUG(!mutex_is_locked(&data->ns->lock)); 130 129 AA_BUG(data->revision > revision); 131 130 132 131 data->revision = revision; 133 - d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime = 134 - current_time(d_inode(data->dents[AAFS_LOADDATA_DIR])); 135 - d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime = 136 - current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION])); 132 + if ((data->dents[AAFS_LOADDATA_REVISION])) { 133 + d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime = 134 + current_time(d_inode(data->dents[AAFS_LOADDATA_DIR])); 135 + d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime = 136 + current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION])); 137 + } 137 138 } 138 139 139 140 bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r) ··· 1217 1216 goto fail; 1218 1217 } 1219 1218 } 1220 - error = compress_loaddata(udata); 1221 - if (error) 1222 - goto fail; 1219 + 1220 + if (aa_g_export_binary) { 1221 + error = compress_loaddata(udata); 1222 + if (error) 1223 + goto fail; 1224 + } 1223 1225 return 0; 1224 1226 1225 1227 fail_profile: