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

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

Pull apparmor updates from John Johansen:
"Features:
- extend next/check table to add support for 2^24 states to the state
machine.
- rework capability audit cache to use broader cred information
instead of just the profile. Also add a time stamp so old entries
can be aged out of the cache.

Bug Fixes:
- fix 'Do simple duplicate message elimination' to clear previous
state when updating in capability audit cache
- Fix memory leak for aa_unpack_strdup()
- properly handle cx/px lookup failure when in complain mode
- allocate xmatch for nullpdb inside aa_alloc_null fixing a NULL ptr
deref of tracking profiles in when in complain mode

Cleanups:
- Remove everything being reported as deadcode
- replace misleading 'scrubbing environment' phrase in debug print
- Remove unnecessary NULL check before kvfree()
- clean up duplicated parts of handle_onexec()
- Use IS_ERR_OR_NULL() helper function
- move new_profile declaration to top of block instead immediately
after label to remove C23 extension warning

Documentation:
- add comment to document capability.c:profile_capable ad ptr
parameter can not be NULL
- add comment to document first entry is in packed perms struct is
reserved for future planned expansion.
- Update LSM/apparmor.rst add blurb for DEFAULT_SECURITY_APPARMOR"

* tag 'apparmor-pr-2024-11-27' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor:
apparmor: lift new_profile declaration to remove C23 extension warning
apparmor: replace misleading 'scrubbing environment' phrase in debug print
parser: drop dead code for XXX_comb macros
apparmor: Remove unused parameter L1 in macro next_comb
Docs: Update LSM/apparmor.rst
apparmor: audit_cap dedup based on subj_cred instead of profile
apparmor: add a cache entry expiration time aging out capability audit cache
apparmor: document capability.c:profile_capable ad ptr not being NULL
apparmor: fix 'Do simple duplicate message elimination'
apparmor: document first entry is in packed perms struct is reserved
apparmor: test: Fix memory leak for aa_unpack_strdup()
apparmor: Remove deadcode
apparmor: Remove unnecessary NULL check before kvfree()
apparmor: domain: clean up duplicated parts of handle_onexec()
apparmor: Use IS_ERR_OR_NULL() helper function
apparmor: add support for 2^24 states to the dfa state machine.
apparmor: properly handle cx/px lookup failure for complain
apparmor: allocate xmatch for nullpdb inside aa_alloc_null

+141 -246
+5 -2
Documentation/admin-guide/LSM/apparmor.rst
··· 18 18 19 19 If AppArmor should be selected as the default security module then set:: 20 20 21 - CONFIG_DEFAULT_SECURITY="apparmor" 22 - CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 21 + CONFIG_DEFAULT_SECURITY_APPARMOR=y 22 + 23 + The CONFIG_LSM parameter manages the order and selection of LSMs. 24 + Specify apparmor as the first "major" module (e.g. AppArmor, SELinux, Smack) 25 + in the list. 23 26 24 27 Build the kernel 25 28
+1
security/apparmor/apparmorfs.c
··· 2366 2366 AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED), 2367 2367 AA_SFS_FILE_U64("permstable32_version", 1), 2368 2368 AA_SFS_FILE_STRING("permstable32", PERMS32STR), 2369 + AA_SFS_FILE_U64("state32", 1), 2369 2370 AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined), 2370 2371 { } 2371 2372 };
+12 -7
security/apparmor/capability.c
··· 12 12 #include <linux/errno.h> 13 13 #include <linux/gfp.h> 14 14 #include <linux/security.h> 15 + #include <linux/timekeeping.h> 15 16 16 17 #include "include/apparmor.h" 17 18 #include "include/capability.h" ··· 31 30 }; 32 31 33 32 struct audit_cache { 34 - struct aa_profile *profile; 35 - kernel_cap_t caps; 33 + const struct cred *ad_subj_cred; 34 + /* Capabilities go from 0 to CAP_LAST_CAP */ 35 + u64 ktime_ns_expiration[CAP_LAST_CAP+1]; 36 36 }; 37 37 38 38 static DEFINE_PER_CPU(struct audit_cache, audit_cache); ··· 66 64 static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile, 67 65 int cap, int error) 68 66 { 67 + const u64 AUDIT_CACHE_TIMEOUT_NS = 1000*1000*1000; /* 1 second */ 68 + 69 69 struct aa_ruleset *rules = list_first_entry(&profile->rules, 70 70 typeof(*rules), list); 71 71 struct audit_cache *ent; ··· 93 89 94 90 /* Do simple duplicate message elimination */ 95 91 ent = &get_cpu_var(audit_cache); 96 - if (profile == ent->profile && cap_raised(ent->caps, cap)) { 92 + /* If the capability was never raised the timestamp check would also catch that */ 93 + if (ad->subj_cred == ent->ad_subj_cred && ktime_get_ns() <= ent->ktime_ns_expiration[cap]) { 97 94 put_cpu_var(audit_cache); 98 95 if (COMPLAIN_MODE(profile)) 99 96 return complain_error(error); 100 97 return error; 101 98 } else { 102 - aa_put_profile(ent->profile); 103 - ent->profile = aa_get_profile(profile); 104 - cap_raise(ent->caps, cap); 99 + put_cred(ent->ad_subj_cred); 100 + ent->ad_subj_cred = get_cred(ad->subj_cred); 101 + ent->ktime_ns_expiration[cap] = ktime_get_ns() + AUDIT_CACHE_TIMEOUT_NS; 105 102 } 106 103 put_cpu_var(audit_cache); 107 104 ··· 114 109 * @profile: profile being enforced (NOT NULL, NOT unconfined) 115 110 * @cap: capability to test if allowed 116 111 * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated 117 - * @ad: audit data (MAY BE NULL indicating no auditing) 112 + * @ad: audit data (NOT NULL) 118 113 * 119 114 * Returns: 0 if allowed else -EPERM 120 115 */
+28 -38
security/apparmor/domain.c
··· 636 636 struct aa_ruleset *rules = list_first_entry(&profile->rules, 637 637 typeof(*rules), list); 638 638 struct aa_label *new = NULL; 639 + struct aa_profile *new_profile = NULL; 639 640 const char *info = NULL, *name = NULL, *target = NULL; 640 641 aa_state_t state = rules->file->start[AA_CLASS_FILE]; 641 642 struct aa_perms perms = {}; ··· 681 680 /* hack ix fallback - improve how this is detected */ 682 681 goto audit; 683 682 } else if (!new) { 684 - error = -EACCES; 685 683 info = "profile transition not found"; 686 - /* remove MAY_EXEC to audit as failure */ 684 + /* remove MAY_EXEC to audit as failure or complaint */ 687 685 perms.allow &= ~MAY_EXEC; 686 + if (COMPLAIN_MODE(profile)) { 687 + /* create null profile instead of failing */ 688 + goto create_learning_profile; 689 + } 690 + error = -EACCES; 688 691 } 689 692 } else if (COMPLAIN_MODE(profile)) { 693 + create_learning_profile: 690 694 /* no exec permission - learning mode */ 691 - struct aa_profile *new_profile = NULL; 692 - 693 695 new_profile = aa_new_learning_profile(profile, false, name, 694 696 GFP_KERNEL); 695 697 if (!new_profile) { ··· 713 709 714 710 if (!(perms.xindex & AA_X_UNSAFE)) { 715 711 if (DEBUG_ON) { 716 - dbg_printk("apparmor: scrubbing environment variables" 717 - " for %s profile=", name); 712 + dbg_printk("apparmor: setting AT_SECURE for %s profile=", 713 + name); 718 714 aa_label_printk(new, GFP_KERNEL); 719 715 dbg_printk("\n"); 720 716 } ··· 793 789 794 790 if (!(perms.xindex & AA_X_UNSAFE)) { 795 791 if (DEBUG_ON) { 796 - dbg_printk("apparmor: scrubbing environment " 797 - "variables for %s label=", xname); 792 + dbg_printk("apparmor: setting AT_SECURE for %s label=", 793 + xname); 798 794 aa_label_printk(onexec, GFP_KERNEL); 799 795 dbg_printk("\n"); 800 796 } ··· 825 821 AA_BUG(!bprm); 826 822 AA_BUG(!buffer); 827 823 828 - if (!stack) { 829 - error = fn_for_each_in_ns(label, profile, 830 - profile_onexec(subj_cred, profile, onexec, stack, 831 - bprm, buffer, cond, unsafe)); 832 - if (error) 833 - return ERR_PTR(error); 834 - new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 835 - aa_get_newest_label(onexec), 836 - profile_transition(subj_cred, profile, bprm, 837 - buffer, 838 - cond, unsafe)); 824 + /* TODO: determine how much we want to loosen this */ 825 + error = fn_for_each_in_ns(label, profile, 826 + profile_onexec(subj_cred, profile, onexec, stack, 827 + bprm, buffer, cond, unsafe)); 828 + if (error) 829 + return ERR_PTR(error); 839 830 840 - } else { 841 - /* TODO: determine how much we want to loosen this */ 842 - error = fn_for_each_in_ns(label, profile, 843 - profile_onexec(subj_cred, profile, onexec, stack, bprm, 844 - buffer, cond, unsafe)); 845 - if (error) 846 - return ERR_PTR(error); 847 - new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 848 - aa_label_merge(&profile->label, onexec, 849 - GFP_KERNEL), 850 - profile_transition(subj_cred, profile, bprm, 851 - buffer, 852 - cond, unsafe)); 853 - } 854 - 831 + new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 832 + stack ? aa_label_merge(&profile->label, onexec, 833 + GFP_KERNEL) 834 + : aa_get_newest_label(onexec), 835 + profile_transition(subj_cred, profile, bprm, 836 + buffer, cond, unsafe)); 855 837 if (new) 856 838 return new; 857 839 ··· 950 960 951 961 if (unsafe) { 952 962 if (DEBUG_ON) { 953 - dbg_printk("scrubbing environment variables for %s " 954 - "label=", bprm->filename); 963 + dbg_printk("setting AT_SECURE for %s label=", 964 + bprm->filename); 955 965 aa_label_printk(new, GFP_KERNEL); 956 966 dbg_printk("\n"); 957 967 } ··· 961 971 if (label->proxy != new->proxy) { 962 972 /* when transitioning clear unsafe personality bits */ 963 973 if (DEBUG_ON) { 964 - dbg_printk("apparmor: clearing unsafe personality " 965 - "bits. %s label=", bprm->filename); 974 + dbg_printk("apparmor: clearing unsafe personality bits. %s label=", 975 + bprm->filename); 966 976 aa_label_printk(new, GFP_KERNEL); 967 977 dbg_printk("\n"); 968 978 }
-28
security/apparmor/include/label.h
··· 160 160 #define label_for_each_cont(I, L, P) \ 161 161 for (++((I).i); ((P) = (L)->vec[(I).i]); ++((I).i)) 162 162 163 - #define next_comb(I, L1, L2) \ 164 - do { \ 165 - (I).j++; \ 166 - if ((I).j >= (L2)->size) { \ 167 - (I).i++; \ 168 - (I).j = 0; \ 169 - } \ 170 - } while (0) 171 163 172 - 173 - /* for each combination of P1 in L1, and P2 in L2 */ 174 - #define label_for_each_comb(I, L1, L2, P1, P2) \ 175 - for ((I).i = (I).j = 0; \ 176 - ((P1) = (L1)->vec[(I).i]) && ((P2) = (L2)->vec[(I).j]); \ 177 - (I) = next_comb(I, L1, L2)) 178 - 179 - #define fn_for_each_comb(L1, L2, P1, P2, FN) \ 180 - ({ \ 181 - struct label_it i; \ 182 - int __E = 0; \ 183 - label_for_each_comb(i, (L1), (L2), (P1), (P2)) { \ 184 - last_error(__E, (FN)); \ 185 - } \ 186 - __E; \ 187 - }) 188 164 189 165 /* for each profile that is enforcing confinement in a label */ 190 166 #define label_for_each_confined(I, L, P) \ ··· 267 291 bool aa_label_make_newest(struct aa_labelset *ls, struct aa_label *old, 268 292 struct aa_label *new); 269 293 270 - struct aa_label *aa_label_find(struct aa_label *l); 271 - 272 294 struct aa_profile *aa_label_next_in_merge(struct label_it *I, 273 295 struct aa_label *a, 274 296 struct aa_label *b); ··· 294 320 struct aa_label *label, int flags, gfp_t gfp); 295 321 void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags, 296 322 gfp_t gfp); 297 - void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp); 298 - void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp); 299 323 void aa_label_printk(struct aa_label *label, gfp_t gfp); 300 324 301 325 struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,
-1
security/apparmor/include/lib.h
··· 59 59 60 60 /* fn's in lib */ 61 61 const char *skipn_spaces(const char *str, size_t n); 62 - char *aa_split_fqname(char *args, char **ns_name); 63 62 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 64 63 size_t *ns_len); 65 64 void aa_info_message(const char *str);
+5 -3
security/apparmor/include/match.h
··· 87 87 char td_data[]; 88 88 }; 89 89 90 - #define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data)) 90 + #define TABLE_DATAU16(TABLE) ((u16 *)((TABLE)->td_data)) 91 + #define TABLE_DATAU32(TABLE) ((u32 *)((TABLE)->td_data)) 92 + #define DEFAULT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_DEF]->td_data)) 91 93 #define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data)) 92 - #define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data)) 93 - #define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data)) 94 + #define NEXT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_NXT]->td_data)) 95 + #define CHECK_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_CHK]->td_data)) 94 96 #define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data)) 95 97 #define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data)) 96 98 #define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))
-3
security/apparmor/include/perms.h
··· 213 213 void aa_profile_match_label(struct aa_profile *profile, 214 214 struct aa_ruleset *rules, struct aa_label *label, 215 215 int type, u32 request, struct aa_perms *perms); 216 - int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 217 - u32 request, int type, u32 *deny, 218 - struct apparmor_audit_data *ad); 219 216 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 220 217 u32 request, struct apparmor_audit_data *ad, 221 218 void (*cb)(struct audit_buffer *, void *));
-1
security/apparmor/include/policy.h
··· 264 264 struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); 265 265 struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, 266 266 size_t n); 267 - struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); 268 267 struct aa_profile *aa_fqlookupn_profile(struct aa_label *base, 269 268 const char *fqname, size_t n); 270 269
-1
security/apparmor/include/secid.h
··· 34 34 35 35 int aa_alloc_secid(struct aa_label *label, gfp_t gfp); 36 36 void aa_free_secid(u32 secid); 37 - void aa_secid_update(u32 secid, struct aa_label *label); 38 37 39 38 #endif /* __AA_SECID_H */
-33
security/apparmor/label.c
··· 899 899 return vec_create_and_insert_label(vec, len, gfp); 900 900 } 901 901 902 - /** 903 - * aa_label_find - find label @label in label set 904 - * @label: label to find (NOT NULL) 905 - * 906 - * Requires: caller to hold a valid ref on l 907 - * 908 - * Returns: refcounted @label if @label is in tree 909 - * refcounted label that is equiv to @label in tree 910 - * else NULL if @label or equiv is not in tree 911 - */ 912 - struct aa_label *aa_label_find(struct aa_label *label) 913 - { 914 - AA_BUG(!label); 915 - 916 - return vec_find(label->vec, label->size); 917 - } 918 - 919 902 920 903 /** 921 904 * aa_label_insert - insert label @label into @ls or return existing label ··· 1792 1809 label_modename(ns, label, flags)); 1793 1810 else 1794 1811 pr_info("%s", label->hname); 1795 - } 1796 - 1797 - void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp) 1798 - { 1799 - struct aa_ns *ns = aa_get_current_ns(); 1800 - 1801 - aa_label_xaudit(ab, ns, label, FLAG_VIEW_SUBNS, gfp); 1802 - aa_put_ns(ns); 1803 - } 1804 - 1805 - void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp) 1806 - { 1807 - struct aa_ns *ns = aa_get_current_ns(); 1808 - 1809 - aa_label_seq_xprint(f, ns, label, FLAG_VIEW_SUBNS, gfp); 1810 - aa_put_ns(ns); 1811 1812 } 1812 1813 1813 1814 void aa_label_printk(struct aa_label *label, gfp_t gfp)
-84
security/apparmor/lib.c
··· 46 46 } 47 47 48 48 /** 49 - * aa_split_fqname - split a fqname into a profile and namespace name 50 - * @fqname: a full qualified name in namespace profile format (NOT NULL) 51 - * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) 52 - * 53 - * Returns: profile name or NULL if one is not specified 54 - * 55 - * Split a namespace name from a profile name (see policy.c for naming 56 - * description). If a portion of the name is missing it returns NULL for 57 - * that portion. 58 - * 59 - * NOTE: may modify the @fqname string. The pointers returned point 60 - * into the @fqname string. 61 - */ 62 - char *aa_split_fqname(char *fqname, char **ns_name) 63 - { 64 - char *name = strim(fqname); 65 - 66 - *ns_name = NULL; 67 - if (name[0] == ':') { 68 - char *split = strchr(&name[1], ':'); 69 - *ns_name = skip_spaces(&name[1]); 70 - if (split) { 71 - /* overwrite ':' with \0 */ 72 - *split++ = 0; 73 - if (strncmp(split, "//", 2) == 0) 74 - split += 2; 75 - name = skip_spaces(split); 76 - } else 77 - /* a ns name without a following profile is allowed */ 78 - name = NULL; 79 - } 80 - if (name && *name == 0) 81 - name = NULL; 82 - 83 - return name; 84 - } 85 - 86 - /** 87 49 * skipn_spaces - Removes leading whitespace from @str. 88 50 * @str: The string to be stripped. 89 51 * @n: length of str to parse, will stop at \0 if encountered before n ··· 238 276 } 239 277 240 278 /** 241 - * aa_audit_perms_cb - generic callback fn for auditing perms 242 - * @ab: audit buffer (NOT NULL) 243 - * @va: audit struct to audit values of (NOT NULL) 244 - */ 245 - static void aa_audit_perms_cb(struct audit_buffer *ab, void *va) 246 - { 247 - struct common_audit_data *sa = va; 248 - struct apparmor_audit_data *ad = aad(sa); 249 - 250 - if (ad->request) { 251 - audit_log_format(ab, " requested_mask="); 252 - aa_audit_perm_mask(ab, ad->request, aa_file_perm_chrs, 253 - PERMS_CHRS_MASK, aa_file_perm_names, 254 - PERMS_NAMES_MASK); 255 - } 256 - if (ad->denied) { 257 - audit_log_format(ab, "denied_mask="); 258 - aa_audit_perm_mask(ab, ad->denied, aa_file_perm_chrs, 259 - PERMS_CHRS_MASK, aa_file_perm_names, 260 - PERMS_NAMES_MASK); 261 - } 262 - audit_log_format(ab, " peer="); 263 - aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, 264 - FLAGS_NONE, GFP_ATOMIC); 265 - } 266 - 267 - /** 268 279 * aa_apply_modes_to_perms - apply namespace and profile flags to perms 269 280 * @profile: that perms where computed from 270 281 * @perms: perms to apply mode modifiers to ··· 283 348 aa_label_match(profile, rules, label, state, false, request, perms); 284 349 } 285 350 286 - 287 - /* currently unused */ 288 - int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 289 - u32 request, int type, u32 *deny, 290 - struct apparmor_audit_data *ad) 291 - { 292 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 293 - typeof(*rules), list); 294 - struct aa_perms perms; 295 - 296 - ad->peer = &target->label; 297 - ad->request = request; 298 - 299 - aa_profile_match_label(profile, rules, &target->label, type, request, 300 - &perms); 301 - aa_apply_modes_to_perms(profile, &perms); 302 - *deny |= request & perms.deny; 303 - return aa_check_perms(profile, &perms, request, ad, aa_audit_perms_cb); 304 - } 305 351 306 352 /** 307 353 * aa_check_perms - do audit mode selection based on perms set
+77 -22
security/apparmor/match.c
··· 247 247 dfa_free(dfa); 248 248 } 249 249 250 + 251 + 252 + /** 253 + * remap_data16_to_data32 - remap u16 @old table to a u32 based table 254 + * @old: table to remap 255 + * 256 + * Returns: new table with u32 entries instead of u16. 257 + * 258 + * Note: will free @old so caller does not have to 259 + */ 260 + static struct table_header *remap_data16_to_data32(struct table_header *old) 261 + { 262 + struct table_header *new; 263 + size_t tsize; 264 + u32 i; 265 + 266 + tsize = table_size(old->td_lolen, YYTD_DATA32); 267 + new = kvzalloc(tsize, GFP_KERNEL); 268 + if (!new) { 269 + kvfree(old); 270 + return NULL; 271 + } 272 + new->td_id = old->td_id; 273 + new->td_flags = YYTD_DATA32; 274 + new->td_lolen = old->td_lolen; 275 + 276 + for (i = 0; i < old->td_lolen; i++) 277 + TABLE_DATAU32(new)[i] = (u32) TABLE_DATAU16(old)[i]; 278 + 279 + kvfree(old); 280 + if (is_vmalloc_addr(new)) 281 + vm_unmap_aliases(); 282 + 283 + return new; 284 + } 285 + 250 286 /** 251 287 * aa_dfa_unpack - unpack the binary tables of a serialized dfa 252 288 * @blob: aligned serialized stream of data to unpack (NOT NULL) ··· 362 326 case YYTD_ID_DEF: 363 327 case YYTD_ID_NXT: 364 328 case YYTD_ID_CHK: 365 - if (table->td_flags != YYTD_DATA16) 329 + if (!(table->td_flags == YYTD_DATA16 || 330 + table->td_flags == YYTD_DATA32)) { 366 331 goto fail; 332 + } 367 333 break; 368 334 case YYTD_ID_EC: 369 335 if (table->td_flags != YYTD_DATA8) ··· 380 342 dfa->tables[table->td_id] = table; 381 343 data += table_size(table->td_lolen, table->td_flags); 382 344 size -= table_size(table->td_lolen, table->td_flags); 345 + 346 + /* 347 + * this remapping has to be done after incrementing data above 348 + * for now straight remap, later have dfa support both 349 + */ 350 + switch (table->td_id) { 351 + case YYTD_ID_DEF: 352 + case YYTD_ID_NXT: 353 + case YYTD_ID_CHK: 354 + if (table->td_flags == YYTD_DATA16) { 355 + table = remap_data16_to_data32(table); 356 + if (!table) 357 + goto fail; 358 + } 359 + dfa->tables[table->td_id] = table; 360 + break; 361 + } 383 362 table = NULL; 384 363 } 385 364 error = verify_table_headers(dfa->tables, flags); ··· 450 395 aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start, 451 396 const char *str, int len) 452 397 { 453 - u16 *def = DEFAULT_TABLE(dfa); 398 + u32 *def = DEFAULT_TABLE(dfa); 454 399 u32 *base = BASE_TABLE(dfa); 455 - u16 *next = NEXT_TABLE(dfa); 456 - u16 *check = CHECK_TABLE(dfa); 400 + u32 *next = NEXT_TABLE(dfa); 401 + u32 *check = CHECK_TABLE(dfa); 457 402 aa_state_t state = start; 458 403 459 404 if (state == DFA_NOMATCH) ··· 489 434 */ 490 435 aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str) 491 436 { 492 - u16 *def = DEFAULT_TABLE(dfa); 437 + u32 *def = DEFAULT_TABLE(dfa); 493 438 u32 *base = BASE_TABLE(dfa); 494 - u16 *next = NEXT_TABLE(dfa); 495 - u16 *check = CHECK_TABLE(dfa); 439 + u32 *next = NEXT_TABLE(dfa); 440 + u32 *check = CHECK_TABLE(dfa); 496 441 aa_state_t state = start; 497 442 498 443 if (state == DFA_NOMATCH) ··· 527 472 */ 528 473 aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c) 529 474 { 530 - u16 *def = DEFAULT_TABLE(dfa); 475 + u32 *def = DEFAULT_TABLE(dfa); 531 476 u32 *base = BASE_TABLE(dfa); 532 - u16 *next = NEXT_TABLE(dfa); 533 - u16 *check = CHECK_TABLE(dfa); 477 + u32 *next = NEXT_TABLE(dfa); 478 + u32 *check = CHECK_TABLE(dfa); 534 479 535 480 /* current state is <state>, matching character *str */ 536 481 if (dfa->tables[YYTD_ID_EC]) { ··· 545 490 546 491 aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state) 547 492 { 548 - u16 *def = DEFAULT_TABLE(dfa); 493 + u32 *def = DEFAULT_TABLE(dfa); 549 494 u32 *base = BASE_TABLE(dfa); 550 - u16 *next = NEXT_TABLE(dfa); 551 - u16 *check = CHECK_TABLE(dfa); 495 + u32 *next = NEXT_TABLE(dfa); 496 + u32 *check = CHECK_TABLE(dfa); 552 497 u32 b = (base)[(state)]; 553 498 554 499 if (!(b & MATCH_FLAG_OOB_TRANSITION)) ··· 576 521 aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start, 577 522 const char *str, const char **retpos) 578 523 { 579 - u16 *def = DEFAULT_TABLE(dfa); 524 + u32 *def = DEFAULT_TABLE(dfa); 580 525 u32 *base = BASE_TABLE(dfa); 581 - u16 *next = NEXT_TABLE(dfa); 582 - u16 *check = CHECK_TABLE(dfa); 526 + u32 *next = NEXT_TABLE(dfa); 527 + u32 *check = CHECK_TABLE(dfa); 583 528 u32 *accept = ACCEPT_TABLE(dfa); 584 529 aa_state_t state = start, pos; 585 530 ··· 637 582 aa_state_t aa_dfa_matchn_until(struct aa_dfa *dfa, aa_state_t start, 638 583 const char *str, int n, const char **retpos) 639 584 { 640 - u16 *def = DEFAULT_TABLE(dfa); 585 + u32 *def = DEFAULT_TABLE(dfa); 641 586 u32 *base = BASE_TABLE(dfa); 642 - u16 *next = NEXT_TABLE(dfa); 643 - u16 *check = CHECK_TABLE(dfa); 587 + u32 *next = NEXT_TABLE(dfa); 588 + u32 *check = CHECK_TABLE(dfa); 644 589 u32 *accept = ACCEPT_TABLE(dfa); 645 590 aa_state_t state = start, pos; 646 591 ··· 713 658 const char *str, struct match_workbuf *wb, 714 659 unsigned int *count) 715 660 { 716 - u16 *def = DEFAULT_TABLE(dfa); 661 + u32 *def = DEFAULT_TABLE(dfa); 717 662 u32 *base = BASE_TABLE(dfa); 718 - u16 *next = NEXT_TABLE(dfa); 719 - u16 *check = CHECK_TABLE(dfa); 663 + u32 *next = NEXT_TABLE(dfa); 664 + u32 *check = CHECK_TABLE(dfa); 720 665 aa_state_t state = start, pos; 721 666 722 667 AA_BUG(!dfa);
+1 -1
security/apparmor/path.c
··· 130 130 /* handle error conditions - and still allow a partial path to 131 131 * be returned. 132 132 */ 133 - if (!res || IS_ERR(res)) { 133 + if (IS_ERR_OR_NULL(res)) { 134 134 if (PTR_ERR(res) == -ENAMETOOLONG) { 135 135 error = -ENAMETOOLONG; 136 136 *name = buf;
+2 -7
security/apparmor/policy.c
··· 103 103 { 104 104 if (pdb) { 105 105 aa_put_dfa(pdb->dfa); 106 - if (pdb->perms) 107 - kvfree(pdb->perms); 106 + kvfree(pdb->perms); 108 107 aa_free_str_table(&pdb->trans); 109 108 kfree(pdb); 110 109 } ··· 579 580 return profile; 580 581 } 581 582 582 - struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) 583 - { 584 - return aa_lookupn_profile(ns, hname, strlen(hname)); 585 - } 586 - 587 583 struct aa_profile *aa_fqlookupn_profile(struct aa_label *base, 588 584 const char *fqname, size_t n) 589 585 { ··· 620 626 621 627 /* TODO: ideally we should inherit abi from parent */ 622 628 profile->label.flags |= FLAG_NULL; 629 + profile->attach.xmatch = aa_get_pdb(nullpdb); 623 630 rules = list_first_entry(&profile->rules, typeof(*rules), list); 624 631 rules->file = aa_get_pdb(nullpdb); 625 632 rules->policy = aa_get_pdb(nullpdb);
+4 -1
security/apparmor/policy_unpack.c
··· 645 645 646 646 static bool unpack_perm(struct aa_ext *e, u32 version, struct aa_perms *perm) 647 647 { 648 + u32 reserved; 649 + 648 650 if (version != 1) 649 651 return false; 650 652 651 - return aa_unpack_u32(e, &perm->allow, NULL) && 653 + /* reserved entry is for later expansion, discard for now */ 654 + return aa_unpack_u32(e, &reserved, NULL) && 652 655 aa_unpack_u32(e, &perm->allow, NULL) && 653 656 aa_unpack_u32(e, &perm->deny, NULL) && 654 657 aa_unpack_u32(e, &perm->subtree, NULL) &&
+6
security/apparmor/policy_unpack_test.c
··· 281 281 ((uintptr_t)puf->e->start <= (uintptr_t)string) 282 282 && ((uintptr_t)string <= (uintptr_t)puf->e->end)); 283 283 KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); 284 + 285 + kfree(string); 284 286 } 285 287 286 288 static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test) ··· 298 296 ((uintptr_t)puf->e->start <= (uintptr_t)string) 299 297 && ((uintptr_t)string <= (uintptr_t)puf->e->end)); 300 298 KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); 299 + 300 + kfree(string); 301 301 } 302 302 303 303 static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test) ··· 317 313 KUNIT_EXPECT_EQ(test, size, 0); 318 314 KUNIT_EXPECT_NULL(test, string); 319 315 KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start); 316 + 317 + kfree(string); 320 318 } 321 319 322 320 static void policy_unpack_test_unpack_nameX_with_null_name(struct kunit *test)
-14
security/apparmor/secid.c
··· 39 39 * TODO: use secid_update in label replace 40 40 */ 41 41 42 - /** 43 - * aa_secid_update - update a secid mapping to a new label 44 - * @secid: secid to update 45 - * @label: label the secid will now map to 46 - */ 47 - void aa_secid_update(u32 secid, struct aa_label *label) 48 - { 49 - unsigned long flags; 50 - 51 - xa_lock_irqsave(&aa_secids, flags); 52 - __xa_store(&aa_secids, secid, label, 0); 53 - xa_unlock_irqrestore(&aa_secids, flags); 54 - } 55 - 56 42 /* 57 43 * see label for inverse aa_label_to_secid 58 44 */