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

Merge tag 'apparmor-pr-2022-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor

Pull apparmor updates from John Johansen:
"Features:
- switch to zstd compression for profile raw data

Cleanups:
- simplify obtaining the newest label on a cred
- remove useless static inline functions
- compute permission conversion on policy unpack
- refactor code to share common permissins
- refactor unpack to group policy backwards compatiblity code
- add __init annotation to aa_{setup/teardown}_dfa_engine()

Bug Fixes:
- fix a memleak in
- multi_transaction_new()
- free_ruleset()
- unpack_profile()
- alloc_ns()
- fix lockdep warning when removing a namespace
- fix regression in stacking due to label flags
- fix loading of child before parent
- fix kernel-doc comments that differ from fns
- fix spelling errors in comments
- store return value of unpack_perms_table() to signed variable"

* tag 'apparmor-pr-2022-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (64 commits)
apparmor: Fix uninitialized symbol 'array_size' in policy_unpack_test.c
apparmor: Add __init annotation to aa_{setup/teardown}_dfa_engine()
apparmor: Fix memleak in alloc_ns()
apparmor: Fix memleak issue in unpack_profile()
apparmor: fix a memleak in free_ruleset()
apparmor: Fix spelling of function name in comment block
apparmor: Use pointer to struct aa_label for lbs_cred
AppArmor: Fix kernel-doc
LSM: Fix kernel-doc
AppArmor: Fix kernel-doc
apparmor: Fix loading of child before parent
apparmor: refactor code that alloc null profiles
apparmor: fix obsoleted comments for aa_getprocattr() and audit_resource()
apparmor: remove useless static inline functions
apparmor: Fix unpack_profile() warn: passing zero to 'ERR_PTR'
apparmor: fix uninitialize table variable in error in unpack_trans_table
apparmor: store return value of unpack_perms_table() to signed variable
apparmor: Fix kunit test for out of bounds array
apparmor: Fix decompression of rawdata for read back to userspace
apparmor: Fix undefined references to zstd_ symbols
...

+1633 -915
+2 -2
security/apparmor/Kconfig
··· 85 85 config SECURITY_APPARMOR_EXPORT_BINARY 86 86 bool "Allow exporting the raw binary policy" 87 87 depends on SECURITY_APPARMOR_INTROSPECT_POLICY 88 - select ZLIB_INFLATE 89 - select ZLIB_DEFLATE 88 + select ZSTD_COMPRESS 89 + select ZSTD_DECOMPRESS 90 90 default y 91 91 help 92 92 This option allows reading back binary policy as it was loaded.
+2 -1
security/apparmor/Makefile
··· 5 5 6 6 apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \ 7 7 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ 8 - resource.o secid.o file.o policy_ns.o label.o mount.o net.o 8 + resource.o secid.o file.o policy_ns.o label.o mount.o net.o \ 9 + policy_compat.o 9 10 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o 10 11 11 12 obj-$(CONFIG_SECURITY_APPARMOR_KUNIT_TEST) += apparmor_policy_unpack_test.o
+62 -51
security/apparmor/apparmorfs.c
··· 21 21 #include <linux/fs.h> 22 22 #include <linux/fs_context.h> 23 23 #include <linux/poll.h> 24 - #include <linux/zlib.h> 24 + #include <linux/zstd.h> 25 25 #include <uapi/linux/major.h> 26 26 #include <uapi/linux/magic.h> 27 27 ··· 611 611 static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, 612 612 const char *match_str, size_t match_len) 613 613 { 614 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 615 + typeof(*rules), list); 614 616 struct aa_perms tmp = { }; 615 - struct aa_dfa *dfa; 616 - unsigned int state = 0; 617 + aa_state_t state = DFA_NOMATCH; 617 618 618 619 if (profile_unconfined(profile)) 619 620 return; 620 - if (profile->file.dfa && *match_str == AA_CLASS_FILE) { 621 - dfa = profile->file.dfa; 622 - state = aa_dfa_match_len(dfa, profile->file.start, 621 + if (rules->file.dfa && *match_str == AA_CLASS_FILE) { 622 + state = aa_dfa_match_len(rules->file.dfa, 623 + rules->file.start[AA_CLASS_FILE], 623 624 match_str + 1, match_len - 1); 624 625 if (state) { 625 626 struct path_cond cond = { }; 626 627 627 - tmp = aa_compute_fperms(dfa, state, &cond); 628 + tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 628 629 } 629 - } else if (profile->policy.dfa) { 630 - if (!PROFILE_MEDIATES(profile, *match_str)) 630 + } else if (rules->policy.dfa) { 631 + if (!RULE_MEDIATES(rules, *match_str)) 631 632 return; /* no change to current perms */ 632 - dfa = profile->policy.dfa; 633 - state = aa_dfa_match_len(dfa, profile->policy.start[0], 633 + state = aa_dfa_match_len(rules->policy.dfa, 634 + rules->policy.start[0], 634 635 match_str, match_len); 635 636 if (state) 636 - aa_compute_perms(dfa, state, &tmp); 637 + tmp = *aa_lookup_perms(&rules->policy, state); 637 638 } 638 639 aa_apply_modes_to_perms(profile, &tmp); 639 640 aa_perms_accum_raw(perms, &tmp); ··· 869 868 if (!t) 870 869 return ERR_PTR(-ENOMEM); 871 870 kref_init(&t->count); 872 - if (copy_from_user(t->data, buf, size)) 871 + if (copy_from_user(t->data, buf, size)) { 872 + put_multi_transaction(t); 873 873 return ERR_PTR(-EFAULT); 874 + } 874 875 875 876 return t; 876 877 } ··· 1093 1090 struct aa_proxy *proxy = seq->private; 1094 1091 struct aa_label *label = aa_get_label_rcu(&proxy->label); 1095 1092 struct aa_profile *profile = labels_profile(label); 1096 - if (profile->attach) 1097 - seq_printf(seq, "%s\n", profile->attach); 1098 - else if (profile->xmatch) 1093 + if (profile->attach.xmatch_str) 1094 + seq_printf(seq, "%s\n", profile->attach.xmatch_str); 1095 + else if (profile->attach.xmatch.dfa) 1099 1096 seq_puts(seq, "<unknown>\n"); 1100 1097 else 1101 1098 seq_printf(seq, "%s\n", profile->base.name); ··· 1200 1197 return 0; 1201 1198 } 1202 1199 1200 + static int seq_ns_compress_min_show(struct seq_file *seq, void *v) 1201 + { 1202 + seq_printf(seq, "%d\n", AA_MIN_CLEVEL); 1203 + return 0; 1204 + } 1205 + 1206 + static int seq_ns_compress_max_show(struct seq_file *seq, void *v) 1207 + { 1208 + seq_printf(seq, "%d\n", AA_MAX_CLEVEL); 1209 + return 0; 1210 + } 1211 + 1203 1212 SEQ_NS_FOPS(stacked); 1204 1213 SEQ_NS_FOPS(nsstacked); 1205 1214 SEQ_NS_FOPS(level); 1206 1215 SEQ_NS_FOPS(name); 1216 + SEQ_NS_FOPS(compress_min); 1217 + SEQ_NS_FOPS(compress_max); 1207 1218 1208 1219 1209 1220 /* policy/raw_data/ * file ops */ ··· 1312 1295 SEQ_RAWDATA_FOPS(hash); 1313 1296 SEQ_RAWDATA_FOPS(compressed_size); 1314 1297 1315 - static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen) 1298 + static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen) 1316 1299 { 1317 1300 #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 1318 - if (aa_g_rawdata_compression_level != 0) { 1319 - int error = 0; 1320 - struct z_stream_s strm; 1301 + if (slen < dlen) { 1302 + const size_t wksp_len = zstd_dctx_workspace_bound(); 1303 + zstd_dctx *ctx; 1304 + void *wksp; 1305 + size_t out_len; 1306 + int ret = 0; 1321 1307 1322 - memset(&strm, 0, sizeof(strm)); 1323 - 1324 - strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); 1325 - if (!strm.workspace) 1326 - return -ENOMEM; 1327 - 1328 - strm.next_in = src; 1329 - strm.avail_in = slen; 1330 - 1331 - error = zlib_inflateInit(&strm); 1332 - if (error != Z_OK) { 1333 - error = -ENOMEM; 1334 - goto fail_inflate_init; 1308 + wksp = kvzalloc(wksp_len, GFP_KERNEL); 1309 + if (!wksp) { 1310 + ret = -ENOMEM; 1311 + goto cleanup; 1335 1312 } 1336 - 1337 - strm.next_out = dst; 1338 - strm.avail_out = dlen; 1339 - 1340 - error = zlib_inflate(&strm, Z_FINISH); 1341 - if (error != Z_STREAM_END) 1342 - error = -EINVAL; 1343 - else 1344 - error = 0; 1345 - 1346 - zlib_inflateEnd(&strm); 1347 - fail_inflate_init: 1348 - kvfree(strm.workspace); 1349 - 1350 - return error; 1313 + ctx = zstd_init_dctx(wksp, wksp_len); 1314 + if (ctx == NULL) { 1315 + ret = -ENOMEM; 1316 + goto cleanup; 1317 + } 1318 + out_len = zstd_decompress_dctx(ctx, dst, dlen, src, slen); 1319 + if (zstd_is_error(out_len)) { 1320 + ret = -EINVAL; 1321 + goto cleanup; 1322 + } 1323 + cleanup: 1324 + kvfree(wksp); 1325 + return ret; 1351 1326 } 1352 1327 #endif 1353 1328 ··· 1388 1379 1389 1380 private->loaddata = loaddata; 1390 1381 1391 - error = deflate_decompress(loaddata->data, loaddata->compressed_size, 1392 - RAWDATA_F_DATA_BUF(private), 1393 - loaddata->size); 1382 + error = decompress_zstd(loaddata->data, loaddata->compressed_size, 1383 + RAWDATA_F_DATA_BUF(private), 1384 + loaddata->size); 1394 1385 if (error) 1395 1386 goto fail_decompress; 1396 1387 ··· 2401 2392 AA_SFS_FILE_FOPS(".ns_level", 0444, &seq_ns_level_fops), 2402 2393 AA_SFS_FILE_FOPS(".ns_name", 0444, &seq_ns_name_fops), 2403 2394 AA_SFS_FILE_FOPS("profiles", 0444, &aa_sfs_profiles_fops), 2395 + AA_SFS_FILE_FOPS("raw_data_compression_level_min", 0444, &seq_ns_compress_min_fops), 2396 + AA_SFS_FILE_FOPS("raw_data_compression_level_max", 0444, &seq_ns_compress_max_fops), 2404 2397 AA_SFS_DIR("features", aa_sfs_entry_features), 2405 2398 { } 2406 2399 };
+44 -1
security/apparmor/audit.c
··· 36 36 "AUTO" 37 37 }; 38 38 39 + static const char *const aa_class_names[] = { 40 + "none", 41 + "unknown", 42 + "file", 43 + "cap", 44 + "net", 45 + "rlimits", 46 + "domain", 47 + "mount", 48 + "unknown", 49 + "ptrace", 50 + "signal", 51 + "xmatch", 52 + "unknown", 53 + "unknown", 54 + "net", 55 + "unknown", 56 + "label", 57 + "posix_mqueue", 58 + "io_uring", 59 + "module", 60 + "lsm", 61 + "unknown", 62 + "unknown", 63 + "unknown", 64 + "unknown", 65 + "unknown", 66 + "unknown", 67 + "unknown", 68 + "unknown", 69 + "unknown", 70 + "unknown", 71 + "X", 72 + "dbus", 73 + }; 74 + 75 + 39 76 /* 40 77 * Currently AppArmor auditing is fed straight into the audit framework. 41 78 * ··· 83 46 */ 84 47 85 48 /** 86 - * audit_base - core AppArmor function. 49 + * audit_pre() - core AppArmor function. 87 50 * @ab: audit buffer to fill (NOT NULL) 88 51 * @ca: audit structure containing data to audit (NOT NULL) 89 52 * ··· 101 64 if (aad(sa)->op) { 102 65 audit_log_format(ab, " operation=\"%s\"", aad(sa)->op); 103 66 } 67 + 68 + if (aad(sa)->class) 69 + audit_log_format(ab, " class=\"%s\"", 70 + aad(sa)->class <= AA_CLASS_LAST ? 71 + aa_class_names[aad(sa)->class] : 72 + "unknown"); 104 73 105 74 if (aad(sa)->info) { 106 75 audit_log_format(ab, " info=\"%s\"", aad(sa)->info);
+10 -6
security/apparmor/capability.c
··· 64 64 static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, 65 65 int cap, int error) 66 66 { 67 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 68 + typeof(*rules), list); 67 69 struct audit_cache *ent; 68 70 int type = AUDIT_APPARMOR_AUTO; 69 71 ··· 74 72 if (likely(!error)) { 75 73 /* test if auditing is being forced */ 76 74 if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && 77 - !cap_raised(profile->caps.audit, cap))) 75 + !cap_raised(rules->caps.audit, cap))) 78 76 return 0; 79 77 type = AUDIT_APPARMOR_AUDIT; 80 78 } else if (KILL_MODE(profile) || 81 - cap_raised(profile->caps.kill, cap)) { 79 + cap_raised(rules->caps.kill, cap)) { 82 80 type = AUDIT_APPARMOR_KILL; 83 - } else if (cap_raised(profile->caps.quiet, cap) && 81 + } else if (cap_raised(rules->caps.quiet, cap) && 84 82 AUDIT_MODE(profile) != AUDIT_NOQUIET && 85 83 AUDIT_MODE(profile) != AUDIT_ALL) { 86 84 /* quiet auditing */ ··· 116 114 static int profile_capable(struct aa_profile *profile, int cap, 117 115 unsigned int opts, struct common_audit_data *sa) 118 116 { 117 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 118 + typeof(*rules), list); 119 119 int error; 120 120 121 - if (cap_raised(profile->caps.allow, cap) && 122 - !cap_raised(profile->caps.denied, cap)) 121 + if (cap_raised(rules->caps.allow, cap) && 122 + !cap_raised(rules->caps.denied, cap)) 123 123 error = 0; 124 124 else 125 125 error = -EPERM; ··· 152 148 { 153 149 struct aa_profile *profile; 154 150 int error = 0; 155 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); 151 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, AA_CLASS_CAP, OP_CAPABLE); 156 152 157 153 sa.u.cap = cap; 158 154 error = fn_for_each_confined(label, profile,
+77 -70
security/apparmor/domain.c
··· 30 30 #include "include/policy_ns.h" 31 31 32 32 /** 33 - * aa_free_domain_entries - free entries in a domain table 34 - * @domain: the domain table to free (MAYBE NULL) 35 - */ 36 - void aa_free_domain_entries(struct aa_domain *domain) 37 - { 38 - int i; 39 - if (domain) { 40 - if (!domain->table) 41 - return; 42 - 43 - for (i = 0; i < domain->size; i++) 44 - kfree_sensitive(domain->table[i]); 45 - kfree_sensitive(domain->table); 46 - domain->table = NULL; 47 - } 48 - } 49 - 50 - /** 51 33 * may_change_ptraced_domain - check if can change profile on ptraced task 52 34 * @to_label: profile to change to (NOT NULL) 53 35 * @info: message if there is an error ··· 77 95 * If a subns profile is not to be matched should be prescreened with 78 96 * visibility test. 79 97 */ 80 - static inline unsigned int match_component(struct aa_profile *profile, 81 - struct aa_profile *tp, 82 - bool stack, unsigned int state) 98 + static inline aa_state_t match_component(struct aa_profile *profile, 99 + struct aa_profile *tp, 100 + bool stack, aa_state_t state) 83 101 { 102 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 103 + typeof(*rules), list); 84 104 const char *ns_name; 85 105 86 106 if (stack) 87 - state = aa_dfa_match(profile->file.dfa, state, "&"); 107 + state = aa_dfa_match(rules->file.dfa, state, "&"); 88 108 if (profile->ns == tp->ns) 89 - return aa_dfa_match(profile->file.dfa, state, tp->base.hname); 109 + return aa_dfa_match(rules->file.dfa, state, tp->base.hname); 90 110 91 111 /* try matching with namespace name and then profile */ 92 112 ns_name = aa_ns_name(profile->ns, tp->ns, true); 93 - state = aa_dfa_match_len(profile->file.dfa, state, ":", 1); 94 - state = aa_dfa_match(profile->file.dfa, state, ns_name); 95 - state = aa_dfa_match_len(profile->file.dfa, state, ":", 1); 96 - return aa_dfa_match(profile->file.dfa, state, tp->base.hname); 113 + state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); 114 + state = aa_dfa_match(rules->file.dfa, state, ns_name); 115 + state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); 116 + return aa_dfa_match(rules->file.dfa, state, tp->base.hname); 97 117 } 98 118 99 119 /** ··· 116 132 */ 117 133 static int label_compound_match(struct aa_profile *profile, 118 134 struct aa_label *label, bool stack, 119 - unsigned int state, bool subns, u32 request, 135 + aa_state_t state, bool subns, u32 request, 120 136 struct aa_perms *perms) 121 137 { 138 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 139 + typeof(*rules), list); 122 140 struct aa_profile *tp; 123 141 struct label_it i; 124 142 struct path_cond cond = { }; ··· 143 157 label_for_each_cont(i, label, tp) { 144 158 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 145 159 continue; 146 - state = aa_dfa_match(profile->file.dfa, state, "//&"); 160 + state = aa_dfa_match(rules->file.dfa, state, "//&"); 147 161 state = match_component(profile, tp, false, state); 148 162 if (!state) 149 163 goto fail; 150 164 } 151 - *perms = aa_compute_fperms(profile->file.dfa, state, &cond); 165 + *perms = *(aa_lookup_fperms(&(rules->file), state, &cond)); 152 166 aa_apply_modes_to_perms(profile, perms); 153 167 if ((perms->allow & request) != request) 154 168 return -EACCES; ··· 178 192 */ 179 193 static int label_components_match(struct aa_profile *profile, 180 194 struct aa_label *label, bool stack, 181 - unsigned int start, bool subns, u32 request, 195 + aa_state_t start, bool subns, u32 request, 182 196 struct aa_perms *perms) 183 197 { 198 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 199 + typeof(*rules), list); 184 200 struct aa_profile *tp; 185 201 struct label_it i; 186 202 struct aa_perms tmp; 187 203 struct path_cond cond = { }; 188 - unsigned int state = 0; 204 + aa_state_t state = 0; 189 205 190 206 /* find first subcomponent to test */ 191 207 label_for_each(i, label, tp) { ··· 203 215 return 0; 204 216 205 217 next: 206 - tmp = aa_compute_fperms(profile->file.dfa, state, &cond); 218 + tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 207 219 aa_apply_modes_to_perms(profile, &tmp); 208 220 aa_perms_accum(perms, &tmp); 209 221 label_for_each_cont(i, label, tp) { ··· 212 224 state = match_component(profile, tp, stack, start); 213 225 if (!state) 214 226 goto fail; 215 - tmp = aa_compute_fperms(profile->file.dfa, state, &cond); 227 + tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 216 228 aa_apply_modes_to_perms(profile, &tmp); 217 229 aa_perms_accum(perms, &tmp); 218 230 } ··· 240 252 * Returns: the state the match finished in, may be the none matching state 241 253 */ 242 254 static int label_match(struct aa_profile *profile, struct aa_label *label, 243 - bool stack, unsigned int state, bool subns, u32 request, 255 + bool stack, aa_state_t state, bool subns, u32 request, 244 256 struct aa_perms *perms) 245 257 { 246 258 int error; ··· 274 286 */ 275 287 static int change_profile_perms(struct aa_profile *profile, 276 288 struct aa_label *target, bool stack, 277 - u32 request, unsigned int start, 289 + u32 request, aa_state_t start, 278 290 struct aa_perms *perms) 279 291 { 280 292 if (profile_unconfined(profile)) { ··· 296 308 * Returns: number of extended attributes that matched, or < 0 on error 297 309 */ 298 310 static int aa_xattrs_match(const struct linux_binprm *bprm, 299 - struct aa_profile *profile, unsigned int state) 311 + struct aa_profile *profile, aa_state_t state) 300 312 { 301 313 int i; 302 314 struct dentry *d; 303 315 char *value = NULL; 304 - int size, value_size = 0, ret = profile->xattr_count; 316 + struct aa_attachment *attach = &profile->attach; 317 + int size, value_size = 0, ret = attach->xattr_count; 305 318 306 - if (!bprm || !profile->xattr_count) 319 + if (!bprm || !attach->xattr_count) 307 320 return 0; 308 321 might_sleep(); 309 322 310 323 /* transition from exec match to xattr set */ 311 - state = aa_dfa_outofband_transition(profile->xmatch, state); 324 + state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); 312 325 d = bprm->file->f_path.dentry; 313 326 314 - for (i = 0; i < profile->xattr_count; i++) { 315 - size = vfs_getxattr_alloc(&init_user_ns, d, profile->xattrs[i], 327 + for (i = 0; i < attach->xattr_count; i++) { 328 + size = vfs_getxattr_alloc(&init_user_ns, d, attach->xattrs[i], 316 329 &value, value_size, GFP_KERNEL); 317 330 if (size >= 0) { 318 - u32 perm; 331 + u32 index, perm; 319 332 320 333 /* 321 334 * Check the xattr presence before value. This ensure 322 335 * that not present xattr can be distinguished from a 0 323 336 * length value or rule that matches any value 324 337 */ 325 - state = aa_dfa_null_transition(profile->xmatch, state); 338 + state = aa_dfa_null_transition(attach->xmatch.dfa, 339 + state); 326 340 /* Check xattr value */ 327 - state = aa_dfa_match_len(profile->xmatch, state, value, 328 - size); 329 - perm = dfa_user_allow(profile->xmatch, state); 341 + state = aa_dfa_match_len(attach->xmatch.dfa, state, 342 + value, size); 343 + index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; 344 + perm = attach->xmatch.perms[index].allow; 330 345 if (!(perm & MAY_EXEC)) { 331 346 ret = -EINVAL; 332 347 goto out; 333 348 } 334 349 } 335 350 /* transition to next element */ 336 - state = aa_dfa_outofband_transition(profile->xmatch, state); 351 + state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); 337 352 if (size < 0) { 338 353 /* 339 354 * No xattr match, so verify if transition to ··· 388 397 rcu_read_lock(); 389 398 restart: 390 399 list_for_each_entry_rcu(profile, head, base.list) { 400 + struct aa_attachment *attach = &profile->attach; 401 + 391 402 if (profile->label.flags & FLAG_NULL && 392 403 &profile->label == ns_unconfined(profile->ns)) 393 404 continue; ··· 405 412 * as another profile, signal a conflict and refuse to 406 413 * match. 407 414 */ 408 - if (profile->xmatch) { 409 - unsigned int state, count; 410 - u32 perm; 415 + if (attach->xmatch.dfa) { 416 + unsigned int count; 417 + aa_state_t state; 418 + u32 index, perm; 411 419 412 - state = aa_dfa_leftmatch(profile->xmatch, DFA_START, 413 - name, &count); 414 - perm = dfa_user_allow(profile->xmatch, state); 420 + state = aa_dfa_leftmatch(attach->xmatch.dfa, 421 + attach->xmatch.start[AA_CLASS_XMATCH], 422 + name, &count); 423 + index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; 424 + perm = attach->xmatch.perms[index].allow; 415 425 /* any accepting state means a valid match. */ 416 426 if (perm & MAY_EXEC) { 417 427 int ret = 0; ··· 422 426 if (count < candidate_len) 423 427 continue; 424 428 425 - if (bprm && profile->xattr_count) { 429 + if (bprm && attach->xattr_count) { 426 430 long rev = READ_ONCE(ns->revision); 427 431 428 432 if (!aa_get_profile_not0(profile)) ··· 461 465 * xattrs, or a longer match 462 466 */ 463 467 candidate = profile; 464 - candidate_len = max(count, profile->xmatch_len); 468 + candidate_len = max(count, attach->xmatch_len); 465 469 candidate_xattrs = ret; 466 470 conflict = false; 467 471 } ··· 505 509 struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, 506 510 const char **name) 507 511 { 512 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 513 + typeof(*rules), list); 508 514 struct aa_label *label = NULL; 509 515 u32 xtype = xindex & AA_X_TYPE_MASK; 510 516 int index = xindex & AA_X_INDEX_MASK; ··· 517 519 /* TODO: move lookup parsing to unpack time so this is a straight 518 520 * index into the resultant label 519 521 */ 520 - for (*name = profile->file.trans.table[index]; !label && *name; 522 + for (*name = rules->file.trans.table[index]; !label && *name; 521 523 *name = next_name(xtype, *name)) { 522 524 if (xindex & AA_X_CHILD) { 523 525 struct aa_profile *new_profile; ··· 556 558 const char **lookupname, 557 559 const char **info) 558 560 { 561 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 562 + typeof(*rules), list); 559 563 struct aa_label *new = NULL; 560 564 struct aa_ns *ns = profile->ns; 561 565 u32 xtype = xindex & AA_X_TYPE_MASK; ··· 570 570 break; 571 571 case AA_X_TABLE: 572 572 /* TODO: fix when perm mapping done at unload */ 573 - stack = profile->file.trans.table[xindex & AA_X_INDEX_MASK]; 573 + stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK]; 574 574 if (*stack != '&') { 575 575 /* released by caller */ 576 576 new = x_table_lookup(profile, xindex, lookupname); ··· 624 624 char *buffer, struct path_cond *cond, 625 625 bool *secure_exec) 626 626 { 627 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 628 + typeof(*rules), list); 627 629 struct aa_label *new = NULL; 628 630 const char *info = NULL, *name = NULL, *target = NULL; 629 - unsigned int state = profile->file.start; 631 + aa_state_t state = rules->file.start[AA_CLASS_FILE]; 630 632 struct aa_perms perms = {}; 631 633 bool nonewprivs = false; 632 634 int error = 0; ··· 662 660 } 663 661 664 662 /* find exec permissions for name */ 665 - state = aa_str_perms(profile->file.dfa, state, name, cond, &perms); 663 + state = aa_str_perms(&(rules->file), state, name, cond, &perms); 666 664 if (perms.allow & MAY_EXEC) { 667 665 /* exec permission determine how to transition */ 668 666 new = x_to_label(profile, bprm, name, perms.xindex, &target, ··· 680 678 /* no exec permission - learning mode */ 681 679 struct aa_profile *new_profile = NULL; 682 680 683 - new_profile = aa_new_null_profile(profile, false, name, 684 - GFP_KERNEL); 681 + new_profile = aa_new_learning_profile(profile, false, name, 682 + GFP_KERNEL); 685 683 if (!new_profile) { 686 684 error = -ENOMEM; 687 685 info = "could not create null profile"; ··· 724 722 char *buffer, struct path_cond *cond, 725 723 bool *secure_exec) 726 724 { 727 - unsigned int state = profile->file.start; 725 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 726 + typeof(*rules), list); 727 + aa_state_t state = rules->file.start[AA_CLASS_FILE]; 728 728 struct aa_perms perms = {}; 729 729 const char *xname = NULL, *info = "change_profile onexec"; 730 730 int error = -EACCES; ··· 759 755 } 760 756 761 757 /* find exec permissions for name */ 762 - state = aa_str_perms(profile->file.dfa, state, xname, cond, &perms); 758 + state = aa_str_perms(&(rules->file), state, xname, cond, &perms); 763 759 if (!(perms.allow & AA_MAY_ONEXEC)) { 764 760 info = "no change_onexec valid for executable"; 765 761 goto audit; ··· 768 764 * onexec permission is linked to exec with a standard pairing 769 765 * exec\0change_profile 770 766 */ 771 - state = aa_dfa_null_transition(profile->file.dfa, state); 767 + state = aa_dfa_null_transition(rules->file.dfa, state); 772 768 error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC, 773 769 state, &perms); 774 770 if (error) { ··· 1008 1004 if (!hat) { 1009 1005 error = -ENOENT; 1010 1006 if (COMPLAIN_MODE(profile)) { 1011 - hat = aa_new_null_profile(profile, true, name, 1012 - GFP_KERNEL); 1007 + hat = aa_new_learning_profile(profile, true, name, 1008 + GFP_KERNEL); 1013 1009 if (!hat) { 1014 1010 info = "failed null profile create"; 1015 1011 error = -ENOMEM; ··· 1265 1261 struct aa_label *target, bool stack, 1266 1262 u32 request, struct aa_perms *perms) 1267 1263 { 1264 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 1265 + typeof(*rules), list); 1268 1266 const char *info = NULL; 1269 1267 int error = 0; 1270 1268 1271 1269 if (!error) 1272 1270 error = change_profile_perms(profile, target, stack, request, 1273 - profile->file.start, perms); 1271 + rules->file.start[AA_CLASS_FILE], 1272 + perms); 1274 1273 if (error) 1275 1274 error = aa_audit_file(profile, perms, op, request, name, 1276 1275 NULL, target, GLOBAL_ROOT_UID, info, ··· 1360 1353 !COMPLAIN_MODE(labels_profile(label))) 1361 1354 goto audit; 1362 1355 /* released below */ 1363 - tprofile = aa_new_null_profile(labels_profile(label), false, 1364 - fqname, GFP_KERNEL); 1356 + tprofile = aa_new_learning_profile(labels_profile(label), false, 1357 + fqname, GFP_KERNEL); 1365 1358 if (!tprofile) { 1366 1359 info = "failed null profile create"; 1367 1360 error = -ENOMEM;
+37 -88
security/apparmor/file.c
··· 95 95 kuid_t ouid, const char *info, int error) 96 96 { 97 97 int type = AUDIT_APPARMOR_AUTO; 98 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, op); 98 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, AA_CLASS_FILE, op); 99 99 100 100 sa.u.tsk = NULL; 101 101 aad(&sa)->request = request; ··· 141 141 return aa_audit(type, profile, &sa, file_audit_cb); 142 142 } 143 143 144 - /** 145 - * is_deleted - test if a file has been completely unlinked 146 - * @dentry: dentry of file to test for deletion (NOT NULL) 147 - * 148 - * Returns: true if deleted else false 149 - */ 150 - static inline bool is_deleted(struct dentry *dentry) 151 - { 152 - if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0) 153 - return true; 154 - return false; 155 - } 156 - 157 144 static int path_name(const char *op, struct aa_label *label, 158 145 const struct path *path, int flags, char *buffer, 159 146 const char **name, struct path_cond *cond, u32 request) ··· 162 175 } 163 176 164 177 /** 165 - * map_old_perms - map old file perms layout to the new layout 166 - * @old: permission set in old mapping 167 - * 168 - * Returns: new permission mapping 169 - */ 170 - static u32 map_old_perms(u32 old) 171 - { 172 - u32 new = old & 0xf; 173 - if (old & MAY_READ) 174 - new |= AA_MAY_GETATTR | AA_MAY_OPEN; 175 - if (old & MAY_WRITE) 176 - new |= AA_MAY_SETATTR | AA_MAY_CREATE | AA_MAY_DELETE | 177 - AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_OPEN; 178 - if (old & 0x10) 179 - new |= AA_MAY_LINK; 180 - /* the old mapping lock and link_subset flags where overlaid 181 - * and use was determined by part of a pair that they were in 182 - */ 183 - if (old & 0x20) 184 - new |= AA_MAY_LOCK | AA_LINK_SUBSET; 185 - if (old & 0x40) /* AA_EXEC_MMAP */ 186 - new |= AA_EXEC_MMAP; 187 - 188 - return new; 189 - } 190 - 191 - /** 192 - * aa_compute_fperms - convert dfa compressed perms to internal perms 193 - * @dfa: dfa to compute perms for (NOT NULL) 178 + * aa_lookup_fperms - convert dfa compressed perms to internal perms 179 + * @dfa: dfa to lookup perms for (NOT NULL) 194 180 * @state: state in dfa 195 181 * @cond: conditions to consider (NOT NULL) 196 182 * 197 - * TODO: convert from dfa + state to permission entry, do computation conversion 198 - * at load time. 183 + * TODO: convert from dfa + state to permission entry 199 184 * 200 - * Returns: computed permission set 185 + * Returns: a pointer to a file permission set 201 186 */ 202 - struct aa_perms aa_compute_fperms(struct aa_dfa *dfa, unsigned int state, 203 - struct path_cond *cond) 187 + struct aa_perms default_perms = {}; 188 + struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules, 189 + aa_state_t state, struct path_cond *cond) 204 190 { 205 - /* FIXME: change over to new dfa format 206 - * currently file perms are encoded in the dfa, new format 207 - * splits the permissions from the dfa. This mapping can be 208 - * done at profile load 209 - */ 210 - struct aa_perms perms = { }; 191 + unsigned int index = ACCEPT_TABLE(file_rules->dfa)[state]; 211 192 212 - if (uid_eq(current_fsuid(), cond->uid)) { 213 - perms.allow = map_old_perms(dfa_user_allow(dfa, state)); 214 - perms.audit = map_old_perms(dfa_user_audit(dfa, state)); 215 - perms.quiet = map_old_perms(dfa_user_quiet(dfa, state)); 216 - perms.xindex = dfa_user_xindex(dfa, state); 217 - } else { 218 - perms.allow = map_old_perms(dfa_other_allow(dfa, state)); 219 - perms.audit = map_old_perms(dfa_other_audit(dfa, state)); 220 - perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); 221 - perms.xindex = dfa_other_xindex(dfa, state); 222 - } 223 - perms.allow |= AA_MAY_GETATTR; 193 + if (!(file_rules->perms)) 194 + return &default_perms; 224 195 225 - /* change_profile wasn't determined by ownership in old mapping */ 226 - if (ACCEPT_TABLE(dfa)[state] & 0x80000000) 227 - perms.allow |= AA_MAY_CHANGE_PROFILE; 228 - if (ACCEPT_TABLE(dfa)[state] & 0x40000000) 229 - perms.allow |= AA_MAY_ONEXEC; 196 + if (uid_eq(current_fsuid(), cond->uid)) 197 + return &(file_rules->perms[index]); 230 198 231 - return perms; 199 + return &(file_rules->perms[index + 1]); 232 200 } 233 201 234 202 /** ··· 196 254 * 197 255 * Returns: the final state in @dfa when beginning @start and walking @name 198 256 */ 199 - unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start, 200 - const char *name, struct path_cond *cond, 201 - struct aa_perms *perms) 257 + aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start, 258 + const char *name, struct path_cond *cond, 259 + struct aa_perms *perms) 202 260 { 203 - unsigned int state; 204 - state = aa_dfa_match(dfa, start, name); 205 - *perms = aa_compute_fperms(dfa, state, cond); 261 + aa_state_t state; 262 + state = aa_dfa_match(file_rules->dfa, start, name); 263 + *perms = *(aa_lookup_fperms(file_rules, state, cond)); 206 264 207 265 return state; 208 266 } 209 267 210 - int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name, 211 - u32 request, struct path_cond *cond, int flags, 212 - struct aa_perms *perms) 268 + static int __aa_path_perm(const char *op, struct aa_profile *profile, 269 + const char *name, u32 request, 270 + struct path_cond *cond, int flags, 271 + struct aa_perms *perms) 213 272 { 273 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 274 + typeof(*rules), list); 214 275 int e = 0; 215 276 216 277 if (profile_unconfined(profile)) 217 278 return 0; 218 - aa_str_perms(profile->file.dfa, profile->file.start, name, cond, perms); 279 + aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], 280 + name, cond, perms); 219 281 if (request & ~perms->allow) 220 282 e = -EACCES; 221 283 return aa_audit_file(profile, perms, op, request, name, NULL, NULL, ··· 306 360 const struct path *target, char *buffer2, 307 361 struct path_cond *cond) 308 362 { 363 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 364 + typeof(*rules), list); 309 365 const char *lname, *tname = NULL; 310 366 struct aa_perms lperms = {}, perms; 311 367 const char *info = NULL; 312 368 u32 request = AA_MAY_LINK; 313 - unsigned int state; 369 + aa_state_t state; 314 370 int error; 315 371 316 372 error = path_name(OP_LINK, &profile->label, link, profile->path_flags, ··· 328 380 329 381 error = -EACCES; 330 382 /* aa_str_perms - handles the case of the dfa being NULL */ 331 - state = aa_str_perms(profile->file.dfa, profile->file.start, lname, 383 + state = aa_str_perms(&(rules->file), 384 + rules->file.start[AA_CLASS_FILE], lname, 332 385 cond, &lperms); 333 386 334 387 if (!(lperms.allow & AA_MAY_LINK)) 335 388 goto audit; 336 389 337 390 /* test to see if target can be paired with link */ 338 - state = aa_dfa_null_transition(profile->file.dfa, state); 339 - aa_str_perms(profile->file.dfa, state, tname, cond, &perms); 391 + state = aa_dfa_null_transition(rules->file.dfa, state); 392 + aa_str_perms(&(rules->file), state, tname, cond, &perms); 340 393 341 394 /* force audit/quiet masks for link are stored in the second entry 342 395 * in the link pair. ··· 359 410 /* Do link perm subset test requiring allowed permission on link are 360 411 * a subset of the allowed permissions on target. 361 412 */ 362 - aa_str_perms(profile->file.dfa, profile->file.start, tname, cond, 363 - &perms); 413 + aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], 414 + tname, cond, &perms); 364 415 365 416 /* AA_MAY_LINK is not considered in the subset test */ 366 417 request = lperms.allow & ~AA_MAY_LINK;
+21 -2
security/apparmor/include/apparmor.h
··· 16 16 /* 17 17 * Class of mediation types in the AppArmor policy db 18 18 */ 19 - #define AA_CLASS_ENTRY 0 19 + #define AA_CLASS_NONE 0 20 20 #define AA_CLASS_UNKNOWN 1 21 21 #define AA_CLASS_FILE 2 22 22 #define AA_CLASS_CAP 3 ··· 26 26 #define AA_CLASS_MOUNT 7 27 27 #define AA_CLASS_PTRACE 9 28 28 #define AA_CLASS_SIGNAL 10 29 + #define AA_CLASS_XMATCH 11 29 30 #define AA_CLASS_NET 14 30 31 #define AA_CLASS_LABEL 16 32 + #define AA_CLASS_POSIX_MQUEUE 17 33 + #define AA_CLASS_IO_URING 18 34 + #define AA_CLASS_MODULE 19 35 + #define AA_CLASS_DISPLAY_LSM 20 31 36 32 - #define AA_CLASS_LAST AA_CLASS_LABEL 37 + #define AA_CLASS_X 31 38 + #define AA_CLASS_DBUS 32 39 + 40 + #define AA_CLASS_LAST AA_CLASS_DBUS 33 41 34 42 /* Control parameters settable through module/boot flags */ 35 43 extern enum audit_mode aa_g_audit; ··· 50 42 extern bool aa_g_logsyscall; 51 43 extern bool aa_g_paranoid_load; 52 44 extern unsigned int aa_g_path_max; 45 + 46 + #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 47 + #define AA_MIN_CLEVEL zstd_min_clevel() 48 + #define AA_MAX_CLEVEL zstd_max_clevel() 49 + #define AA_DEFAULT_CLEVEL ZSTD_CLEVEL_DEFAULT 50 + #else 51 + #define AA_MIN_CLEVEL 0 52 + #define AA_MAX_CLEVEL 0 53 + #define AA_DEFAULT_CLEVEL 0 54 + #endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ 55 + 53 56 54 57 #endif /* __APPARMOR_H */
+6 -2
security/apparmor/include/audit.h
··· 107 107 struct apparmor_audit_data { 108 108 int error; 109 109 int type; 110 + u16 class; 110 111 const char *op; 111 112 struct aa_label *label; 112 113 const char *name; ··· 156 155 157 156 /* macros for dealing with apparmor_audit_data structure */ 158 157 #define aad(SA) ((SA)->apparmor_audit_data) 159 - #define DEFINE_AUDIT_DATA(NAME, T, X) \ 158 + #define DEFINE_AUDIT_DATA(NAME, T, C, X) \ 160 159 /* TODO: cleanup audit init so we don't need _aad = {0,} */ \ 161 - struct apparmor_audit_data NAME ## _aad = { .op = (X), }; \ 160 + struct apparmor_audit_data NAME ## _aad = { \ 161 + .class = (C), \ 162 + .op = (X), \ 163 + }; \ 162 164 struct common_audit_data NAME = \ 163 165 { \ 164 166 .type = (T), \
-13
security/apparmor/include/cred.h
··· 64 64 } 65 65 66 66 /** 67 - * __aa_task_raw_label - retrieve another task's label 68 - * @task: task to query (NOT NULL) 69 - * 70 - * Returns: @task's label without incrementing its ref count 71 - * 72 - * If @task != current needs to be called in RCU safe critical section 73 - */ 74 - static inline struct aa_label *__aa_task_raw_label(struct task_struct *task) 75 - { 76 - return aa_cred_raw_label(__task_cred(task)); 77 - } 78 - 79 - /** 80 67 * aa_current_raw_label - find the current tasks confining label 81 68 * 82 69 * Returns: up to date confining label or the ns unconfined label (NOT NULL)
-6
security/apparmor/include/domain.h
··· 16 16 #ifndef __AA_DOMAIN_H 17 17 #define __AA_DOMAIN_H 18 18 19 - struct aa_domain { 20 - int size; 21 - char **table; 22 - }; 23 - 24 19 #define AA_CHANGE_NOFLAGS 0 25 20 #define AA_CHANGE_TEST 1 26 21 #define AA_CHANGE_CHILD 2 ··· 27 32 28 33 int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm); 29 34 30 - void aa_free_domain_entries(struct aa_domain *domain); 31 35 int aa_change_hat(const char *hats[], int count, u64 token, int flags); 32 36 int aa_change_profile(const char *fqname, int flags); 33 37
+15 -93
security/apparmor/include/file.h
··· 17 17 #include "match.h" 18 18 #include "perms.h" 19 19 20 + struct aa_policydb; 20 21 struct aa_profile; 21 22 struct path; 22 23 ··· 88 87 * - exec type - which determines how the executable name and index are used 89 88 * - flags - which modify how the destination name is applied 90 89 */ 91 - #define AA_X_INDEX_MASK 0x03ff 90 + #define AA_X_INDEX_MASK AA_INDEX_MASK 92 91 93 - #define AA_X_TYPE_MASK 0x0c00 94 - #define AA_X_TYPE_SHIFT 10 95 - #define AA_X_NONE 0x0000 96 - #define AA_X_NAME 0x0400 /* use executable name px */ 97 - #define AA_X_TABLE 0x0800 /* use a specified name ->n# */ 92 + #define AA_X_TYPE_MASK 0x0c000000 93 + #define AA_X_NONE AA_INDEX_NONE 94 + #define AA_X_NAME 0x04000000 /* use executable name px */ 95 + #define AA_X_TABLE 0x08000000 /* use a specified name ->n# */ 98 96 99 - #define AA_X_UNSAFE 0x1000 100 - #define AA_X_CHILD 0x2000 /* make >AA_X_NONE apply to children */ 101 - #define AA_X_INHERIT 0x4000 102 - #define AA_X_UNCONFINED 0x8000 97 + #define AA_X_UNSAFE 0x10000000 98 + #define AA_X_CHILD 0x20000000 99 + #define AA_X_INHERIT 0x40000000 100 + #define AA_X_UNCONFINED 0x80000000 103 101 104 102 /* need to make conditional which ones are being set */ 105 103 struct path_cond { ··· 108 108 109 109 #define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill) 110 110 111 - /* FIXME: split perms from dfa and match this to description 112 - * also add delegation info. 113 - */ 114 - static inline u16 dfa_map_xindex(u16 mask) 115 - { 116 - u16 old_index = (mask >> 10) & 0xf; 117 - u16 index = 0; 118 - 119 - if (mask & 0x100) 120 - index |= AA_X_UNSAFE; 121 - if (mask & 0x200) 122 - index |= AA_X_INHERIT; 123 - if (mask & 0x80) 124 - index |= AA_X_UNCONFINED; 125 - 126 - if (old_index == 1) { 127 - index |= AA_X_UNCONFINED; 128 - } else if (old_index == 2) { 129 - index |= AA_X_NAME; 130 - } else if (old_index == 3) { 131 - index |= AA_X_NAME | AA_X_CHILD; 132 - } else if (old_index) { 133 - index |= AA_X_TABLE; 134 - index |= old_index - 4; 135 - } 136 - 137 - return index; 138 - } 139 - 140 - /* 141 - * map old dfa inline permissions to new format 142 - */ 143 - #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \ 144 - ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) 145 - #define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f) 146 - #define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f) 147 - #define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f) 148 - #define dfa_user_xindex(dfa, state) \ 149 - (dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff)) 150 - 151 - #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \ 152 - 0x7f) | \ 153 - ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) 154 - #define dfa_other_xbits(dfa, state) \ 155 - ((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f) 156 - #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f) 157 - #define dfa_other_quiet(dfa, state) \ 158 - ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f) 159 - #define dfa_other_xindex(dfa, state) \ 160 - dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff) 161 - 162 111 int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms, 163 112 const char *op, u32 request, const char *name, 164 113 const char *target, struct aa_label *tlabel, kuid_t ouid, 165 114 const char *info, int error); 166 115 167 - /** 168 - * struct aa_file_rules - components used for file rule permissions 169 - * @dfa: dfa to match path names and conditionals against 170 - * @perms: permission table indexed by the matched state accept entry of @dfa 171 - * @trans: transition table for indexed by named x transitions 172 - * 173 - * File permission are determined by matching a path against @dfa and 174 - * then using the value of the accept entry for the matching state as 175 - * an index into @perms. If a named exec transition is required it is 176 - * looked up in the transition table. 177 - */ 178 - struct aa_file_rules { 179 - unsigned int start; 180 - struct aa_dfa *dfa; 181 - /* struct perms perms; */ 182 - struct aa_domain trans; 183 - /* TODO: add delegate table */ 184 - }; 116 + struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules, 117 + aa_state_t state, struct path_cond *cond); 118 + aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start, 119 + const char *name, struct path_cond *cond, 120 + struct aa_perms *perms); 185 121 186 - struct aa_perms aa_compute_fperms(struct aa_dfa *dfa, unsigned int state, 187 - struct path_cond *cond); 188 - unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start, 189 - const char *name, struct path_cond *cond, 190 - struct aa_perms *perms); 191 - 192 - int __aa_path_perm(const char *op, struct aa_profile *profile, 193 - const char *name, u32 request, struct path_cond *cond, 194 - int flags, struct aa_perms *perms); 195 122 int aa_path_perm(const char *op, struct aa_label *label, 196 123 const struct path *path, int flags, u32 request, 197 124 struct path_cond *cond); ··· 131 204 132 205 void aa_inherit_files(const struct cred *cred, struct files_struct *files); 133 206 134 - static inline void aa_free_file_rules(struct aa_file_rules *rules) 135 - { 136 - aa_put_dfa(rules->dfa); 137 - aa_free_domain_entries(&rules->trans); 138 - } 139 207 140 208 /** 141 209 * aa_map_file_perms - map file flags to AppArmor permissions
+7 -6
security/apparmor/include/label.h
··· 261 261 struct label_it i; \ 262 262 int ret = 0; \ 263 263 label_for_each(i, (L), profile) { \ 264 - if (PROFILE_MEDIATES(profile, (C))) { \ 264 + if (RULE_MEDIATES(&profile->rules, (C))) { \ 265 265 ret = 1; \ 266 266 break; \ 267 267 } \ ··· 333 333 static inline const char *aa_label_strn_split(const char *str, int n) 334 334 { 335 335 const char *pos; 336 - unsigned int state; 336 + aa_state_t state; 337 337 338 338 state = aa_dfa_matchn_until(stacksplitdfa, DFA_START, str, n, &pos); 339 339 if (!ACCEPT_TABLE(stacksplitdfa)[state]) ··· 345 345 static inline const char *aa_label_str_split(const char *str) 346 346 { 347 347 const char *pos; 348 - unsigned int state; 348 + aa_state_t state; 349 349 350 350 state = aa_dfa_match_until(stacksplitdfa, DFA_START, str, &pos); 351 351 if (!ACCEPT_TABLE(stacksplitdfa)[state]) ··· 357 357 358 358 359 359 struct aa_perms; 360 - int aa_label_match(struct aa_profile *profile, struct aa_label *label, 361 - unsigned int state, bool subns, u32 request, 362 - struct aa_perms *perms); 360 + struct aa_ruleset; 361 + int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules, 362 + struct aa_label *label, aa_state_t state, bool subns, 363 + u32 request, struct aa_perms *perms); 363 364 364 365 365 366 /**
+8 -2
security/apparmor/include/lib.h
··· 87 87 * character which is not used in standard matching and is only 88 88 * used to separate pairs. 89 89 */ 90 - static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, 91 - unsigned int start) 90 + static inline aa_state_t aa_dfa_null_transition(struct aa_dfa *dfa, 91 + aa_state_t start) 92 92 { 93 93 /* the null transition only needs the string's null terminator byte */ 94 94 return aa_dfa_next(dfa, start, 0); ··· 99 99 return !(dentry->d_sb->s_flags & SB_NOUSER); 100 100 } 101 101 102 + struct aa_str_table { 103 + int size; 104 + char **table; 105 + }; 106 + 107 + void aa_free_str_table(struct aa_str_table *table); 102 108 103 109 struct counted_str { 104 110 struct kref count;
+14 -14
security/apparmor/include/match.h
··· 125 125 int aa_setup_dfa_engine(void); 126 126 void aa_teardown_dfa_engine(void); 127 127 128 + #define aa_state_t unsigned int 129 + 128 130 struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags); 129 - unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, 130 - const char *str, int len); 131 - unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 132 - const char *str); 133 - unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, 134 - const char c); 135 - unsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa, 136 - unsigned int state); 137 - unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start, 138 - const char *str, const char **retpos); 139 - unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start, 140 - const char *str, int n, const char **retpos); 131 + aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start, 132 + const char *str, int len); 133 + aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, 134 + const char *str); 135 + aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c); 136 + aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state); 137 + aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start, 138 + const char *str, const char **retpos); 139 + aa_state_t aa_dfa_matchn_until(struct aa_dfa *dfa, aa_state_t start, 140 + const char *str, int n, const char **retpos); 141 141 142 142 void aa_dfa_free_kref(struct kref *kref); 143 143 ··· 156 156 .len = 0, \ 157 157 } 158 158 159 - unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start, 160 - const char *str, unsigned int *count); 159 + aa_state_t aa_dfa_leftmatch(struct aa_dfa *dfa, aa_state_t start, 160 + const char *str, unsigned int *count); 161 161 162 162 /** 163 163 * aa_get_dfa - increment refcount on dfa @p
+1
security/apparmor/include/net.h
··· 59 59 DEFINE_AUDIT_DATA(NAME, \ 60 60 ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \ 61 61 LSM_AUDIT_DATA_NONE, \ 62 + AA_CLASS_NET, \ 62 63 OP); \ 63 64 NAME.u.net = &(NAME ## _net); \ 64 65 aad(&NAME)->net.type = (T); \
+77 -14
security/apparmor/include/perms.h
··· 65 65 66 66 struct aa_perms { 67 67 u32 allow; 68 - u32 audit; /* set only when allow is set */ 69 - 70 68 u32 deny; /* explicit deny, or conflict if allow also set */ 71 - u32 quiet; /* set only when ~allow | deny */ 72 - u32 kill; /* set only when ~allow | deny */ 73 - u32 stop; /* set only when ~allow | deny */ 74 69 75 - u32 complain; /* accumulates only used when ~allow & ~deny */ 70 + u32 subtree; /* allow perm on full subtree only when allow is set */ 76 71 u32 cond; /* set only when ~allow and ~deny */ 77 72 78 - u32 hide; /* set only when ~allow | deny */ 73 + u32 kill; /* set only when ~allow | deny */ 74 + u32 complain; /* accumulates only used when ~allow & ~deny */ 79 75 u32 prompt; /* accumulates only used when ~allow & ~deny */ 80 76 81 - /* Reserved: 82 - * u32 subtree; / * set only when allow is set * / 83 - */ 84 - u16 xindex; 77 + u32 audit; /* set only when allow is set */ 78 + u32 quiet; /* set only when ~allow | deny */ 79 + u32 hide; /* set only when ~allow | deny */ 80 + 81 + 82 + u32 xindex; 83 + u32 tag; /* tag string index, if present */ 84 + u32 label; /* label string index, if present */ 85 85 }; 86 + 87 + /* 88 + * Indexes are broken into a 24 bit index and 8 bit flag. 89 + * For the index to be valid there must be a value in the flag 90 + */ 91 + #define AA_INDEX_MASK 0x00ffffff 92 + #define AA_INDEX_FLAG_MASK 0xff000000 93 + #define AA_INDEX_NONE 0 86 94 87 95 #define ALL_PERMS_MASK 0xffffffff 88 96 extern struct aa_perms nullperms; 89 97 extern struct aa_perms allperms; 90 98 99 + /** 100 + * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms 101 + * @accum - perms struct to accumulate into 102 + * @addend - perms struct to add to @accum 103 + */ 104 + static inline void aa_perms_accum_raw(struct aa_perms *accum, 105 + struct aa_perms *addend) 106 + { 107 + accum->deny |= addend->deny; 108 + accum->allow &= addend->allow & ~addend->deny; 109 + accum->audit |= addend->audit & addend->allow; 110 + accum->quiet &= addend->quiet & ~addend->allow; 111 + accum->kill |= addend->kill & ~addend->allow; 112 + accum->complain |= addend->complain & ~addend->allow & ~addend->deny; 113 + accum->cond |= addend->cond & ~addend->allow & ~addend->deny; 114 + accum->hide &= addend->hide & ~addend->allow; 115 + accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny; 116 + accum->subtree |= addend->subtree & ~addend->deny; 117 + 118 + if (!accum->xindex) 119 + accum->xindex = addend->xindex; 120 + if (!accum->tag) 121 + accum->tag = addend->tag; 122 + if (!accum->label) 123 + accum->label = addend->label; 124 + } 125 + 126 + /** 127 + * aa_perms_accum - accumulate perms, masking off overlapping perms 128 + * @accum - perms struct to accumulate into 129 + * @addend - perms struct to add to @accum 130 + */ 131 + static inline void aa_perms_accum(struct aa_perms *accum, 132 + struct aa_perms *addend) 133 + { 134 + accum->deny |= addend->deny; 135 + accum->allow &= addend->allow & ~accum->deny; 136 + accum->audit |= addend->audit & accum->allow; 137 + accum->quiet &= addend->quiet & ~accum->allow; 138 + accum->kill |= addend->kill & ~accum->allow; 139 + accum->complain |= addend->complain & ~accum->allow & ~accum->deny; 140 + accum->cond |= addend->cond & ~accum->allow & ~accum->deny; 141 + accum->hide &= addend->hide & ~accum->allow; 142 + accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny; 143 + accum->subtree &= addend->subtree & ~accum->deny; 144 + 145 + if (!accum->xindex) 146 + accum->xindex = addend->xindex; 147 + if (!accum->tag) 148 + accum->tag = addend->tag; 149 + if (!accum->label) 150 + accum->label = addend->label; 151 + } 91 152 92 153 #define xcheck(FN1, FN2) \ 93 154 ({ \ ··· 194 133 xcheck(fn_for_each((L1), (P), (FN1)), fn_for_each((L2), (P), (FN2))) 195 134 196 135 136 + extern struct aa_perms default_perms; 137 + 138 + 197 139 void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, 198 140 u32 mask); 199 141 void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, ··· 205 141 u32 chrsmask, const char * const *names, u32 namesmask); 206 142 void aa_apply_modes_to_perms(struct aa_profile *profile, 207 143 struct aa_perms *perms); 208 - void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, 209 - struct aa_perms *perms); 210 144 void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend); 211 145 void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend); 212 - void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, 146 + void aa_profile_match_label(struct aa_profile *profile, 147 + struct aa_ruleset *rules, struct aa_label *label, 213 148 int type, u32 request, struct aa_perms *perms); 214 149 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 215 150 u32 request, int type, u32 *deny,
+103 -38
security/apparmor/include/policy.h
··· 44 44 45 45 #define COMPLAIN_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_COMPLAIN) 46 46 47 + #define USER_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_USER) 48 + 47 49 #define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL) 48 50 49 51 #define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT) ··· 69 67 APPARMOR_COMPLAIN, /* allow and log access violations */ 70 68 APPARMOR_KILL, /* kill task on access violation */ 71 69 APPARMOR_UNCONFINED, /* profile set to unconfined */ 70 + APPARMOR_USER, /* modified complain mode to userspace */ 72 71 }; 73 72 74 73 75 74 /* struct aa_policydb - match engine for a policy 76 75 * dfa: dfa pattern match 76 + * perms: table of permissions 77 + * strs: table of strings, index by x 77 78 * start: set of start states for the different classes of data 78 79 */ 79 80 struct aa_policydb { 80 - /* Generic policy DFA specific rule types will be subsections of it */ 81 81 struct aa_dfa *dfa; 82 - unsigned int start[AA_CLASS_LAST + 1]; 83 - 82 + struct { 83 + struct aa_perms *perms; 84 + u32 size; 85 + }; 86 + struct aa_str_table trans; 87 + aa_state_t start[AA_CLASS_LAST + 1]; 84 88 }; 89 + 90 + static inline void aa_destroy_policydb(struct aa_policydb *policy) 91 + { 92 + aa_put_dfa(policy->dfa); 93 + if (policy->perms) 94 + kvfree(policy->perms); 95 + aa_free_str_table(&policy->trans); 96 + 97 + } 98 + 99 + static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy, 100 + aa_state_t state) 101 + { 102 + unsigned int index = ACCEPT_TABLE(policy->dfa)[state]; 103 + 104 + if (!(policy->perms)) 105 + return &default_perms; 106 + 107 + return &(policy->perms[index]); 108 + } 109 + 85 110 86 111 /* struct aa_data - generic data structure 87 112 * key: name for retrieving this data ··· 123 94 struct rhash_head head; 124 95 }; 125 96 97 + /* struct aa_ruleset - data covering mediation rules 98 + * @list: list the rule is on 99 + * @size: the memory consumed by this ruleset 100 + * @policy: general match rules governing policy 101 + * @file: The set of rules governing basic file access and domain transitions 102 + * @caps: capabilities for the profile 103 + * @rlimits: rlimits for the profile 104 + * @secmark_count: number of secmark entries 105 + * @secmark: secmark label match info 106 + */ 107 + struct aa_ruleset { 108 + struct list_head list; 109 + 110 + int size; 111 + 112 + /* TODO: merge policy and file */ 113 + struct aa_policydb policy; 114 + struct aa_policydb file; 115 + struct aa_caps caps; 116 + 117 + struct aa_rlimit rlimits; 118 + 119 + int secmark_count; 120 + struct aa_secmark *secmark; 121 + }; 122 + 123 + /* struct aa_attachment - data and rules for a profiles attachment 124 + * @list: 125 + * @xmatch_str: human readable attachment string 126 + * @xmatch: optional extended matching for unconfined executables names 127 + * @xmatch_len: xmatch prefix len, used to determine xmatch priority 128 + * @xattr_count: number of xattrs in table 129 + * @xattrs: table of xattrs 130 + */ 131 + struct aa_attachment { 132 + const char *xmatch_str; 133 + struct aa_policydb xmatch; 134 + unsigned int xmatch_len; 135 + int xattr_count; 136 + char **xattrs; 137 + }; 126 138 127 139 /* struct aa_profile - basic confinement data 128 140 * @base - base components of the profile (name, refcount, lists, lock ...) ··· 171 101 * @parent: parent of profile 172 102 * @ns: namespace the profile is in 173 103 * @rename: optional profile name that this profile renamed 174 - * @attach: human readable attachment string 175 - * @xmatch: optional extended matching for unconfined executables names 176 - * @xmatch_len: xmatch prefix len, used to determine xmatch priority 104 + * 177 105 * @audit: the auditing mode of the profile 178 106 * @mode: the enforcement mode of the profile 179 107 * @path_flags: flags controlling path generation behavior 180 108 * @disconnected: what to prepend if attach_disconnected is specified 181 - * @size: the memory consumed by this profiles rules 182 - * @policy: general match rules governing policy 183 - * @file: The set of rules governing basic file access and domain transitions 184 - * @caps: capabilities for the profile 185 - * @rlimits: rlimits for the profile 109 + * @attach: attachment rules for the profile 110 + * @rules: rules to be enforced 186 111 * 187 112 * @dents: dentries for the profiles file entries in apparmorfs 188 113 * @dirname: name of the profile dir in apparmorfs ··· 202 137 struct aa_ns *ns; 203 138 const char *rename; 204 139 205 - const char *attach; 206 - struct aa_dfa *xmatch; 207 - unsigned int xmatch_len; 208 140 enum audit_mode audit; 209 141 long mode; 210 142 u32 path_flags; 211 143 const char *disconnected; 212 - int size; 213 144 214 - struct aa_policydb policy; 215 - struct aa_file_rules file; 216 - struct aa_caps caps; 217 - 218 - int xattr_count; 219 - char **xattrs; 220 - 221 - struct aa_rlimit rlimits; 222 - 223 - int secmark_count; 224 - struct aa_secmark *secmark; 145 + struct aa_attachment attach; 146 + struct list_head rules; 225 147 226 148 struct aa_loaddata *rawdata; 227 149 unsigned char *hash; ··· 231 179 232 180 233 181 void aa_free_proxy_kref(struct kref *kref); 182 + struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp); 234 183 struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy, 235 184 gfp_t gfp); 236 - struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, 237 - const char *base, gfp_t gfp); 185 + struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, 186 + gfp_t gfp); 187 + struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat, 188 + const char *base, gfp_t gfp); 238 189 void aa_free_profile(struct aa_profile *profile); 239 190 void aa_free_profile_kref(struct kref *kref); 240 191 struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); ··· 272 217 return labels_profile(aa_get_newest_label(&p->label)); 273 218 } 274 219 275 - static inline unsigned int PROFILE_MEDIATES(struct aa_profile *profile, 276 - unsigned char class) 220 + static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules, 221 + unsigned char class) 277 222 { 278 223 if (class <= AA_CLASS_LAST) 279 - return profile->policy.start[class]; 224 + return rules->policy.start[class]; 280 225 else 281 - return aa_dfa_match_len(profile->policy.dfa, 282 - profile->policy.start[0], &class, 1); 226 + return aa_dfa_match_len(rules->policy.dfa, 227 + rules->policy.start[0], &class, 1); 283 228 } 284 229 285 - static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, 286 - u16 AF) { 287 - unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); 230 + static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) 231 + { 232 + aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NET); 288 233 __be16 be_af = cpu_to_be16(AF); 289 234 290 235 if (!state) 291 - return 0; 292 - return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); 236 + return DFA_NOMATCH; 237 + return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2); 238 + } 239 + 240 + static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head, 241 + unsigned char class) 242 + { 243 + struct aa_ruleset *rule; 244 + 245 + /* TODO: change to list walk */ 246 + rule = list_first_entry(head, typeof(*rule), list); 247 + return RULE_MEDIATES(rule, class); 293 248 } 294 249 295 250 /**
+33
security/apparmor/include/policy_compat.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * AppArmor security module 4 + * 5 + * Code to provide backwards compatibility with older policy versions, 6 + * by converting/mapping older policy formats into the newer internal 7 + * formats. 8 + * 9 + * Copyright 2022 Canonical Ltd. 10 + */ 11 + 12 + #ifndef __POLICY_COMPAT_H 13 + #define __POLICY_COMPAT_H 14 + 15 + #include "policy.h" 16 + 17 + #define K_ABI_MASK 0x3ff 18 + #define FORCE_COMPLAIN_FLAG 0x800 19 + #define VERSION_LT(X, Y) (((X) & K_ABI_MASK) < ((Y) & K_ABI_MASK)) 20 + #define VERSION_LE(X, Y) (((X) & K_ABI_MASK) <= ((Y) & K_ABI_MASK)) 21 + #define VERSION_GT(X, Y) (((X) & K_ABI_MASK) > ((Y) & K_ABI_MASK)) 22 + 23 + #define v5 5 /* base version */ 24 + #define v6 6 /* per entry policydb mediation check */ 25 + #define v7 7 26 + #define v8 8 /* full network masking */ 27 + #define v9 9 /* xbits are used as permission bits in policydb */ 28 + 29 + int aa_compat_map_xmatch(struct aa_policydb *policy); 30 + int aa_compat_map_policy(struct aa_policydb *policy, u32 version); 31 + int aa_compat_map_file(struct aa_policydb *policy); 32 + 33 + #endif /* __POLICY_COMPAT_H */
+3 -1
security/apparmor/include/policy_unpack.h
··· 16 16 #include <linux/dcache.h> 17 17 #include <linux/workqueue.h> 18 18 19 + 19 20 struct aa_load_ent { 20 21 struct list_head list; 21 22 struct aa_profile *new; ··· 36 35 #define PACKED_MODE_COMPLAIN 1 37 36 #define PACKED_MODE_KILL 2 38 37 #define PACKED_MODE_UNCONFINED 3 38 + #define PACKED_MODE_USER 4 39 39 40 40 struct aa_ns; 41 41 ··· 172 170 bool aa_unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name); 173 171 bool aa_unpack_u32(struct aa_ext *e, u32 *data, const char *name); 174 172 bool aa_unpack_u64(struct aa_ext *e, u64 *data, const char *name); 175 - size_t aa_unpack_array(struct aa_ext *e, const char *name); 173 + bool aa_unpack_array(struct aa_ext *e, const char *name, u16 *size); 176 174 size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name); 177 175 int aa_unpack_str(struct aa_ext *e, const char **string, const char *name); 178 176 int aa_unpack_strdup(struct aa_ext *e, char **string, const char *name);
+9 -7
security/apparmor/ipc.c
··· 45 45 } 46 46 47 47 /** 48 - * audit_cb - call back for signal specific audit fields 48 + * audit_signal_cb() - call back for signal specific audit fields 49 49 * @ab: audit_buffer (NOT NULL) 50 50 * @va: audit struct to audit values of (NOT NULL) 51 51 */ ··· 78 78 struct aa_label *peer, u32 request, 79 79 struct common_audit_data *sa) 80 80 { 81 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 82 + typeof(*rules), list); 81 83 struct aa_perms perms; 82 - unsigned int state; 84 + aa_state_t state; 83 85 84 86 if (profile_unconfined(profile) || 85 - !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL)) 87 + !ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL)) 86 88 return 0; 87 89 88 90 aad(sa)->peer = peer; 89 91 /* TODO: secondary cache check <profile, profile, perm> */ 90 - state = aa_dfa_next(profile->policy.dfa, 91 - profile->policy.start[AA_CLASS_SIGNAL], 92 + state = aa_dfa_next(rules->policy.dfa, 93 + rules->policy.start[AA_CLASS_SIGNAL], 92 94 aad(sa)->signal); 93 - aa_label_match(profile, peer, state, false, request, &perms); 95 + aa_label_match(profile, rules, peer, state, false, request, &perms); 94 96 aa_apply_modes_to_perms(profile, &perms); 95 97 return aa_check_perms(profile, &perms, request, sa, audit_signal_cb); 96 98 } ··· 100 98 int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig) 101 99 { 102 100 struct aa_profile *profile; 103 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL); 101 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_SIGNAL, OP_SIGNAL); 104 102 105 103 aad(&sa)->signal = map_signal_num(sig); 106 104 aad(&sa)->unmappedsig = sig;
+38 -37
security/apparmor/label.c
··· 197 197 return false; 198 198 } 199 199 200 - static long union_vec_flags(struct aa_profile **vec, int n, long mask) 200 + static long accum_vec_flags(struct aa_profile **vec, int n) 201 201 { 202 - long u = 0; 202 + long u = FLAG_UNCONFINED; 203 203 int i; 204 204 205 205 AA_BUG(!vec); 206 206 207 207 for (i = 0; i < n; i++) { 208 - u |= vec[i]->label.flags & mask; 208 + u |= vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 | 209 + FLAG_STALE); 210 + if (!(u & vec[i]->label.flags & FLAG_UNCONFINED)) 211 + u &= ~FLAG_UNCONFINED; 209 212 } 210 213 211 214 return u; ··· 1100 1097 else if (k == b->size) 1101 1098 return aa_get_label(b); 1102 1099 } 1103 - new->flags |= union_vec_flags(new->vec, new->size, FLAG_UNCONFINED | 1104 - FLAG_DEBUG1 | FLAG_DEBUG2); 1100 + new->flags |= accum_vec_flags(new->vec, new->size); 1105 1101 ls = labels_set(new); 1106 1102 write_lock_irqsave(&ls->lock, flags); 1107 1103 label = __label_insert(labels_set(new), new, false); ··· 1256 1254 return label; 1257 1255 } 1258 1256 1259 - static inline bool label_is_visible(struct aa_profile *profile, 1260 - struct aa_label *label) 1261 - { 1262 - return aa_ns_visible(profile->ns, labels_ns(label), true); 1263 - } 1264 - 1265 1257 /* match a profile and its associated ns component if needed 1266 1258 * Assumes visibility test has already been done. 1267 1259 * If a subns profile is not to be matched should be prescreened with 1268 1260 * visibility test. 1269 1261 */ 1270 - static inline unsigned int match_component(struct aa_profile *profile, 1271 - struct aa_profile *tp, 1272 - unsigned int state) 1262 + static inline aa_state_t match_component(struct aa_profile *profile, 1263 + struct aa_ruleset *rules, 1264 + struct aa_profile *tp, 1265 + aa_state_t state) 1273 1266 { 1274 1267 const char *ns_name; 1275 1268 1276 1269 if (profile->ns == tp->ns) 1277 - return aa_dfa_match(profile->policy.dfa, state, tp->base.hname); 1270 + return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); 1278 1271 1279 1272 /* try matching with namespace name and then profile */ 1280 1273 ns_name = aa_ns_name(profile->ns, tp->ns, true); 1281 - state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1); 1282 - state = aa_dfa_match(profile->policy.dfa, state, ns_name); 1283 - state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1); 1284 - return aa_dfa_match(profile->policy.dfa, state, tp->base.hname); 1274 + state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); 1275 + state = aa_dfa_match(rules->policy.dfa, state, ns_name); 1276 + state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); 1277 + return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); 1285 1278 } 1286 1279 1287 1280 /** ··· 1295 1298 * check to be stacked. 1296 1299 */ 1297 1300 static int label_compound_match(struct aa_profile *profile, 1301 + struct aa_ruleset *rules, 1298 1302 struct aa_label *label, 1299 - unsigned int state, bool subns, u32 request, 1303 + aa_state_t state, bool subns, u32 request, 1300 1304 struct aa_perms *perms) 1301 1305 { 1302 1306 struct aa_profile *tp; ··· 1307 1309 label_for_each(i, label, tp) { 1308 1310 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 1309 1311 continue; 1310 - state = match_component(profile, tp, state); 1312 + state = match_component(profile, rules, tp, state); 1311 1313 if (!state) 1312 1314 goto fail; 1313 1315 goto next; ··· 1321 1323 label_for_each_cont(i, label, tp) { 1322 1324 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 1323 1325 continue; 1324 - state = aa_dfa_match(profile->policy.dfa, state, "//&"); 1325 - state = match_component(profile, tp, state); 1326 + state = aa_dfa_match(rules->policy.dfa, state, "//&"); 1327 + state = match_component(profile, rules, tp, state); 1326 1328 if (!state) 1327 1329 goto fail; 1328 1330 } 1329 - aa_compute_perms(profile->policy.dfa, state, perms); 1331 + *perms = *aa_lookup_perms(&rules->policy, state); 1330 1332 aa_apply_modes_to_perms(profile, perms); 1331 1333 if ((perms->allow & request) != request) 1332 1334 return -EACCES; ··· 1341 1343 /** 1342 1344 * label_components_match - find perms for all subcomponents of a label 1343 1345 * @profile: profile to find perms for 1346 + * @rules: ruleset to search 1344 1347 * @label: label to check access permissions for 1345 1348 * @start: state to start match in 1346 1349 * @subns: whether to do permission checks on components in a subns ··· 1355 1356 * check to be stacked. 1356 1357 */ 1357 1358 static int label_components_match(struct aa_profile *profile, 1358 - struct aa_label *label, unsigned int start, 1359 + struct aa_ruleset *rules, 1360 + struct aa_label *label, aa_state_t start, 1359 1361 bool subns, u32 request, 1360 1362 struct aa_perms *perms) 1361 1363 { 1362 1364 struct aa_profile *tp; 1363 1365 struct label_it i; 1364 1366 struct aa_perms tmp; 1365 - unsigned int state = 0; 1367 + aa_state_t state = 0; 1366 1368 1367 1369 /* find first subcomponent to test */ 1368 1370 label_for_each(i, label, tp) { 1369 1371 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 1370 1372 continue; 1371 - state = match_component(profile, tp, start); 1373 + state = match_component(profile, rules, tp, start); 1372 1374 if (!state) 1373 1375 goto fail; 1374 1376 goto next; ··· 1379 1379 return 0; 1380 1380 1381 1381 next: 1382 - aa_compute_perms(profile->policy.dfa, state, &tmp); 1382 + tmp = *aa_lookup_perms(&rules->policy, state); 1383 1383 aa_apply_modes_to_perms(profile, &tmp); 1384 1384 aa_perms_accum(perms, &tmp); 1385 1385 label_for_each_cont(i, label, tp) { 1386 1386 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 1387 1387 continue; 1388 - state = match_component(profile, tp, start); 1388 + state = match_component(profile, rules, tp, start); 1389 1389 if (!state) 1390 1390 goto fail; 1391 - aa_compute_perms(profile->policy.dfa, state, &tmp); 1391 + tmp = *aa_lookup_perms(&rules->policy, state); 1392 1392 aa_apply_modes_to_perms(profile, &tmp); 1393 1393 aa_perms_accum(perms, &tmp); 1394 1394 } ··· 1406 1406 /** 1407 1407 * aa_label_match - do a multi-component label match 1408 1408 * @profile: profile to match against (NOT NULL) 1409 + * @rules: ruleset to search 1409 1410 * @label: label to match (NOT NULL) 1410 1411 * @state: state to start in 1411 1412 * @subns: whether to match subns components ··· 1415 1414 * 1416 1415 * Returns: the state the match finished in, may be the none matching state 1417 1416 */ 1418 - int aa_label_match(struct aa_profile *profile, struct aa_label *label, 1419 - unsigned int state, bool subns, u32 request, 1420 - struct aa_perms *perms) 1417 + int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules, 1418 + struct aa_label *label, aa_state_t state, bool subns, 1419 + u32 request, struct aa_perms *perms) 1421 1420 { 1422 - int error = label_compound_match(profile, label, state, subns, request, 1423 - perms); 1421 + int error = label_compound_match(profile, rules, label, state, subns, 1422 + request, perms); 1424 1423 if (!error) 1425 1424 return error; 1426 1425 1427 1426 *perms = allperms; 1428 - return label_components_match(profile, label, state, subns, request, 1429 - perms); 1427 + return label_components_match(profile, rules, label, state, subns, 1428 + request, perms); 1430 1429 } 1431 1430 1432 1431
+33 -92
security/apparmor/lib.c
··· 26 26 .hide = ALL_PERMS_MASK }; 27 27 28 28 /** 29 + * aa_free_str_table - free entries str table 30 + * @str: the string table to free (MAYBE NULL) 31 + */ 32 + void aa_free_str_table(struct aa_str_table *t) 33 + { 34 + int i; 35 + 36 + if (t) { 37 + if (!t->table) 38 + return; 39 + 40 + for (i = 0; i < t->size; i++) 41 + kfree_sensitive(t->table[i]); 42 + kfree_sensitive(t->table); 43 + t->table = NULL; 44 + } 45 + } 46 + 47 + /** 29 48 * aa_split_fqname - split a fqname into a profile and namespace name 30 49 * @fqname: a full qualified name in namespace profile format (NOT NULL) 31 50 * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) ··· 143 124 void aa_info_message(const char *str) 144 125 { 145 126 if (audit_enabled) { 146 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); 127 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL); 147 128 148 129 aad(&sa)->info = str; 149 130 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); ··· 327 308 perms->kill = ALL_PERMS_MASK; 328 309 else if (COMPLAIN_MODE(profile)) 329 310 perms->complain = ALL_PERMS_MASK; 330 - /* 331 - * TODO: 332 - * else if (PROMPT_MODE(profile)) 333 - * perms->prompt = ALL_PERMS_MASK; 334 - */ 311 + else if (USER_MODE(profile)) 312 + perms->prompt = ALL_PERMS_MASK; 335 313 } 336 314 337 - static u32 map_other(u32 x) 338 - { 339 - return ((x & 0x3) << 8) | /* SETATTR/GETATTR */ 340 - ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */ 341 - ((x & 0x60) << 19); /* SETOPT/GETOPT */ 342 - } 343 - 344 - static u32 map_xbits(u32 x) 345 - { 346 - return ((x & 0x1) << 7) | 347 - ((x & 0x7e) << 9); 348 - } 349 - 350 - void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, 351 - struct aa_perms *perms) 352 - { 353 - /* This mapping is convulated due to history. 354 - * v1-v4: only file perms 355 - * v5: added policydb which dropped in perm user conditional to 356 - * gain new perm bits, but had to map around the xbits because 357 - * the userspace compiler was still munging them. 358 - * v9: adds using the xbits in policydb because the compiler now 359 - * supports treating policydb permission bits different. 360 - * Unfortunately there is not way to force auditing on the 361 - * perms represented by the xbits 362 - */ 363 - *perms = (struct aa_perms) { 364 - .allow = dfa_user_allow(dfa, state) | 365 - map_xbits(dfa_user_xbits(dfa, state)), 366 - .audit = dfa_user_audit(dfa, state), 367 - .quiet = dfa_user_quiet(dfa, state) | 368 - map_xbits(dfa_other_xbits(dfa, state)), 369 - }; 370 - 371 - /* for v5-v9 perm mapping in the policydb, the other set is used 372 - * to extend the general perm set 373 - */ 374 - perms->allow |= map_other(dfa_other_allow(dfa, state)); 375 - perms->audit |= map_other(dfa_other_audit(dfa, state)); 376 - perms->quiet |= map_other(dfa_other_quiet(dfa, state)); 377 - } 378 - 379 - /** 380 - * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms 381 - * @accum - perms struct to accumulate into 382 - * @addend - perms struct to add to @accum 383 - */ 384 - void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend) 385 - { 386 - accum->deny |= addend->deny; 387 - accum->allow &= addend->allow & ~addend->deny; 388 - accum->audit |= addend->audit & addend->allow; 389 - accum->quiet &= addend->quiet & ~addend->allow; 390 - accum->kill |= addend->kill & ~addend->allow; 391 - accum->stop |= addend->stop & ~addend->allow; 392 - accum->complain |= addend->complain & ~addend->allow & ~addend->deny; 393 - accum->cond |= addend->cond & ~addend->allow & ~addend->deny; 394 - accum->hide &= addend->hide & ~addend->allow; 395 - accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny; 396 - } 397 - 398 - /** 399 - * aa_perms_accum - accumulate perms, masking off overlapping perms 400 - * @accum - perms struct to accumulate into 401 - * @addend - perms struct to add to @accum 402 - */ 403 - void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend) 404 - { 405 - accum->deny |= addend->deny; 406 - accum->allow &= addend->allow & ~accum->deny; 407 - accum->audit |= addend->audit & accum->allow; 408 - accum->quiet &= addend->quiet & ~accum->allow; 409 - accum->kill |= addend->kill & ~accum->allow; 410 - accum->stop |= addend->stop & ~accum->allow; 411 - accum->complain |= addend->complain & ~accum->allow & ~accum->deny; 412 - accum->cond |= addend->cond & ~accum->allow & ~accum->deny; 413 - accum->hide &= addend->hide & ~accum->allow; 414 - accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny; 415 - } 416 - 417 - void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, 315 + void aa_profile_match_label(struct aa_profile *profile, 316 + struct aa_ruleset *rules, 317 + struct aa_label *label, 418 318 int type, u32 request, struct aa_perms *perms) 419 319 { 420 320 /* TODO: doesn't yet handle extended types */ 421 - unsigned int state; 321 + aa_state_t state; 422 322 423 - state = aa_dfa_next(profile->policy.dfa, 424 - profile->policy.start[AA_CLASS_LABEL], 323 + state = aa_dfa_next(rules->policy.dfa, 324 + rules->policy.start[AA_CLASS_LABEL], 425 325 type); 426 - aa_label_match(profile, label, state, false, request, perms); 326 + aa_label_match(profile, rules, label, state, false, request, perms); 427 327 } 428 328 429 329 ··· 351 413 u32 request, int type, u32 *deny, 352 414 struct common_audit_data *sa) 353 415 { 416 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 417 + typeof(*rules), list); 354 418 struct aa_perms perms; 355 419 356 420 aad(sa)->label = &profile->label; 357 421 aad(sa)->peer = &target->label; 358 422 aad(sa)->request = request; 359 423 360 - aa_profile_match_label(profile, &target->label, type, request, &perms); 424 + aa_profile_match_label(profile, rules, &target->label, type, request, 425 + &perms); 361 426 aa_apply_modes_to_perms(profile, &perms); 362 427 *deny |= request & perms.deny; 363 428 return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
+14 -11
security/apparmor/lsm.c
··· 21 21 #include <linux/user_namespace.h> 22 22 #include <linux/netfilter_ipv4.h> 23 23 #include <linux/netfilter_ipv6.h> 24 - #include <linux/zlib.h> 24 + #include <linux/zstd.h> 25 25 #include <net/sock.h> 26 26 #include <uapi/linux/mount.h> 27 27 ··· 163 163 struct label_it i; 164 164 165 165 label_for_each_confined(i, label, profile) { 166 + struct aa_ruleset *rules; 166 167 if (COMPLAIN_MODE(profile)) 167 168 continue; 169 + rules = list_first_entry(&profile->rules, 170 + typeof(*rules), list); 168 171 *effective = cap_intersect(*effective, 169 - profile->caps.allow); 172 + rules->caps.allow); 170 173 *permitted = cap_intersect(*permitted, 171 - profile->caps.allow); 174 + rules->caps.allow); 172 175 } 173 176 } 174 177 rcu_read_unlock(); ··· 664 661 char *command, *largs = NULL, *args = value; 665 662 size_t arg_size; 666 663 int error; 667 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETPROCATTR); 664 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, 665 + OP_SETPROCATTR); 668 666 669 667 if (size == 0) 670 668 return -EINVAL; ··· 755 751 } 756 752 757 753 /** 758 - * apparmor_bprm_committed_cred - do cleanup after new creds committed 754 + * apparmor_bprm_committed_creds() - do cleanup after new creds committed 759 755 * @bprm: binprm for the exec (NOT NULL) 760 756 */ 761 757 static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) ··· 1209 1205 #endif 1210 1206 1211 1207 /* 1212 - * The cred blob is a pointer to, not an instance of, an aa_task_ctx. 1208 + * The cred blob is a pointer to, not an instance of, an aa_label. 1213 1209 */ 1214 1210 struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { 1215 - .lbs_cred = sizeof(struct aa_task_ctx *), 1211 + .lbs_cred = sizeof(struct aa_label *), 1216 1212 .lbs_file = sizeof(struct aa_file_ctx), 1217 1213 .lbs_task = sizeof(struct aa_task_ctx), 1218 1214 }; ··· 1377 1373 #endif 1378 1374 1379 1375 /* policy loaddata compression level */ 1380 - int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION; 1376 + int aa_g_rawdata_compression_level = AA_DEFAULT_CLEVEL; 1381 1377 module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level, 1382 1378 aacompressionlevel, 0400); 1383 1379 ··· 1559 1555 error = param_set_int(val, kp); 1560 1556 1561 1557 aa_g_rawdata_compression_level = clamp(aa_g_rawdata_compression_level, 1562 - Z_NO_COMPRESSION, 1563 - Z_BEST_COMPRESSION); 1564 - pr_info("AppArmor: policy rawdata compression level set to %u\n", 1558 + AA_MIN_CLEVEL, AA_MAX_CLEVEL); 1559 + pr_info("AppArmor: policy rawdata compression level set to %d\n", 1565 1560 aa_g_rawdata_compression_level); 1566 1561 1567 1562 return error;
+30 -32
security/apparmor/match.c
··· 31 31 }; 32 32 struct aa_dfa *stacksplitdfa; 33 33 34 - int aa_setup_dfa_engine(void) 34 + int __init aa_setup_dfa_engine(void) 35 35 { 36 36 int error; 37 37 ··· 59 59 return 0; 60 60 } 61 61 62 - void aa_teardown_dfa_engine(void) 62 + void __init aa_teardown_dfa_engine(void) 63 63 { 64 64 aa_put_dfa(stacksplitdfa); 65 65 aa_put_dfa(nulldfa); ··· 436 436 * 437 437 * Returns: final state reached after input is consumed 438 438 */ 439 - unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, 440 - const char *str, int len) 439 + aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start, 440 + const char *str, int len) 441 441 { 442 442 u16 *def = DEFAULT_TABLE(dfa); 443 443 u32 *base = BASE_TABLE(dfa); 444 444 u16 *next = NEXT_TABLE(dfa); 445 445 u16 *check = CHECK_TABLE(dfa); 446 - unsigned int state = start; 446 + aa_state_t state = start; 447 447 448 - if (state == 0) 449 - return 0; 448 + if (state == DFA_NOMATCH) 449 + return DFA_NOMATCH; 450 450 451 451 /* current state is <state>, matching character *str */ 452 452 if (dfa->tables[YYTD_ID_EC]) { ··· 476 476 * 477 477 * Returns: final state reached after input is consumed 478 478 */ 479 - unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, 480 - const char *str) 479 + aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str) 481 480 { 482 481 u16 *def = DEFAULT_TABLE(dfa); 483 482 u32 *base = BASE_TABLE(dfa); 484 483 u16 *next = NEXT_TABLE(dfa); 485 484 u16 *check = CHECK_TABLE(dfa); 486 - unsigned int state = start; 485 + aa_state_t state = start; 487 486 488 - if (state == 0) 489 - return 0; 487 + if (state == DFA_NOMATCH) 488 + return DFA_NOMATCH; 490 489 491 490 /* current state is <state>, matching character *str */ 492 491 if (dfa->tables[YYTD_ID_EC]) { ··· 514 515 * 515 516 * Returns: state reach after input @c 516 517 */ 517 - unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, 518 - const char c) 518 + aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c) 519 519 { 520 520 u16 *def = DEFAULT_TABLE(dfa); 521 521 u32 *base = BASE_TABLE(dfa); ··· 532 534 return state; 533 535 } 534 536 535 - unsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa, unsigned int state) 537 + aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state) 536 538 { 537 539 u16 *def = DEFAULT_TABLE(dfa); 538 540 u32 *base = BASE_TABLE(dfa); ··· 562 564 * 563 565 * Returns: final state reached after input is consumed 564 566 */ 565 - unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start, 567 + aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start, 566 568 const char *str, const char **retpos) 567 569 { 568 570 u16 *def = DEFAULT_TABLE(dfa); ··· 570 572 u16 *next = NEXT_TABLE(dfa); 571 573 u16 *check = CHECK_TABLE(dfa); 572 574 u32 *accept = ACCEPT_TABLE(dfa); 573 - unsigned int state = start, pos; 575 + aa_state_t state = start, pos; 574 576 575 - if (state == 0) 576 - return 0; 577 + if (state == DFA_NOMATCH) 578 + return DFA_NOMATCH; 577 579 578 580 /* current state is <state>, matching character *str */ 579 581 if (dfa->tables[YYTD_ID_EC]) { ··· 623 625 * 624 626 * Returns: final state reached after input is consumed 625 627 */ 626 - unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start, 628 + aa_state_t aa_dfa_matchn_until(struct aa_dfa *dfa, aa_state_t start, 627 629 const char *str, int n, const char **retpos) 628 630 { 629 631 u16 *def = DEFAULT_TABLE(dfa); ··· 631 633 u16 *next = NEXT_TABLE(dfa); 632 634 u16 *check = CHECK_TABLE(dfa); 633 635 u32 *accept = ACCEPT_TABLE(dfa); 634 - unsigned int state = start, pos; 636 + aa_state_t state = start, pos; 635 637 636 638 *retpos = NULL; 637 - if (state == 0) 638 - return 0; 639 + if (state == DFA_NOMATCH) 640 + return DFA_NOMATCH; 639 641 640 642 /* current state is <state>, matching character *str */ 641 643 if (dfa->tables[YYTD_ID_EC]) { ··· 675 677 } while (0) 676 678 677 679 /* For DFAs that don't support extended tagging of states */ 678 - static bool is_loop(struct match_workbuf *wb, unsigned int state, 680 + static bool is_loop(struct match_workbuf *wb, aa_state_t state, 679 681 unsigned int *adjust) 680 682 { 681 - unsigned int pos = wb->pos; 682 - unsigned int i; 683 + aa_state_t pos = wb->pos; 684 + aa_state_t i; 683 685 684 686 if (wb->history[pos] < state) 685 687 return false; ··· 698 700 return true; 699 701 } 700 702 701 - static unsigned int leftmatch_fb(struct aa_dfa *dfa, unsigned int start, 703 + static aa_state_t leftmatch_fb(struct aa_dfa *dfa, aa_state_t start, 702 704 const char *str, struct match_workbuf *wb, 703 705 unsigned int *count) 704 706 { ··· 706 708 u32 *base = BASE_TABLE(dfa); 707 709 u16 *next = NEXT_TABLE(dfa); 708 710 u16 *check = CHECK_TABLE(dfa); 709 - unsigned int state = start, pos; 711 + aa_state_t state = start, pos; 710 712 711 713 AA_BUG(!dfa); 712 714 AA_BUG(!str); ··· 714 716 AA_BUG(!count); 715 717 716 718 *count = 0; 717 - if (state == 0) 718 - return 0; 719 + if (state == DFA_NOMATCH) 720 + return DFA_NOMATCH; 719 721 720 722 /* current state is <state>, matching character *str */ 721 723 if (dfa->tables[YYTD_ID_EC]) { ··· 779 781 * 780 782 * Returns: final state reached after input is consumed 781 783 */ 782 - unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start, 783 - const char *str, unsigned int *count) 784 + aa_state_t aa_dfa_leftmatch(struct aa_dfa *dfa, aa_state_t start, 785 + const char *str, unsigned int *count) 784 786 { 785 787 DEFINE_MATCH_WB(wb); 786 788
+42 -51
security/apparmor/mount.c
··· 134 134 struct aa_perms *perms, const char *info, int error) 135 135 { 136 136 int audit_type = AUDIT_APPARMOR_AUTO; 137 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); 137 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_MOUNT, op); 138 138 139 139 if (likely(!error)) { 140 140 u32 mask = perms->audit; ··· 190 190 * 191 191 * Returns: next state after flags match 192 192 */ 193 - static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state, 193 + static aa_state_t match_mnt_flags(struct aa_dfa *dfa, aa_state_t state, 194 194 unsigned long flags) 195 195 { 196 196 unsigned int i; ··· 201 201 } 202 202 203 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 - */ 213 - static 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 - }; 221 - 222 - return perms; 223 204 } 224 205 225 206 static const char * const mnt_info_table[] = { ··· 217 236 * Returns 0 on success else element that match failed in, this is the 218 237 * index into the mnt_info_table above 219 238 */ 220 - static int do_match_mnt(struct aa_dfa *dfa, unsigned int start, 239 + static int do_match_mnt(struct aa_policydb *policy, aa_state_t start, 221 240 const char *mntpnt, const char *devname, 222 241 const char *type, unsigned long flags, 223 242 void *data, bool binary, struct aa_perms *perms) 224 243 { 225 - unsigned int state; 244 + aa_state_t state; 226 245 227 - AA_BUG(!dfa); 246 + AA_BUG(!policy); 247 + AA_BUG(!policy->dfa); 248 + AA_BUG(!policy->perms); 228 249 AA_BUG(!perms); 229 250 230 - state = aa_dfa_match(dfa, start, mntpnt); 231 - state = aa_dfa_null_transition(dfa, state); 251 + state = aa_dfa_match(policy->dfa, start, mntpnt); 252 + state = aa_dfa_null_transition(policy->dfa, state); 232 253 if (!state) 233 254 return 1; 234 255 235 256 if (devname) 236 - state = aa_dfa_match(dfa, state, devname); 237 - state = aa_dfa_null_transition(dfa, state); 257 + state = aa_dfa_match(policy->dfa, state, devname); 258 + state = aa_dfa_null_transition(policy->dfa, state); 238 259 if (!state) 239 260 return 2; 240 261 241 262 if (type) 242 - state = aa_dfa_match(dfa, state, type); 243 - state = aa_dfa_null_transition(dfa, state); 263 + state = aa_dfa_match(policy->dfa, state, type); 264 + state = aa_dfa_null_transition(policy->dfa, state); 244 265 if (!state) 245 266 return 3; 246 267 247 - state = match_mnt_flags(dfa, state, flags); 268 + state = match_mnt_flags(policy->dfa, state, flags); 248 269 if (!state) 249 270 return 4; 250 - *perms = compute_mnt_perms(dfa, state); 271 + *perms = *aa_lookup_perms(policy, state); 251 272 if (perms->allow & AA_MAY_MOUNT) 252 273 return 0; 253 274 254 275 /* only match data if not binary and the DFA flags data is expected */ 255 276 if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) { 256 - state = aa_dfa_null_transition(dfa, state); 277 + state = aa_dfa_null_transition(policy->dfa, state); 257 278 if (!state) 258 279 return 4; 259 280 260 - state = aa_dfa_match(dfa, state, data); 281 + state = aa_dfa_match(policy->dfa, state, data); 261 282 if (!state) 262 283 return 5; 263 - *perms = compute_mnt_perms(dfa, state); 284 + *perms = *aa_lookup_perms(policy, state); 264 285 if (perms->allow & AA_MAY_MOUNT) 265 286 return 0; 266 287 } ··· 303 320 { 304 321 struct aa_perms perms = { }; 305 322 const char *mntpnt = NULL, *info = NULL; 323 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 324 + typeof(*rules), list); 306 325 int pos, error; 307 326 308 327 AA_BUG(!profile); 309 328 AA_BUG(!mntpath); 310 329 AA_BUG(!buffer); 311 330 312 - if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) 331 + if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 313 332 return 0; 314 333 315 334 error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer, ··· 326 341 } 327 342 328 343 error = -EACCES; 329 - pos = do_match_mnt(profile->policy.dfa, 330 - profile->policy.start[AA_CLASS_MOUNT], 344 + pos = do_match_mnt(&rules->policy, 345 + rules->policy.start[AA_CLASS_MOUNT], 331 346 mntpnt, devname, type, flags, data, binary, &perms); 332 347 if (pos) { 333 348 info = mnt_info_table[pos]; ··· 360 375 bool binary) 361 376 { 362 377 const char *devname = NULL, *info = NULL; 378 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 379 + typeof(*rules), list); 363 380 int error = -EACCES; 364 381 365 382 AA_BUG(!profile); 366 383 AA_BUG(devpath && !devbuffer); 367 384 368 - if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) 385 + if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 369 386 return 0; 370 387 371 388 if (devpath) { ··· 569 582 static int profile_umount(struct aa_profile *profile, const struct path *path, 570 583 char *buffer) 571 584 { 585 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 586 + typeof(*rules), list); 572 587 struct aa_perms perms = { }; 573 588 const char *name = NULL, *info = NULL; 574 - unsigned int state; 589 + aa_state_t state; 575 590 int error; 576 591 577 592 AA_BUG(!profile); 578 593 AA_BUG(!path); 579 594 580 - if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) 595 + if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 581 596 return 0; 582 597 583 598 error = aa_path_name(path, path_flags(profile, path), buffer, &name, ··· 587 598 if (error) 588 599 goto audit; 589 600 590 - state = aa_dfa_match(profile->policy.dfa, 591 - profile->policy.start[AA_CLASS_MOUNT], 601 + state = aa_dfa_match(rules->policy.dfa, 602 + rules->policy.start[AA_CLASS_MOUNT], 592 603 name); 593 - perms = compute_mnt_perms(profile->policy.dfa, state); 604 + perms = *aa_lookup_perms(&rules->policy, state); 594 605 if (AA_MAY_UMOUNT & ~perms.allow) 595 606 error = -EACCES; 596 607 ··· 630 641 const struct path *old_path, 631 642 char *old_buffer) 632 643 { 644 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 645 + typeof(*rules), list); 633 646 const char *old_name, *new_name = NULL, *info = NULL; 634 647 const char *trans_name = NULL; 635 648 struct aa_perms perms = { }; 636 - unsigned int state; 649 + aa_state_t state; 637 650 int error; 638 651 639 652 AA_BUG(!profile); ··· 643 652 AA_BUG(!old_path); 644 653 645 654 if (profile_unconfined(profile) || 646 - !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) 655 + !RULE_MEDIATES(rules, AA_CLASS_MOUNT)) 647 656 return aa_get_newest_label(&profile->label); 648 657 649 658 error = aa_path_name(old_path, path_flags(profile, old_path), ··· 658 667 goto audit; 659 668 660 669 error = -EACCES; 661 - state = aa_dfa_match(profile->policy.dfa, 662 - profile->policy.start[AA_CLASS_MOUNT], 670 + state = aa_dfa_match(rules->policy.dfa, 671 + rules->policy.start[AA_CLASS_MOUNT], 663 672 new_name); 664 - state = aa_dfa_null_transition(profile->policy.dfa, state); 665 - state = aa_dfa_match(profile->policy.dfa, state, old_name); 666 - perms = compute_mnt_perms(profile->policy.dfa, state); 673 + state = aa_dfa_null_transition(rules->policy.dfa, state); 674 + state = aa_dfa_match(rules->policy.dfa, state, old_name); 675 + perms = *aa_lookup_perms(&rules->policy, state); 667 676 668 677 if (AA_MAY_PIVOTROOT & perms.allow) 669 678 error = 0;
+16 -12
security/apparmor/net.c
··· 108 108 int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, 109 109 u32 request, u16 family, int type) 110 110 { 111 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 112 + typeof(*rules), list); 111 113 struct aa_perms perms = { }; 112 - unsigned int state; 114 + aa_state_t state; 113 115 __be16 buffer[2]; 114 116 115 117 AA_BUG(family >= AF_MAX); ··· 119 117 120 118 if (profile_unconfined(profile)) 121 119 return 0; 122 - state = PROFILE_MEDIATES(profile, AA_CLASS_NET); 120 + state = RULE_MEDIATES(rules, AA_CLASS_NET); 123 121 if (!state) 124 122 return 0; 125 123 126 124 buffer[0] = cpu_to_be16(family); 127 125 buffer[1] = cpu_to_be16((u16) type); 128 - state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer, 126 + state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer, 129 127 4); 130 - aa_compute_perms(profile->policy.dfa, state, &perms); 128 + perms = *aa_lookup_perms(&rules->policy, state); 131 129 aa_apply_modes_to_perms(profile, &perms); 132 130 133 131 return aa_check_perms(profile, &perms, request, sa, audit_net_cb); ··· 218 216 { 219 217 int i, ret; 220 218 struct aa_perms perms = { }; 219 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 220 + typeof(*rules), list); 221 221 222 - if (profile->secmark_count == 0) 222 + if (rules->secmark_count == 0) 223 223 return 0; 224 224 225 - for (i = 0; i < profile->secmark_count; i++) { 226 - if (!profile->secmark[i].secid) { 227 - ret = apparmor_secmark_init(&profile->secmark[i]); 225 + for (i = 0; i < rules->secmark_count; i++) { 226 + if (!rules->secmark[i].secid) { 227 + ret = apparmor_secmark_init(&rules->secmark[i]); 228 228 if (ret) 229 229 return ret; 230 230 } 231 231 232 - if (profile->secmark[i].secid == secid || 233 - profile->secmark[i].secid == AA_SECID_WILDCARD) { 234 - if (profile->secmark[i].deny) 232 + if (rules->secmark[i].secid == secid || 233 + rules->secmark[i].secid == AA_SECID_WILDCARD) { 234 + if (rules->secmark[i].deny) 235 235 perms.deny = ALL_PERMS_MASK; 236 236 else 237 237 perms.allow = ALL_PERMS_MASK; 238 238 239 - if (profile->secmark[i].audit) 239 + if (rules->secmark[i].audit) 240 240 perms.audit = ALL_PERMS_MASK; 241 241 } 242 242 }
+168 -36
security/apparmor/policy.c
··· 94 94 "complain", 95 95 "kill", 96 96 "unconfined", 97 + "user", 97 98 }; 98 99 99 100 ··· 193 192 kfree_sensitive(data); 194 193 } 195 194 195 + static void free_attachment(struct aa_attachment *attach) 196 + { 197 + int i; 198 + 199 + for (i = 0; i < attach->xattr_count; i++) 200 + kfree_sensitive(attach->xattrs[i]); 201 + kfree_sensitive(attach->xattrs); 202 + aa_destroy_policydb(&attach->xmatch); 203 + } 204 + 205 + static void free_ruleset(struct aa_ruleset *rules) 206 + { 207 + int i; 208 + 209 + aa_destroy_policydb(&rules->file); 210 + aa_destroy_policydb(&rules->policy); 211 + aa_free_cap_rules(&rules->caps); 212 + aa_free_rlimit_rules(&rules->rlimits); 213 + 214 + for (i = 0; i < rules->secmark_count; i++) 215 + kfree_sensitive(rules->secmark[i].label); 216 + kfree_sensitive(rules->secmark); 217 + kfree_sensitive(rules); 218 + } 219 + 220 + struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp) 221 + { 222 + struct aa_ruleset *rules; 223 + 224 + rules = kzalloc(sizeof(*rules), gfp); 225 + if (rules) 226 + INIT_LIST_HEAD(&rules->list); 227 + 228 + return rules; 229 + } 230 + 196 231 /** 197 232 * aa_free_profile - free a profile 198 233 * @profile: the profile to free (MAYBE NULL) ··· 241 204 */ 242 205 void aa_free_profile(struct aa_profile *profile) 243 206 { 207 + struct aa_ruleset *rule, *tmp; 244 208 struct rhashtable *rht; 245 - int i; 246 209 247 210 AA_DEBUG("%s(%p)\n", __func__, profile); 248 211 ··· 256 219 aa_put_ns(profile->ns); 257 220 kfree_sensitive(profile->rename); 258 221 259 - aa_free_file_rules(&profile->file); 260 - aa_free_cap_rules(&profile->caps); 261 - aa_free_rlimit_rules(&profile->rlimits); 222 + free_attachment(&profile->attach); 262 223 263 - for (i = 0; i < profile->xattr_count; i++) 264 - kfree_sensitive(profile->xattrs[i]); 265 - kfree_sensitive(profile->xattrs); 266 - for (i = 0; i < profile->secmark_count; i++) 267 - kfree_sensitive(profile->secmark[i].label); 268 - kfree_sensitive(profile->secmark); 224 + /* 225 + * at this point there are no tasks that can have a reference 226 + * to rules 227 + */ 228 + list_for_each_entry_safe(rule, tmp, &profile->rules, list) { 229 + list_del_init(&rule->list); 230 + free_ruleset(rule); 231 + } 269 232 kfree_sensitive(profile->dirname); 270 - aa_put_dfa(profile->xmatch); 271 - aa_put_dfa(profile->policy.dfa); 272 233 273 234 if (profile->data) { 274 235 rht = profile->data; ··· 293 258 gfp_t gfp) 294 259 { 295 260 struct aa_profile *profile; 261 + struct aa_ruleset *rules; 296 262 297 263 /* freed by free_profile - usually through aa_put_profile */ 298 264 profile = kzalloc(struct_size(profile, label.vec, 2), gfp); ··· 304 268 goto fail; 305 269 if (!aa_label_init(&profile->label, 1, gfp)) 306 270 goto fail; 271 + 272 + INIT_LIST_HEAD(&profile->rules); 273 + 274 + /* allocate the first ruleset, but leave it empty */ 275 + rules = aa_alloc_ruleset(gfp); 276 + if (!rules) 277 + goto fail; 278 + list_add(&rules->list, &profile->rules); 307 279 308 280 /* update being set needed by fs interface */ 309 281 if (!proxy) { ··· 425 381 } 426 382 427 383 /** 384 + * __create_missing_ancestors - create place holders for missing ancestores 385 + * @ns: namespace to lookup profile in (NOT NULL) 386 + * @hname: hierarchical profile name to find parent of (NOT NULL) 387 + * @gfp: type of allocation. 388 + * 389 + * Returns: NULL on error, parent profile on success 390 + * 391 + * Requires: ns mutex lock held 392 + * 393 + * Returns: unrefcounted parent policy or NULL if error creating 394 + * place holder profiles. 395 + */ 396 + static struct aa_policy *__create_missing_ancestors(struct aa_ns *ns, 397 + const char *hname, 398 + gfp_t gfp) 399 + { 400 + struct aa_policy *policy; 401 + struct aa_profile *parent, *profile = NULL; 402 + char *split; 403 + 404 + AA_BUG(!ns); 405 + AA_BUG(!hname); 406 + 407 + policy = &ns->base; 408 + 409 + for (split = strstr(hname, "//"); split;) { 410 + parent = profile; 411 + profile = __strn_find_child(&policy->profiles, hname, 412 + split - hname); 413 + if (!profile) { 414 + const char *name = kstrndup(hname, split - hname, 415 + gfp); 416 + if (!name) 417 + return NULL; 418 + profile = aa_alloc_null(parent, name, gfp); 419 + kfree(name); 420 + if (!profile) 421 + return NULL; 422 + if (!parent) 423 + profile->ns = aa_get_ns(ns); 424 + } 425 + policy = &profile->base; 426 + hname = split + 2; 427 + split = strstr(hname, "//"); 428 + } 429 + if (!profile) 430 + return &ns->base; 431 + return &profile->base; 432 + } 433 + 434 + /** 428 435 * __lookupn_profile - lookup the profile matching @hname 429 436 * @base: base list to start looking up profile name from (NOT NULL) 430 437 * @hname: hierarchical profile name (NOT NULL) ··· 576 481 return profile; 577 482 } 578 483 484 + 485 + struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, 486 + gfp_t gfp) 487 + { 488 + struct aa_profile *profile; 489 + struct aa_ruleset *rules; 490 + 491 + profile = aa_alloc_profile(name, NULL, gfp); 492 + if (!profile) 493 + return NULL; 494 + 495 + /* TODO: ideally we should inherit abi from parent */ 496 + profile->label.flags |= FLAG_NULL; 497 + rules = list_first_entry(&profile->rules, typeof(*rules), list); 498 + rules->file.dfa = aa_get_dfa(nulldfa); 499 + rules->policy.dfa = aa_get_dfa(nulldfa); 500 + 501 + if (parent) { 502 + profile->path_flags = parent->path_flags; 503 + 504 + /* released on free_profile */ 505 + rcu_assign_pointer(profile->parent, aa_get_profile(parent)); 506 + profile->ns = aa_get_ns(parent->ns); 507 + } 508 + 509 + return profile; 510 + } 511 + 579 512 /** 580 - * aa_new_null_profile - create or find a null-X learning profile 513 + * aa_new_learning_profile - create or find a null-X learning profile 581 514 * @parent: profile that caused this profile to be created (NOT NULL) 582 515 * @hat: true if the null- learning profile is a hat 583 516 * @base: name to base the null profile off of ··· 622 499 * 623 500 * Returns: new refcounted profile else NULL on failure 624 501 */ 625 - struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, 626 - const char *base, gfp_t gfp) 502 + struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat, 503 + const char *base, gfp_t gfp) 627 504 { 628 505 struct aa_profile *p, *profile; 629 506 const char *bname; ··· 654 531 if (profile) 655 532 goto out; 656 533 657 - profile = aa_alloc_profile(name, NULL, gfp); 534 + profile = aa_alloc_null(parent, name, gfp); 658 535 if (!profile) 659 536 goto fail; 660 - 661 537 profile->mode = APPARMOR_COMPLAIN; 662 - profile->label.flags |= FLAG_NULL; 663 538 if (hat) 664 539 profile->label.flags |= FLAG_HAT; 665 - profile->path_flags = parent->path_flags; 666 - 667 - /* released on free_profile */ 668 - rcu_assign_pointer(profile->parent, aa_get_profile(parent)); 669 - profile->ns = aa_get_ns(parent->ns); 670 - profile->file.dfa = aa_get_dfa(nulldfa); 671 - profile->policy.dfa = aa_get_dfa(nulldfa); 672 540 673 541 mutex_lock_nested(&profile->ns->lock, profile->ns->level); 674 542 p = __find_child(&parent->base.profiles, bname); ··· 732 618 const char *ns_name, const char *name, 733 619 const char *info, int error) 734 620 { 735 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); 621 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, op); 736 622 737 623 aad(&sa)->iface.ns = ns_name; 738 624 aad(&sa)->name = name; ··· 1084 970 /* setup parent and ns info */ 1085 971 list_for_each_entry(ent, &lh, list) { 1086 972 struct aa_policy *policy; 973 + struct aa_profile *p; 1087 974 1088 975 if (aa_g_export_binary) 1089 976 ent->new->rawdata = aa_get_loaddata(udata); ··· 1109 994 continue; 1110 995 1111 996 /* no ref on policy only use inside lock */ 997 + p = NULL; 1112 998 policy = __lookup_parent(ns, ent->new->base.hname); 1113 999 if (!policy) { 1114 - struct aa_profile *p; 1000 + /* first check for parent in the load set */ 1115 1001 p = __list_lookup_parent(&lh, ent->new); 1116 1002 if (!p) { 1117 - error = -ENOENT; 1118 - info = "parent does not exist"; 1119 - goto fail_lock; 1003 + /* 1004 + * fill in missing parent with null 1005 + * profile that doesn't have 1006 + * permissions. This allows for 1007 + * individual profile loading where 1008 + * the child is loaded before the 1009 + * parent, and outside of the current 1010 + * atomic set. This unfortunately can 1011 + * happen with some userspaces. The 1012 + * null profile will be replaced once 1013 + * the parent is loaded. 1014 + */ 1015 + policy = __create_missing_ancestors(ns, 1016 + ent->new->base.hname, 1017 + GFP_KERNEL); 1018 + if (!policy) { 1019 + error = -ENOENT; 1020 + info = "parent does not exist"; 1021 + goto fail_lock; 1022 + } 1120 1023 } 1121 - rcu_assign_pointer(ent->new->parent, aa_get_profile(p)); 1122 - } else if (policy != &ns->base) { 1123 - /* released on profile replacement or free_profile */ 1124 - struct aa_profile *p = (struct aa_profile *) policy; 1125 - rcu_assign_pointer(ent->new->parent, aa_get_profile(p)); 1126 1024 } 1025 + if (!p && policy != &ns->base) 1026 + /* released on profile replacement or free_profile */ 1027 + p = (struct aa_profile *) policy; 1028 + rcu_assign_pointer(ent->new->parent, aa_get_profile(p)); 1127 1029 } 1128 1030 1129 1031 /* create new fs entries for introspection if needed */ ··· 1302 1170 1303 1171 if (!name) { 1304 1172 /* remove namespace - can only happen if fqname[0] == ':' */ 1305 - mutex_lock_nested(&ns->parent->lock, ns->level); 1173 + mutex_lock_nested(&ns->parent->lock, ns->parent->level); 1306 1174 __aa_bump_ns_revision(ns); 1307 1175 __aa_remove_ns(ns); 1308 1176 mutex_unlock(&ns->parent->lock);
+319
security/apparmor/policy_compat.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * AppArmor security module 4 + * 5 + * This file contains AppArmor functions for unpacking policy loaded 6 + * from userspace. 7 + * 8 + * Copyright (C) 1998-2008 Novell/SUSE 9 + * Copyright 2009-2022 Canonical Ltd. 10 + * 11 + * Code to provide backwards compatibility with older policy versions, 12 + * by converting/mapping older policy formats into the newer internal 13 + * formats. 14 + */ 15 + 16 + #include <linux/ctype.h> 17 + #include <linux/errno.h> 18 + 19 + #include "include/lib.h" 20 + #include "include/policy_unpack.h" 21 + #include "include/policy_compat.h" 22 + 23 + /* remap old accept table embedded permissions to separate permission table */ 24 + static u32 dfa_map_xindex(u16 mask) 25 + { 26 + u16 old_index = (mask >> 10) & 0xf; 27 + u32 index = 0; 28 + 29 + if (mask & 0x100) 30 + index |= AA_X_UNSAFE; 31 + if (mask & 0x200) 32 + index |= AA_X_INHERIT; 33 + if (mask & 0x80) 34 + index |= AA_X_UNCONFINED; 35 + 36 + if (old_index == 1) { 37 + index |= AA_X_UNCONFINED; 38 + } else if (old_index == 2) { 39 + index |= AA_X_NAME; 40 + } else if (old_index == 3) { 41 + index |= AA_X_NAME | AA_X_CHILD; 42 + } else if (old_index) { 43 + index |= AA_X_TABLE; 44 + index |= old_index - 4; 45 + } 46 + 47 + return index; 48 + } 49 + 50 + /* 51 + * map old dfa inline permissions to new format 52 + */ 53 + #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \ 54 + ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) 55 + #define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f) 56 + #define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f) 57 + #define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f) 58 + #define dfa_user_xindex(dfa, state) \ 59 + (dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff)) 60 + 61 + #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \ 62 + 0x7f) | \ 63 + ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) 64 + #define dfa_other_xbits(dfa, state) \ 65 + ((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f) 66 + #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f) 67 + #define dfa_other_quiet(dfa, state) \ 68 + ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f) 69 + #define dfa_other_xindex(dfa, state) \ 70 + dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff) 71 + 72 + /** 73 + * map_old_perms - map old file perms layout to the new layout 74 + * @old: permission set in old mapping 75 + * 76 + * Returns: new permission mapping 77 + */ 78 + static u32 map_old_perms(u32 old) 79 + { 80 + u32 new = old & 0xf; 81 + 82 + if (old & MAY_READ) 83 + new |= AA_MAY_GETATTR | AA_MAY_OPEN; 84 + if (old & MAY_WRITE) 85 + new |= AA_MAY_SETATTR | AA_MAY_CREATE | AA_MAY_DELETE | 86 + AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_OPEN; 87 + if (old & 0x10) 88 + new |= AA_MAY_LINK; 89 + /* the old mapping lock and link_subset flags where overlaid 90 + * and use was determined by part of a pair that they were in 91 + */ 92 + if (old & 0x20) 93 + new |= AA_MAY_LOCK | AA_LINK_SUBSET; 94 + if (old & 0x40) /* AA_EXEC_MMAP */ 95 + new |= AA_EXEC_MMAP; 96 + 97 + return new; 98 + } 99 + 100 + static void compute_fperms_allow(struct aa_perms *perms, struct aa_dfa *dfa, 101 + aa_state_t state) 102 + { 103 + perms->allow |= AA_MAY_GETATTR; 104 + 105 + /* change_profile wasn't determined by ownership in old mapping */ 106 + if (ACCEPT_TABLE(dfa)[state] & 0x80000000) 107 + perms->allow |= AA_MAY_CHANGE_PROFILE; 108 + if (ACCEPT_TABLE(dfa)[state] & 0x40000000) 109 + perms->allow |= AA_MAY_ONEXEC; 110 + } 111 + 112 + static struct aa_perms compute_fperms_user(struct aa_dfa *dfa, 113 + aa_state_t state) 114 + { 115 + struct aa_perms perms = { }; 116 + 117 + perms.allow = map_old_perms(dfa_user_allow(dfa, state)); 118 + perms.audit = map_old_perms(dfa_user_audit(dfa, state)); 119 + perms.quiet = map_old_perms(dfa_user_quiet(dfa, state)); 120 + perms.xindex = dfa_user_xindex(dfa, state); 121 + 122 + compute_fperms_allow(&perms, dfa, state); 123 + 124 + return perms; 125 + } 126 + 127 + static struct aa_perms compute_fperms_other(struct aa_dfa *dfa, 128 + aa_state_t state) 129 + { 130 + struct aa_perms perms = { }; 131 + 132 + perms.allow = map_old_perms(dfa_other_allow(dfa, state)); 133 + perms.audit = map_old_perms(dfa_other_audit(dfa, state)); 134 + perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); 135 + perms.xindex = dfa_other_xindex(dfa, state); 136 + 137 + compute_fperms_allow(&perms, dfa, state); 138 + 139 + return perms; 140 + } 141 + 142 + /** 143 + * compute_fperms - convert dfa compressed perms to internal perms and store 144 + * them so they can be retrieved later. 145 + * @dfa: a dfa using fperms to remap to internal permissions 146 + * 147 + * Returns: remapped perm table 148 + */ 149 + static struct aa_perms *compute_fperms(struct aa_dfa *dfa) 150 + { 151 + aa_state_t state; 152 + unsigned int state_count; 153 + struct aa_perms *table; 154 + 155 + AA_BUG(!dfa); 156 + 157 + state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 158 + /* DFAs are restricted from having a state_count of less than 2 */ 159 + table = kvcalloc(state_count * 2, sizeof(struct aa_perms), GFP_KERNEL); 160 + if (!table) 161 + return NULL; 162 + 163 + /* zero init so skip the trap state (state == 0) */ 164 + for (state = 1; state < state_count; state++) { 165 + table[state * 2] = compute_fperms_user(dfa, state); 166 + table[state * 2 + 1] = compute_fperms_other(dfa, state); 167 + } 168 + 169 + return table; 170 + } 171 + 172 + static struct aa_perms *compute_xmatch_perms(struct aa_dfa *xmatch) 173 + { 174 + struct aa_perms *perms; 175 + int state; 176 + int state_count; 177 + 178 + AA_BUG(!xmatch); 179 + 180 + state_count = xmatch->tables[YYTD_ID_BASE]->td_lolen; 181 + /* DFAs are restricted from having a state_count of less than 2 */ 182 + perms = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL); 183 + 184 + /* zero init so skip the trap state (state == 0) */ 185 + for (state = 1; state < state_count; state++) 186 + perms[state].allow = dfa_user_allow(xmatch, state); 187 + 188 + return perms; 189 + } 190 + 191 + static u32 map_other(u32 x) 192 + { 193 + return ((x & 0x3) << 8) | /* SETATTR/GETATTR */ 194 + ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */ 195 + ((x & 0x60) << 19); /* SETOPT/GETOPT */ 196 + } 197 + 198 + static u32 map_xbits(u32 x) 199 + { 200 + return ((x & 0x1) << 7) | 201 + ((x & 0x7e) << 9); 202 + } 203 + 204 + static struct aa_perms compute_perms_entry(struct aa_dfa *dfa, 205 + aa_state_t state, 206 + u32 version) 207 + { 208 + struct aa_perms perms = { }; 209 + 210 + perms.allow = dfa_user_allow(dfa, state); 211 + perms.audit = dfa_user_audit(dfa, state); 212 + perms.quiet = dfa_user_quiet(dfa, state); 213 + 214 + /* 215 + * This mapping is convulated due to history. 216 + * v1-v4: only file perms, which are handled by compute_fperms 217 + * v5: added policydb which dropped user conditional to gain new 218 + * perm bits, but had to map around the xbits because the 219 + * userspace compiler was still munging them. 220 + * v9: adds using the xbits in policydb because the compiler now 221 + * supports treating policydb permission bits different. 222 + * Unfortunately there is no way to force auditing on the 223 + * perms represented by the xbits 224 + */ 225 + perms.allow |= map_other(dfa_other_allow(dfa, state)); 226 + if (VERSION_LE(version, v8)) 227 + perms.allow |= AA_MAY_LOCK; 228 + else 229 + perms.allow |= map_xbits(dfa_user_xbits(dfa, state)); 230 + 231 + /* 232 + * for v5-v9 perm mapping in the policydb, the other set is used 233 + * to extend the general perm set 234 + */ 235 + perms.audit |= map_other(dfa_other_audit(dfa, state)); 236 + perms.quiet |= map_other(dfa_other_quiet(dfa, state)); 237 + if (VERSION_GT(version, v8)) 238 + perms.quiet |= map_xbits(dfa_other_xbits(dfa, state)); 239 + 240 + return perms; 241 + } 242 + 243 + static struct aa_perms *compute_perms(struct aa_dfa *dfa, u32 version) 244 + { 245 + unsigned int state; 246 + unsigned int state_count; 247 + struct aa_perms *table; 248 + 249 + AA_BUG(!dfa); 250 + 251 + state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 252 + /* DFAs are restricted from having a state_count of less than 2 */ 253 + table = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL); 254 + if (!table) 255 + return NULL; 256 + 257 + /* zero init so skip the trap state (state == 0) */ 258 + for (state = 1; state < state_count; state++) 259 + table[state] = compute_perms_entry(dfa, state, version); 260 + 261 + return table; 262 + } 263 + 264 + /** 265 + * remap_dfa_accept - remap old dfa accept table to be an index 266 + * @dfa: dfa to do the remapping on 267 + * @factor: scaling factor for the index conversion. 268 + * 269 + * Used in conjunction with compute_Xperms, it converts old style perms 270 + * that are encoded in the dfa accept tables to the new style where 271 + * there is a permission table and the accept table is an index into 272 + * the permission table. 273 + */ 274 + static void remap_dfa_accept(struct aa_dfa *dfa, unsigned int factor) 275 + { 276 + unsigned int state; 277 + unsigned int state_count = dfa->tables[YYTD_ID_BASE]->td_lolen; 278 + 279 + AA_BUG(!dfa); 280 + 281 + for (state = 0; state < state_count; state++) 282 + ACCEPT_TABLE(dfa)[state] = state * factor; 283 + kvfree(dfa->tables[YYTD_ID_ACCEPT2]); 284 + dfa->tables[YYTD_ID_ACCEPT2] = NULL; 285 + } 286 + 287 + /* TODO: merge different dfa mappings into single map_policy fn */ 288 + int aa_compat_map_xmatch(struct aa_policydb *policy) 289 + { 290 + policy->perms = compute_xmatch_perms(policy->dfa); 291 + if (!policy->perms) 292 + return -ENOMEM; 293 + 294 + remap_dfa_accept(policy->dfa, 1); 295 + 296 + return 0; 297 + } 298 + 299 + int aa_compat_map_policy(struct aa_policydb *policy, u32 version) 300 + { 301 + policy->perms = compute_perms(policy->dfa, version); 302 + if (!policy->perms) 303 + return -ENOMEM; 304 + 305 + remap_dfa_accept(policy->dfa, 1); 306 + 307 + return 0; 308 + } 309 + 310 + int aa_compat_map_file(struct aa_policydb *policy) 311 + { 312 + policy->perms = compute_fperms(policy->dfa); 313 + if (!policy->perms) 314 + return -ENOMEM; 315 + 316 + remap_dfa_accept(policy->dfa, 2); 317 + 318 + return 0; 319 + }
+2 -4
security/apparmor/policy_ns.c
··· 84 84 { 85 85 struct aa_profile *profile; 86 86 87 - profile = aa_alloc_profile(name, NULL, GFP_KERNEL); 87 + profile = aa_alloc_null(NULL, name, GFP_KERNEL); 88 88 if (!profile) 89 89 return NULL; 90 90 91 91 profile->label.flags |= FLAG_IX_ON_NAME_ERROR | 92 92 FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; 93 93 profile->mode = APPARMOR_UNCONFINED; 94 - profile->file.dfa = aa_get_dfa(nulldfa); 95 - profile->policy.dfa = aa_get_dfa(nulldfa); 96 94 97 95 return profile; 98 96 } ··· 132 134 return ns; 133 135 134 136 fail_unconfined: 135 - kfree_sensitive(ns->base.hname); 137 + aa_policy_destroy(&ns->base); 136 138 fail_ns: 137 139 kfree_sensitive(ns); 138 140 return NULL;
+402 -193
security/apparmor/policy_unpack.c
··· 17 17 #include <kunit/visibility.h> 18 18 #include <linux/ctype.h> 19 19 #include <linux/errno.h> 20 - #include <linux/zlib.h> 20 + #include <linux/zstd.h> 21 21 22 22 #include "include/apparmor.h" 23 23 #include "include/audit.h" 24 24 #include "include/cred.h" 25 25 #include "include/crypto.h" 26 + #include "include/file.h" 26 27 #include "include/match.h" 27 28 #include "include/path.h" 28 29 #include "include/policy.h" 29 30 #include "include/policy_unpack.h" 30 - 31 - #define K_ABI_MASK 0x3ff 32 - #define FORCE_COMPLAIN_FLAG 0x800 33 - #define VERSION_LT(X, Y) (((X) & K_ABI_MASK) < ((Y) & K_ABI_MASK)) 34 - #define VERSION_GT(X, Y) (((X) & K_ABI_MASK) > ((Y) & K_ABI_MASK)) 35 - 36 - #define v5 5 /* base version */ 37 - #define v6 6 /* per entry policydb mediation check */ 38 - #define v7 7 39 - #define v8 8 /* full network masking */ 31 + #include "include/policy_compat.h" 40 32 41 33 /* audit callback for unpack fields */ 42 34 static void audit_cb(struct audit_buffer *ab, void *va) ··· 63 71 int error) 64 72 { 65 73 struct aa_profile *profile = labels_profile(aa_current_raw_label()); 66 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); 74 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL); 67 75 if (e) 68 76 aad(&sa)->iface.pos = e->pos - e->start; 69 77 aad(&sa)->iface.ns = ns_name; ··· 313 321 } 314 322 EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u64); 315 323 316 - VISIBLE_IF_KUNIT size_t aa_unpack_array(struct aa_ext *e, const char *name) 324 + VISIBLE_IF_KUNIT bool aa_unpack_array(struct aa_ext *e, const char *name, u16 *size) 317 325 { 318 326 void *pos = e->pos; 319 327 320 328 if (aa_unpack_nameX(e, AA_ARRAY, name)) { 321 - int size; 322 329 if (!aa_inbounds(e, sizeof(u16))) 323 330 goto fail; 324 - size = (int)le16_to_cpu(get_unaligned((__le16 *) e->pos)); 331 + *size = le16_to_cpu(get_unaligned((__le16 *) e->pos)); 325 332 e->pos += sizeof(u16); 326 - return size; 333 + return true; 327 334 } 328 335 329 336 fail: 330 337 e->pos = pos; 331 - return 0; 338 + return false; 332 339 } 333 340 EXPORT_SYMBOL_IF_KUNIT(aa_unpack_array); 334 341 ··· 402 411 /** 403 412 * unpack_dfa - unpack a file rule dfa 404 413 * @e: serialized data extent information (NOT NULL) 414 + * @flags: dfa flags to check 405 415 * 406 416 * returns dfa or ERR_PTR or NULL if no dfa 407 417 */ 408 - static struct aa_dfa *unpack_dfa(struct aa_ext *e) 418 + static struct aa_dfa *unpack_dfa(struct aa_ext *e, int flags) 409 419 { 410 420 char *blob = NULL; 411 421 size_t size; ··· 422 430 size_t sz = blob - (char *) e->start - 423 431 ((e->pos - e->start) & 7); 424 432 size_t pad = ALIGN(sz, 8) - sz; 425 - int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | 426 - TO_ACCEPT2_FLAG(YYTD_DATA32); 427 433 if (aa_g_paranoid_load) 428 434 flags |= DFA_FLAG_VERIFY_STATES; 429 435 dfa = aa_dfa_unpack(blob + pad, size - pad, flags); ··· 437 447 /** 438 448 * unpack_trans_table - unpack a profile transition table 439 449 * @e: serialized data extent information (NOT NULL) 440 - * @profile: profile to add the accept table to (NOT NULL) 450 + * @table: str table to unpack to (NOT NULL) 441 451 * 442 - * Returns: true if table successfully unpacked 452 + * Returns: true if table successfully unpacked or not present 443 453 */ 444 - static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile) 454 + static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs) 445 455 { 446 456 void *saved_pos = e->pos; 457 + char **table = NULL; 447 458 448 459 /* exec table is optional */ 449 460 if (aa_unpack_nameX(e, AA_STRUCT, "xtable")) { 450 - int i, size; 461 + u16 size; 462 + int i; 451 463 452 - size = aa_unpack_array(e, NULL); 453 - /* currently 4 exec bits and entries 0-3 are reserved iupcx */ 454 - if (size > 16 - 4) 464 + if (!aa_unpack_array(e, NULL, &size)) 465 + /* 466 + * Note: index into trans table array is a max 467 + * of 2^24, but unpack array can only unpack 468 + * an array of 2^16 in size atm so no need 469 + * for size check here 470 + */ 455 471 goto fail; 456 - profile->file.trans.table = kcalloc(size, sizeof(char *), 457 - GFP_KERNEL); 458 - if (!profile->file.trans.table) 472 + table = kcalloc(size, sizeof(char *), GFP_KERNEL); 473 + if (!table) 459 474 goto fail; 460 475 461 - profile->file.trans.size = size; 462 476 for (i = 0; i < size; i++) { 463 477 char *str; 464 478 int c, j, pos, size2 = aa_unpack_strdup(e, &str, NULL); ··· 471 477 */ 472 478 if (!size2) 473 479 goto fail; 474 - profile->file.trans.table[i] = str; 480 + table[i] = str; 475 481 /* verify that name doesn't start with space */ 476 482 if (isspace(*str)) 477 483 goto fail; ··· 505 511 goto fail; 506 512 if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) 507 513 goto fail; 514 + 515 + strs->table = table; 516 + strs->size = size; 508 517 } 509 518 return true; 510 519 511 520 fail: 512 - aa_free_domain_entries(&profile->file.trans); 521 + kfree_sensitive(table); 513 522 e->pos = saved_pos; 514 523 return false; 515 524 } ··· 522 525 void *pos = e->pos; 523 526 524 527 if (aa_unpack_nameX(e, AA_STRUCT, "xattrs")) { 525 - int i, size; 528 + u16 size; 529 + int i; 526 530 527 - size = aa_unpack_array(e, NULL); 528 - profile->xattr_count = size; 529 - profile->xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL); 530 - if (!profile->xattrs) 531 + if (!aa_unpack_array(e, NULL, &size)) 532 + goto fail; 533 + profile->attach.xattr_count = size; 534 + profile->attach.xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL); 535 + if (!profile->attach.xattrs) 531 536 goto fail; 532 537 for (i = 0; i < size; i++) { 533 - if (!aa_unpack_strdup(e, &profile->xattrs[i], NULL)) 538 + if (!aa_unpack_strdup(e, &profile->attach.xattrs[i], NULL)) 534 539 goto fail; 535 540 } 536 541 if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL)) ··· 548 549 return false; 549 550 } 550 551 551 - static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile) 552 + static bool unpack_secmark(struct aa_ext *e, struct aa_ruleset *rules) 552 553 { 553 554 void *pos = e->pos; 554 - int i, size; 555 + u16 size; 556 + int i; 555 557 556 558 if (aa_unpack_nameX(e, AA_STRUCT, "secmark")) { 557 - size = aa_unpack_array(e, NULL); 558 - 559 - profile->secmark = kcalloc(size, sizeof(struct aa_secmark), 560 - GFP_KERNEL); 561 - if (!profile->secmark) 559 + if (!aa_unpack_array(e, NULL, &size)) 562 560 goto fail; 563 561 564 - profile->secmark_count = size; 562 + rules->secmark = kcalloc(size, sizeof(struct aa_secmark), 563 + GFP_KERNEL); 564 + if (!rules->secmark) 565 + goto fail; 566 + 567 + rules->secmark_count = size; 565 568 566 569 for (i = 0; i < size; i++) { 567 - if (!unpack_u8(e, &profile->secmark[i].audit, NULL)) 570 + if (!unpack_u8(e, &rules->secmark[i].audit, NULL)) 568 571 goto fail; 569 - if (!unpack_u8(e, &profile->secmark[i].deny, NULL)) 572 + if (!unpack_u8(e, &rules->secmark[i].deny, NULL)) 570 573 goto fail; 571 - if (!aa_unpack_strdup(e, &profile->secmark[i].label, NULL)) 574 + if (!aa_unpack_strdup(e, &rules->secmark[i].label, NULL)) 572 575 goto fail; 573 576 } 574 577 if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL)) ··· 582 581 return true; 583 582 584 583 fail: 585 - if (profile->secmark) { 584 + if (rules->secmark) { 586 585 for (i = 0; i < size; i++) 587 - kfree(profile->secmark[i].label); 588 - kfree(profile->secmark); 589 - profile->secmark_count = 0; 590 - profile->secmark = NULL; 586 + kfree(rules->secmark[i].label); 587 + kfree(rules->secmark); 588 + rules->secmark_count = 0; 589 + rules->secmark = NULL; 591 590 } 592 591 593 592 e->pos = pos; 594 593 return false; 595 594 } 596 595 597 - static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) 596 + static bool unpack_rlimits(struct aa_ext *e, struct aa_ruleset *rules) 598 597 { 599 598 void *pos = e->pos; 600 599 601 600 /* rlimits are optional */ 602 601 if (aa_unpack_nameX(e, AA_STRUCT, "rlimits")) { 603 - int i, size; 602 + u16 size; 603 + int i; 604 604 u32 tmp = 0; 605 605 if (!aa_unpack_u32(e, &tmp, NULL)) 606 606 goto fail; 607 - profile->rlimits.mask = tmp; 607 + rules->rlimits.mask = tmp; 608 608 609 - size = aa_unpack_array(e, NULL); 610 - if (size > RLIM_NLIMITS) 609 + if (!aa_unpack_array(e, NULL, &size) || 610 + size > RLIM_NLIMITS) 611 611 goto fail; 612 612 for (i = 0; i < size; i++) { 613 613 u64 tmp2 = 0; 614 614 int a = aa_map_resource(i); 615 615 if (!aa_unpack_u64(e, &tmp2, NULL)) 616 616 goto fail; 617 - profile->rlimits.limits[a].rlim_max = tmp2; 617 + rules->rlimits.limits[a].rlim_max = tmp2; 618 618 } 619 619 if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL)) 620 620 goto fail; ··· 627 625 fail: 628 626 e->pos = pos; 629 627 return false; 628 + } 629 + 630 + static bool unpack_perm(struct aa_ext *e, u32 version, struct aa_perms *perm) 631 + { 632 + if (version != 1) 633 + return false; 634 + 635 + return aa_unpack_u32(e, &perm->allow, NULL) && 636 + aa_unpack_u32(e, &perm->allow, NULL) && 637 + aa_unpack_u32(e, &perm->deny, NULL) && 638 + aa_unpack_u32(e, &perm->subtree, NULL) && 639 + aa_unpack_u32(e, &perm->cond, NULL) && 640 + aa_unpack_u32(e, &perm->kill, NULL) && 641 + aa_unpack_u32(e, &perm->complain, NULL) && 642 + aa_unpack_u32(e, &perm->prompt, NULL) && 643 + aa_unpack_u32(e, &perm->audit, NULL) && 644 + aa_unpack_u32(e, &perm->quiet, NULL) && 645 + aa_unpack_u32(e, &perm->hide, NULL) && 646 + aa_unpack_u32(e, &perm->xindex, NULL) && 647 + aa_unpack_u32(e, &perm->tag, NULL) && 648 + aa_unpack_u32(e, &perm->label, NULL); 649 + } 650 + 651 + static ssize_t unpack_perms_table(struct aa_ext *e, struct aa_perms **perms) 652 + { 653 + void *pos = e->pos; 654 + u16 size = 0; 655 + 656 + AA_BUG(!perms); 657 + /* 658 + * policy perms are optional, in which case perms are embedded 659 + * in the dfa accept table 660 + */ 661 + if (aa_unpack_nameX(e, AA_STRUCT, "perms")) { 662 + int i; 663 + u32 version; 664 + 665 + if (!aa_unpack_u32(e, &version, "version")) 666 + goto fail_reset; 667 + if (!aa_unpack_array(e, NULL, &size)) 668 + goto fail_reset; 669 + *perms = kcalloc(size, sizeof(struct aa_perms), GFP_KERNEL); 670 + if (!*perms) 671 + goto fail_reset; 672 + for (i = 0; i < size; i++) { 673 + if (!unpack_perm(e, version, &(*perms)[i])) 674 + goto fail; 675 + } 676 + if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL)) 677 + goto fail; 678 + if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) 679 + goto fail; 680 + } else 681 + *perms = NULL; 682 + 683 + return size; 684 + 685 + fail: 686 + kfree(*perms); 687 + fail_reset: 688 + e->pos = pos; 689 + return -EPROTO; 690 + } 691 + 692 + static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy, 693 + bool required_dfa, bool required_trans, 694 + const char **info) 695 + { 696 + void *pos = e->pos; 697 + int i, flags, error = -EPROTO; 698 + ssize_t size; 699 + 700 + size = unpack_perms_table(e, &policy->perms); 701 + if (size < 0) { 702 + error = size; 703 + policy->perms = NULL; 704 + *info = "failed to unpack - perms"; 705 + goto fail; 706 + } 707 + policy->size = size; 708 + 709 + if (policy->perms) { 710 + /* perms table present accept is index */ 711 + flags = TO_ACCEPT1_FLAG(YYTD_DATA32); 712 + } else { 713 + /* packed perms in accept1 and accept2 */ 714 + flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | 715 + TO_ACCEPT2_FLAG(YYTD_DATA32); 716 + } 717 + 718 + policy->dfa = unpack_dfa(e, flags); 719 + if (IS_ERR(policy->dfa)) { 720 + error = PTR_ERR(policy->dfa); 721 + policy->dfa = NULL; 722 + *info = "failed to unpack - dfa"; 723 + goto fail; 724 + } else if (!policy->dfa) { 725 + if (required_dfa) { 726 + *info = "missing required dfa"; 727 + goto fail; 728 + } 729 + goto out; 730 + } 731 + 732 + /* 733 + * only unpack the following if a dfa is present 734 + * 735 + * sadly start was given different names for file and policydb 736 + * but since it is optional we can try both 737 + */ 738 + if (!aa_unpack_u32(e, &policy->start[0], "start")) 739 + /* default start state */ 740 + policy->start[0] = DFA_START; 741 + if (!aa_unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) { 742 + /* default start state for xmatch and file dfa */ 743 + policy->start[AA_CLASS_FILE] = DFA_START; 744 + } /* setup class index */ 745 + for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) { 746 + policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0], 747 + i); 748 + } 749 + if (!unpack_trans_table(e, &policy->trans) && required_trans) { 750 + *info = "failed to unpack profile transition table"; 751 + goto fail; 752 + } 753 + 754 + /* TODO: move compat mapping here, requires dfa merging first */ 755 + /* TODO: move verify here, it has to be done after compat mappings */ 756 + out: 757 + return 0; 758 + 759 + fail: 760 + e->pos = pos; 761 + return error; 630 762 } 631 763 632 764 static u32 strhash(const void *data, u32 len, u32 seed) ··· 787 651 */ 788 652 static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) 789 653 { 654 + struct aa_ruleset *rules; 790 655 struct aa_profile *profile = NULL; 791 656 const char *tmpname, *tmpns = NULL, *name = NULL; 792 657 const char *info = "failed to unpack profile"; ··· 795 658 struct rhashtable_params params = { 0 }; 796 659 char *key = NULL; 797 660 struct aa_data *data; 798 - int i, error = -EPROTO; 661 + int error = -EPROTO; 799 662 kernel_cap_t tmpcap; 800 663 u32 tmp; 801 664 ··· 814 677 *ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL); 815 678 if (!*ns_name) { 816 679 info = "out of memory"; 680 + error = -ENOMEM; 817 681 goto fail; 818 682 } 819 683 name = tmpname; 820 684 } 821 685 822 686 profile = aa_alloc_profile(name, NULL, GFP_KERNEL); 823 - if (!profile) 824 - return ERR_PTR(-ENOMEM); 687 + if (!profile) { 688 + info = "out of memory"; 689 + error = -ENOMEM; 690 + goto fail; 691 + } 692 + rules = list_first_entry(&profile->rules, typeof(*rules), list); 825 693 826 694 /* profile renaming is optional */ 827 695 (void) aa_unpack_str(e, &profile->rename, "rename"); 828 696 829 697 /* attachment string is optional */ 830 - (void) aa_unpack_str(e, &profile->attach, "attach"); 698 + (void) aa_unpack_str(e, &profile->attach.xmatch_str, "attach"); 831 699 832 700 /* xmatch is optional and may be NULL */ 833 - profile->xmatch = unpack_dfa(e); 834 - if (IS_ERR(profile->xmatch)) { 835 - error = PTR_ERR(profile->xmatch); 836 - profile->xmatch = NULL; 701 + error = unpack_pdb(e, &profile->attach.xmatch, false, false, &info); 702 + if (error) { 837 703 info = "bad xmatch"; 838 704 goto fail; 839 705 } 840 - /* xmatch_len is not optional if xmatch is set */ 841 - if (profile->xmatch) { 706 + 707 + /* neither xmatch_len not xmatch_perms are optional if xmatch is set */ 708 + if (profile->attach.xmatch.dfa) { 842 709 if (!aa_unpack_u32(e, &tmp, NULL)) { 843 710 info = "missing xmatch len"; 844 711 goto fail; 845 712 } 846 - profile->xmatch_len = tmp; 713 + profile->attach.xmatch_len = tmp; 714 + profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START; 715 + error = aa_compat_map_xmatch(&profile->attach.xmatch); 716 + if (error) { 717 + info = "failed to convert xmatch permission table"; 718 + goto fail; 719 + } 847 720 } 848 721 849 722 /* disconnected attachment string is optional */ ··· 884 737 } else if (tmp == PACKED_MODE_UNCONFINED) { 885 738 profile->mode = APPARMOR_UNCONFINED; 886 739 profile->label.flags |= FLAG_UNCONFINED; 740 + } else if (tmp == PACKED_MODE_USER) { 741 + profile->mode = APPARMOR_USER; 887 742 } else { 888 743 goto fail; 889 744 } ··· 906 757 profile->path_flags = PATH_MEDIATE_DELETED; 907 758 908 759 info = "failed to unpack profile capabilities"; 909 - if (!aa_unpack_u32(e, &(profile->caps.allow.cap[0]), NULL)) 760 + if (!aa_unpack_u32(e, &(rules->caps.allow.cap[0]), NULL)) 910 761 goto fail; 911 - if (!aa_unpack_u32(e, &(profile->caps.audit.cap[0]), NULL)) 762 + if (!aa_unpack_u32(e, &(rules->caps.audit.cap[0]), NULL)) 912 763 goto fail; 913 - if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL)) 764 + if (!aa_unpack_u32(e, &(rules->caps.quiet.cap[0]), NULL)) 914 765 goto fail; 915 766 if (!aa_unpack_u32(e, &tmpcap.cap[0], NULL)) 916 767 goto fail; ··· 918 769 info = "failed to unpack upper profile capabilities"; 919 770 if (aa_unpack_nameX(e, AA_STRUCT, "caps64")) { 920 771 /* optional upper half of 64 bit caps */ 921 - if (!aa_unpack_u32(e, &(profile->caps.allow.cap[1]), NULL)) 772 + if (!aa_unpack_u32(e, &(rules->caps.allow.cap[1]), NULL)) 922 773 goto fail; 923 - if (!aa_unpack_u32(e, &(profile->caps.audit.cap[1]), NULL)) 774 + if (!aa_unpack_u32(e, &(rules->caps.audit.cap[1]), NULL)) 924 775 goto fail; 925 - if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL)) 776 + if (!aa_unpack_u32(e, &(rules->caps.quiet.cap[1]), NULL)) 926 777 goto fail; 927 778 if (!aa_unpack_u32(e, &(tmpcap.cap[1]), NULL)) 928 779 goto fail; ··· 933 784 info = "failed to unpack extended profile capabilities"; 934 785 if (aa_unpack_nameX(e, AA_STRUCT, "capsx")) { 935 786 /* optional extended caps mediation mask */ 936 - if (!aa_unpack_u32(e, &(profile->caps.extended.cap[0]), NULL)) 787 + if (!aa_unpack_u32(e, &(rules->caps.extended.cap[0]), NULL)) 937 788 goto fail; 938 - if (!aa_unpack_u32(e, &(profile->caps.extended.cap[1]), NULL)) 789 + if (!aa_unpack_u32(e, &(rules->caps.extended.cap[1]), NULL)) 939 790 goto fail; 940 791 if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) 941 792 goto fail; ··· 946 797 goto fail; 947 798 } 948 799 949 - if (!unpack_rlimits(e, profile)) { 800 + if (!unpack_rlimits(e, rules)) { 950 801 info = "failed to unpack profile rlimits"; 951 802 goto fail; 952 803 } 953 804 954 - if (!unpack_secmark(e, profile)) { 805 + if (!unpack_secmark(e, rules)) { 955 806 info = "failed to unpack profile secmark rules"; 956 807 goto fail; 957 808 } ··· 959 810 if (aa_unpack_nameX(e, AA_STRUCT, "policydb")) { 960 811 /* generic policy dfa - optional and may be NULL */ 961 812 info = "failed to unpack policydb"; 962 - profile->policy.dfa = unpack_dfa(e); 963 - if (IS_ERR(profile->policy.dfa)) { 964 - error = PTR_ERR(profile->policy.dfa); 965 - profile->policy.dfa = NULL; 813 + error = unpack_pdb(e, &rules->policy, true, false, 814 + &info); 815 + if (error) 966 816 goto fail; 967 - } else if (!profile->policy.dfa) { 968 - error = -EPROTO; 969 - goto fail; 970 - } 971 - if (!aa_unpack_u32(e, &profile->policy.start[0], "start")) 972 - /* default start state */ 973 - profile->policy.start[0] = DFA_START; 974 - /* setup class index */ 975 - for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) { 976 - profile->policy.start[i] = 977 - aa_dfa_next(profile->policy.dfa, 978 - profile->policy.start[0], 979 - i); 980 - } 817 + /* Fixup: drop when we get rid of start array */ 818 + if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0], 819 + AA_CLASS_FILE)) 820 + rules->policy.start[AA_CLASS_FILE] = 821 + aa_dfa_next(rules->policy.dfa, 822 + rules->policy.start[0], 823 + AA_CLASS_FILE); 981 824 if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) 982 825 goto fail; 826 + error = aa_compat_map_policy(&rules->policy, e->version); 827 + if (error) { 828 + info = "failed to remap policydb permission table"; 829 + goto fail; 830 + } 983 831 } else 984 - profile->policy.dfa = aa_get_dfa(nulldfa); 832 + rules->policy.dfa = aa_get_dfa(nulldfa); 985 833 986 834 /* get file rules */ 987 - profile->file.dfa = unpack_dfa(e); 988 - if (IS_ERR(profile->file.dfa)) { 989 - error = PTR_ERR(profile->file.dfa); 990 - profile->file.dfa = NULL; 991 - info = "failed to unpack profile file rules"; 835 + error = unpack_pdb(e, &rules->file, false, true, &info); 836 + if (error) { 992 837 goto fail; 993 - } else if (profile->file.dfa) { 994 - if (!aa_unpack_u32(e, &profile->file.start, "dfa_start")) 995 - /* default start state */ 996 - profile->file.start = DFA_START; 997 - } else if (profile->policy.dfa && 998 - profile->policy.start[AA_CLASS_FILE]) { 999 - profile->file.dfa = aa_get_dfa(profile->policy.dfa); 1000 - profile->file.start = profile->policy.start[AA_CLASS_FILE]; 838 + } else if (rules->file.dfa) { 839 + error = aa_compat_map_file(&rules->file); 840 + if (error) { 841 + info = "failed to remap file permission table"; 842 + goto fail; 843 + } 844 + } else if (rules->policy.dfa && 845 + rules->policy.start[AA_CLASS_FILE]) { 846 + rules->file.dfa = aa_get_dfa(rules->policy.dfa); 847 + rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE]; 1001 848 } else 1002 - profile->file.dfa = aa_get_dfa(nulldfa); 849 + rules->file.dfa = aa_get_dfa(nulldfa); 1003 850 1004 - if (!unpack_trans_table(e, profile)) { 1005 - info = "failed to unpack profile transition table"; 1006 - goto fail; 1007 - } 1008 - 851 + error = -EPROTO; 1009 852 if (aa_unpack_nameX(e, AA_STRUCT, "data")) { 1010 853 info = "out of memory"; 1011 854 profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL); 1012 - if (!profile->data) 855 + if (!profile->data) { 856 + error = -ENOMEM; 1013 857 goto fail; 1014 - 858 + } 1015 859 params.nelem_hint = 3; 1016 860 params.key_len = sizeof(void *); 1017 861 params.key_offset = offsetof(struct aa_data, key); ··· 1021 879 data = kzalloc(sizeof(*data), GFP_KERNEL); 1022 880 if (!data) { 1023 881 kfree_sensitive(key); 882 + error = -ENOMEM; 1024 883 goto fail; 1025 884 } 1026 885 ··· 1031 888 if (data->size && !data->data) { 1032 889 kfree_sensitive(data->key); 1033 890 kfree_sensitive(data); 891 + error = -ENOMEM; 1034 892 goto fail; 1035 893 } 1036 894 ··· 1053 909 return profile; 1054 910 1055 911 fail: 912 + if (error == 0) 913 + /* default error covers most cases */ 914 + error = -EPROTO; 915 + if (*ns_name) { 916 + kfree(*ns_name); 917 + *ns_name = NULL; 918 + } 1056 919 if (profile) 1057 920 name = NULL; 1058 921 else if (!name) ··· 1097 946 * if not specified use previous version 1098 947 * Mask off everything that is not kernel abi version 1099 948 */ 1100 - if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v7)) { 949 + if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v9)) { 1101 950 audit_iface(NULL, NULL, NULL, "unsupported interface version", 1102 951 e, error); 1103 952 return error; ··· 1138 987 { 1139 988 int i; 1140 989 for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) { 1141 - if (!verify_xindex(dfa_user_xindex(dfa, i), table_size)) 1142 - return false; 1143 - if (!verify_xindex(dfa_other_xindex(dfa, i), table_size)) 990 + if (!verify_xindex(ACCEPT_TABLE(dfa)[i], table_size)) 1144 991 return false; 1145 992 } 993 + return true; 994 + } 995 + 996 + static bool verify_perm(struct aa_perms *perm) 997 + { 998 + /* TODO: allow option to just force the perms into a valid state */ 999 + if (perm->allow & perm->deny) 1000 + return false; 1001 + if (perm->subtree & ~perm->allow) 1002 + return false; 1003 + if (perm->cond & (perm->allow | perm->deny)) 1004 + return false; 1005 + if (perm->kill & perm->allow) 1006 + return false; 1007 + if (perm->complain & (perm->allow | perm->deny)) 1008 + return false; 1009 + if (perm->prompt & (perm->allow | perm->deny)) 1010 + return false; 1011 + if (perm->complain & perm->prompt) 1012 + return false; 1013 + if (perm->hide & perm->allow) 1014 + return false; 1015 + 1016 + return true; 1017 + } 1018 + 1019 + static bool verify_perms(struct aa_policydb *pdb) 1020 + { 1021 + int i; 1022 + 1023 + for (i = 0; i < pdb->size; i++) { 1024 + if (!verify_perm(&pdb->perms[i])) 1025 + return false; 1026 + /* verify indexes into str table */ 1027 + if (pdb->perms[i].xindex >= pdb->trans.size) 1028 + return false; 1029 + if (pdb->perms[i].tag >= pdb->trans.size) 1030 + return false; 1031 + if (pdb->perms[i].label >= pdb->trans.size) 1032 + return false; 1033 + } 1034 + 1146 1035 return true; 1147 1036 } 1148 1037 ··· 1191 1000 * @profile: profile to verify (NOT NULL) 1192 1001 * 1193 1002 * Returns: 0 if passes verification else error 1003 + * 1004 + * This verification is post any unpack mapping or changes 1194 1005 */ 1195 1006 static int verify_profile(struct aa_profile *profile) 1196 1007 { 1197 - if (profile->file.dfa && 1198 - !verify_dfa_xindex(profile->file.dfa, 1199 - profile->file.trans.size)) { 1200 - audit_iface(profile, NULL, NULL, "Invalid named transition", 1201 - NULL, -EPROTO); 1008 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 1009 + typeof(*rules), list); 1010 + if (!rules) 1011 + return 0; 1012 + 1013 + if ((rules->file.dfa && !verify_dfa_xindex(rules->file.dfa, 1014 + rules->file.trans.size)) || 1015 + (rules->policy.dfa && 1016 + !verify_dfa_xindex(rules->policy.dfa, rules->policy.trans.size))) { 1017 + audit_iface(profile, NULL, NULL, 1018 + "Unpack: Invalid named transition", NULL, -EPROTO); 1019 + return -EPROTO; 1020 + } 1021 + 1022 + if (!verify_perms(&rules->file)) { 1023 + audit_iface(profile, NULL, NULL, 1024 + "Unpack: Invalid perm index", NULL, -EPROTO); 1025 + return -EPROTO; 1026 + } 1027 + if (!verify_perms(&rules->policy)) { 1028 + audit_iface(profile, NULL, NULL, 1029 + "Unpack: Invalid perm index", NULL, -EPROTO); 1030 + return -EPROTO; 1031 + } 1032 + if (!verify_perms(&profile->attach.xmatch)) { 1033 + audit_iface(profile, NULL, NULL, 1034 + "Unpack: Invalid perm index", NULL, -EPROTO); 1202 1035 return -EPROTO; 1203 1036 } 1204 1037 ··· 1248 1033 return ent; 1249 1034 } 1250 1035 1251 - static int deflate_compress(const char *src, size_t slen, char **dst, 1252 - size_t *dlen) 1036 + static int compress_zstd(const char *src, size_t slen, char **dst, size_t *dlen) 1253 1037 { 1254 1038 #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 1255 - int error; 1256 - struct z_stream_s strm; 1257 - void *stgbuf, *dstbuf; 1258 - size_t stglen = deflateBound(slen); 1039 + const zstd_parameters params = 1040 + zstd_get_params(aa_g_rawdata_compression_level, slen); 1041 + const size_t wksp_len = zstd_cctx_workspace_bound(&params.cParams); 1042 + void *wksp = NULL; 1043 + zstd_cctx *ctx = NULL; 1044 + size_t out_len = zstd_compress_bound(slen); 1045 + void *out = NULL; 1046 + int ret = 0; 1259 1047 1260 - memset(&strm, 0, sizeof(strm)); 1261 - 1262 - if (stglen < slen) 1263 - return -EFBIG; 1264 - 1265 - strm.workspace = kvzalloc(zlib_deflate_workspacesize(MAX_WBITS, 1266 - MAX_MEM_LEVEL), 1267 - GFP_KERNEL); 1268 - if (!strm.workspace) 1269 - return -ENOMEM; 1270 - 1271 - error = zlib_deflateInit(&strm, aa_g_rawdata_compression_level); 1272 - if (error != Z_OK) { 1273 - error = -ENOMEM; 1274 - goto fail_deflate_init; 1048 + out = kvzalloc(out_len, GFP_KERNEL); 1049 + if (!out) { 1050 + ret = -ENOMEM; 1051 + goto cleanup; 1275 1052 } 1276 1053 1277 - stgbuf = kvzalloc(stglen, GFP_KERNEL); 1278 - if (!stgbuf) { 1279 - error = -ENOMEM; 1280 - goto fail_stg_alloc; 1054 + wksp = kvzalloc(wksp_len, GFP_KERNEL); 1055 + if (!wksp) { 1056 + ret = -ENOMEM; 1057 + goto cleanup; 1281 1058 } 1282 1059 1283 - strm.next_in = src; 1284 - strm.avail_in = slen; 1285 - strm.next_out = stgbuf; 1286 - strm.avail_out = stglen; 1287 - 1288 - error = zlib_deflate(&strm, Z_FINISH); 1289 - if (error != Z_STREAM_END) { 1290 - error = -EINVAL; 1291 - goto fail_deflate; 1060 + ctx = zstd_init_cctx(wksp, wksp_len); 1061 + if (!ctx) { 1062 + ret = -EINVAL; 1063 + goto cleanup; 1292 1064 } 1293 - error = 0; 1294 1065 1295 - if (is_vmalloc_addr(stgbuf)) { 1296 - dstbuf = kvzalloc(strm.total_out, GFP_KERNEL); 1297 - if (dstbuf) { 1298 - memcpy(dstbuf, stgbuf, strm.total_out); 1299 - kvfree(stgbuf); 1066 + out_len = zstd_compress_cctx(ctx, out, out_len, src, slen, &params); 1067 + if (zstd_is_error(out_len) || out_len >= slen) { 1068 + ret = -EINVAL; 1069 + goto cleanup; 1070 + } 1071 + 1072 + if (is_vmalloc_addr(out)) { 1073 + *dst = kvzalloc(out_len, GFP_KERNEL); 1074 + if (*dst) { 1075 + memcpy(*dst, out, out_len); 1076 + kvfree(out); 1077 + out = NULL; 1300 1078 } 1301 - } else 1079 + } else { 1302 1080 /* 1303 1081 * If the staging buffer was kmalloc'd, then using krealloc is 1304 1082 * probably going to be faster. The destination buffer will 1305 1083 * always be smaller, so it's just shrunk, avoiding a memcpy 1306 1084 */ 1307 - dstbuf = krealloc(stgbuf, strm.total_out, GFP_KERNEL); 1308 - 1309 - if (!dstbuf) { 1310 - error = -ENOMEM; 1311 - goto fail_deflate; 1085 + *dst = krealloc(out, out_len, GFP_KERNEL); 1312 1086 } 1313 1087 1314 - *dst = dstbuf; 1315 - *dlen = strm.total_out; 1088 + if (!*dst) { 1089 + ret = -ENOMEM; 1090 + goto cleanup; 1091 + } 1316 1092 1317 - fail_stg_alloc: 1318 - zlib_deflateEnd(&strm); 1319 - fail_deflate_init: 1320 - kvfree(strm.workspace); 1321 - return error; 1093 + *dlen = out_len; 1322 1094 1323 - fail_deflate: 1324 - kvfree(stgbuf); 1325 - goto fail_stg_alloc; 1095 + cleanup: 1096 + if (ret) { 1097 + kvfree(out); 1098 + *dst = NULL; 1099 + } 1100 + 1101 + kvfree(wksp); 1102 + return ret; 1326 1103 #else 1327 1104 *dlen = slen; 1328 1105 return 0; ··· 1323 1116 1324 1117 static int compress_loaddata(struct aa_loaddata *data) 1325 1118 { 1326 - 1327 1119 AA_BUG(data->compressed_size > 0); 1328 1120 1329 1121 /* ··· 1331 1125 */ 1332 1126 if (aa_g_rawdata_compression_level != 0) { 1333 1127 void *udata = data->data; 1334 - int error = deflate_compress(udata, data->size, &data->data, 1335 - &data->compressed_size); 1336 - if (error) 1128 + int error = compress_zstd(udata, data->size, &data->data, 1129 + &data->compressed_size); 1130 + if (error) { 1131 + data->compressed_size = data->size; 1337 1132 return error; 1338 - 1133 + } 1339 1134 if (udata != data->data) 1340 1135 kvfree(udata); 1341 1136 } else ··· 1362 1155 { 1363 1156 struct aa_load_ent *tmp, *ent; 1364 1157 struct aa_profile *profile = NULL; 1158 + char *ns_name = NULL; 1365 1159 int error; 1366 1160 struct aa_ext e = { 1367 1161 .start = udata->data, ··· 1372 1164 1373 1165 *ns = NULL; 1374 1166 while (e.pos < e.end) { 1375 - char *ns_name = NULL; 1376 1167 void *start; 1377 1168 error = verify_header(&e, e.pos == e.start, ns); 1378 1169 if (error) ··· 1402 1195 1403 1196 ent->new = profile; 1404 1197 ent->ns_name = ns_name; 1198 + ns_name = NULL; 1405 1199 list_add_tail(&ent->list, lh); 1406 1200 } 1407 1201 udata->abi = e.version & K_ABI_MASK; ··· 1423 1215 return 0; 1424 1216 1425 1217 fail_profile: 1218 + kfree(ns_name); 1426 1219 aa_put_profile(profile); 1427 1220 1428 1221 fail:
+5 -9
security/apparmor/policy_unpack_test.c
··· 143 143 static void policy_unpack_test_unpack_array_with_null_name(struct kunit *test) 144 144 { 145 145 struct policy_unpack_fixture *puf = test->priv; 146 - u16 array_size; 146 + u16 array_size = 0; 147 147 148 148 puf->e->pos += TEST_ARRAY_BUF_OFFSET; 149 149 150 - array_size = aa_unpack_array(puf->e, NULL); 151 - 150 + KUNIT_EXPECT_TRUE(test, aa_unpack_array(puf->e, NULL, &array_size)); 152 151 KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE); 153 152 KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, 154 153 puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1); ··· 157 158 { 158 159 struct policy_unpack_fixture *puf = test->priv; 159 160 const char name[] = TEST_ARRAY_NAME; 160 - u16 array_size; 161 + u16 array_size = 0; 161 162 162 163 puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET; 163 164 164 - array_size = aa_unpack_array(puf->e, name); 165 - 165 + KUNIT_EXPECT_TRUE(test, aa_unpack_array(puf->e, name, &array_size)); 166 166 KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE); 167 167 KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, 168 168 puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1); ··· 176 178 puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET; 177 179 puf->e->end = puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16); 178 180 179 - array_size = aa_unpack_array(puf->e, name); 180 - 181 - KUNIT_EXPECT_EQ(test, array_size, 0); 181 + KUNIT_EXPECT_FALSE(test, aa_unpack_array(puf->e, name, &array_size)); 182 182 KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, 183 183 puf->e->start + TEST_NAMED_ARRAY_BUF_OFFSET); 184 184 }
+5 -6
security/apparmor/procattr.c
··· 17 17 18 18 19 19 /** 20 - * aa_getprocattr - Return the profile information for @profile 21 - * @profile: the profile to print profile info about (NOT NULL) 22 - * @string: Returns - string containing the profile info (NOT NULL) 20 + * aa_getprocattr - Return the label information for @label 21 + * @label: the label to print label info about (NOT NULL) 22 + * @string: Returns - string containing the label info (NOT NULL) 23 23 * 24 - * Requires: profile != NULL 24 + * Requires: label != NULL && string != NULL 25 25 * 26 - * Creates a string containing the namespace_name://profile_name for 27 - * @profile. 26 + * Creates a string containing the label information for @label. 28 27 * 29 28 * Returns: size of string placed in @string else error code on failure 30 29 */
+20 -9
security/apparmor/resource.c
··· 45 45 * @profile: profile being enforced (NOT NULL) 46 46 * @resource: rlimit being auditing 47 47 * @value: value being set 48 + * @peer: aa_albel of the task being set 49 + * @info: info being auditing 48 50 * @error: error value 49 51 * 50 52 * Returns: 0 or sa->error else other error code on failure ··· 55 53 unsigned long value, struct aa_label *peer, 56 54 const char *info, int error) 57 55 { 58 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETRLIMIT); 56 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_RLIMITS, 57 + OP_SETRLIMIT); 59 58 60 59 aad(&sa)->rlim.rlim = resource; 61 60 aad(&sa)->rlim.max = value; ··· 68 65 } 69 66 70 67 /** 71 - * aa_map_resouce - map compiled policy resource to internal # 68 + * aa_map_resource - map compiled policy resource to internal # 72 69 * @resource: flattened policy resource number 73 70 * 74 71 * Returns: resource # for the current architecture. ··· 84 81 static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, 85 82 struct rlimit *new_rlim) 86 83 { 84 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 85 + typeof(*rules), list); 87 86 int e = 0; 88 87 89 - if (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > 90 - profile->rlimits.limits[resource].rlim_max) 88 + if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max > 89 + rules->rlimits.limits[resource].rlim_max) 91 90 e = -EACCES; 92 91 return audit_resource(profile, resource, new_rlim->rlim_max, NULL, NULL, 93 92 e); ··· 157 152 * to the lesser of the tasks hard limit and the init tasks soft limit 158 153 */ 159 154 label_for_each_confined(i, old_l, old) { 160 - if (old->rlimits.mask) { 155 + struct aa_ruleset *rules = list_first_entry(&old->rules, 156 + typeof(*rules), 157 + list); 158 + if (rules->rlimits.mask) { 161 159 int j; 162 160 163 161 for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, 164 162 mask <<= 1) { 165 - if (old->rlimits.mask & mask) { 163 + if (rules->rlimits.mask & mask) { 166 164 rlim = current->signal->rlim + j; 167 165 initrlim = init_task.signal->rlim + j; 168 166 rlim->rlim_cur = min(rlim->rlim_max, ··· 177 169 178 170 /* set any new hard limits as dictated by the new profile */ 179 171 label_for_each_confined(i, new_l, new) { 172 + struct aa_ruleset *rules = list_first_entry(&new->rules, 173 + typeof(*rules), 174 + list); 180 175 int j; 181 176 182 - if (!new->rlimits.mask) 177 + if (!rules->rlimits.mask) 183 178 continue; 184 179 for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) { 185 - if (!(new->rlimits.mask & mask)) 180 + if (!(rules->rlimits.mask & mask)) 186 181 continue; 187 182 188 183 rlim = current->signal->rlim + j; 189 184 rlim->rlim_max = min(rlim->rlim_max, 190 - new->rlimits.limits[j].rlim_max); 185 + rules->rlimits.limits[j].rlim_max); 191 186 /* soft limit should not exceed hard limit */ 192 187 rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max); 193 188 }
+8 -6
security/apparmor/task.c
··· 31 31 struct aa_label *p; 32 32 33 33 rcu_read_lock(); 34 - p = aa_get_newest_label(__aa_task_raw_label(task)); 34 + p = aa_get_newest_cred_label(__task_cred(task)); 35 35 rcu_read_unlock(); 36 36 37 37 return p; ··· 223 223 FLAGS_NONE, GFP_ATOMIC); 224 224 } 225 225 226 - /* assumes check for PROFILE_MEDIATES is already done */ 226 + /* assumes check for RULE_MEDIATES is already done */ 227 227 /* TODO: conditionals */ 228 228 static int profile_ptrace_perm(struct aa_profile *profile, 229 229 struct aa_label *peer, u32 request, 230 230 struct common_audit_data *sa) 231 231 { 232 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 233 + typeof(*rules), list); 232 234 struct aa_perms perms = { }; 233 235 234 236 aad(sa)->peer = peer; 235 - aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, 237 + aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request, 236 238 &perms); 237 239 aa_apply_modes_to_perms(profile, &perms); 238 240 return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); ··· 245 243 struct common_audit_data *sa) 246 244 { 247 245 if (profile_unconfined(tracee) || unconfined(tracer) || 248 - !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) 246 + !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE)) 249 247 return 0; 250 248 251 249 return profile_ptrace_perm(tracee, tracer, request, sa); ··· 258 256 if (profile_unconfined(tracer)) 259 257 return 0; 260 258 261 - if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) 259 + if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE)) 262 260 return profile_ptrace_perm(tracer, tracee, request, sa); 263 261 264 262 /* profile uses the old style capability check for ptrace */ ··· 287 285 { 288 286 struct aa_profile *profile; 289 287 u32 xrequest = request << PTRACE_PERM_SHIFT; 290 - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); 288 + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE); 291 289 292 290 return xcheck_labels(tracer, tracee, profile, 293 291 profile_tracer_perm(profile, tracee, request, &sa),