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

apparmor: refcount the pdb

With the move to permission tables the dfa is no longer a stand
alone entity when used, needing a minimum of a permission table.
However it still could be shared among different pdbs each using
a different permission table.

Instead of duping the permission table when sharing a pdb, add a
refcount to the pdb so it can be easily shared.

Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>

+261 -211
+9 -9
security/apparmor/apparmorfs.c
··· 619 619 620 620 if (profile_unconfined(profile)) 621 621 return; 622 - if (rules->file.dfa && *match_str == AA_CLASS_FILE) { 623 - state = aa_dfa_match_len(rules->file.dfa, 624 - rules->file.start[AA_CLASS_FILE], 622 + if (rules->file->dfa && *match_str == AA_CLASS_FILE) { 623 + state = aa_dfa_match_len(rules->file->dfa, 624 + rules->file->start[AA_CLASS_FILE], 625 625 match_str + 1, match_len - 1); 626 626 if (state) { 627 627 struct path_cond cond = { }; 628 628 629 - tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 629 + tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 630 630 } 631 - } else if (rules->policy.dfa) { 631 + } else if (rules->policy->dfa) { 632 632 if (!RULE_MEDIATES(rules, *match_str)) 633 633 return; /* no change to current perms */ 634 - state = aa_dfa_match_len(rules->policy.dfa, 635 - rules->policy.start[0], 634 + state = aa_dfa_match_len(rules->policy->dfa, 635 + rules->policy->start[0], 636 636 match_str, match_len); 637 637 if (state) 638 - tmp = *aa_lookup_perms(&rules->policy, state); 638 + tmp = *aa_lookup_perms(rules->policy, state); 639 639 } 640 640 aa_apply_modes_to_perms(profile, &tmp); 641 641 aa_perms_accum_raw(perms, &tmp); ··· 1096 1096 struct aa_profile *profile = labels_profile(label); 1097 1097 if (profile->attach.xmatch_str) 1098 1098 seq_printf(seq, "%s\n", profile->attach.xmatch_str); 1099 - else if (profile->attach.xmatch.dfa) 1099 + else if (profile->attach.xmatch->dfa) 1100 1100 seq_puts(seq, "<unknown>\n"); 1101 1101 else 1102 1102 seq_printf(seq, "%s\n", profile->base.name);
+30 -30
security/apparmor/domain.c
··· 77 77 /**** TODO: dedup to aa_label_match - needs perm and dfa, merging 78 78 * specifically this is an exact copy of aa_label_match except 79 79 * aa_compute_perms is replaced with aa_compute_fperms 80 - * and policy.dfa with file.dfa 80 + * and policy->dfa with file->dfa 81 81 ****/ 82 82 /* match a profile and its associated ns component if needed 83 83 * Assumes visibility test has already been done. ··· 93 93 const char *ns_name; 94 94 95 95 if (stack) 96 - state = aa_dfa_match(rules->file.dfa, state, "&"); 96 + state = aa_dfa_match(rules->file->dfa, state, "&"); 97 97 if (profile->ns == tp->ns) 98 - return aa_dfa_match(rules->file.dfa, state, tp->base.hname); 98 + return aa_dfa_match(rules->file->dfa, state, tp->base.hname); 99 99 100 100 /* try matching with namespace name and then profile */ 101 101 ns_name = aa_ns_name(profile->ns, tp->ns, true); 102 - state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); 103 - state = aa_dfa_match(rules->file.dfa, state, ns_name); 104 - state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); 105 - return aa_dfa_match(rules->file.dfa, state, tp->base.hname); 102 + state = aa_dfa_match_len(rules->file->dfa, state, ":", 1); 103 + state = aa_dfa_match(rules->file->dfa, state, ns_name); 104 + state = aa_dfa_match_len(rules->file->dfa, state, ":", 1); 105 + return aa_dfa_match(rules->file->dfa, state, tp->base.hname); 106 106 } 107 107 108 108 /** ··· 150 150 label_for_each_cont(i, label, tp) { 151 151 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 152 152 continue; 153 - state = aa_dfa_match(rules->file.dfa, state, "//&"); 153 + state = aa_dfa_match(rules->file->dfa, state, "//&"); 154 154 state = match_component(profile, tp, false, state); 155 155 if (!state) 156 156 goto fail; 157 157 } 158 - *perms = *(aa_lookup_fperms(&(rules->file), state, &cond)); 158 + *perms = *(aa_lookup_fperms(rules->file, state, &cond)); 159 159 aa_apply_modes_to_perms(profile, perms); 160 160 if ((perms->allow & request) != request) 161 161 return -EACCES; ··· 210 210 return 0; 211 211 212 212 next: 213 - tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 213 + tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 214 214 aa_apply_modes_to_perms(profile, &tmp); 215 215 aa_perms_accum(perms, &tmp); 216 216 label_for_each_cont(i, label, tp) { ··· 219 219 state = match_component(profile, tp, stack, start); 220 220 if (!state) 221 221 goto fail; 222 - tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); 222 + tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 223 223 aa_apply_modes_to_perms(profile, &tmp); 224 224 aa_perms_accum(perms, &tmp); 225 225 } ··· 317 317 might_sleep(); 318 318 319 319 /* transition from exec match to xattr set */ 320 - state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); 320 + state = aa_dfa_outofband_transition(attach->xmatch->dfa, state); 321 321 d = bprm->file->f_path.dentry; 322 322 323 323 for (i = 0; i < attach->xattr_count; i++) { ··· 331 331 * that not present xattr can be distinguished from a 0 332 332 * length value or rule that matches any value 333 333 */ 334 - state = aa_dfa_null_transition(attach->xmatch.dfa, 334 + state = aa_dfa_null_transition(attach->xmatch->dfa, 335 335 state); 336 336 /* Check xattr value */ 337 - state = aa_dfa_match_len(attach->xmatch.dfa, state, 337 + state = aa_dfa_match_len(attach->xmatch->dfa, state, 338 338 value, size); 339 - index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; 340 - perm = attach->xmatch.perms[index].allow; 339 + index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; 340 + perm = attach->xmatch->perms[index].allow; 341 341 if (!(perm & MAY_EXEC)) { 342 342 ret = -EINVAL; 343 343 goto out; 344 344 } 345 345 } 346 346 /* transition to next element */ 347 - state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); 347 + state = aa_dfa_outofband_transition(attach->xmatch->dfa, state); 348 348 if (size < 0) { 349 349 /* 350 350 * No xattr match, so verify if transition to ··· 413 413 * as another profile, signal a conflict and refuse to 414 414 * match. 415 415 */ 416 - if (attach->xmatch.dfa) { 416 + if (attach->xmatch->dfa) { 417 417 unsigned int count; 418 418 aa_state_t state; 419 419 u32 index, perm; 420 420 421 - state = aa_dfa_leftmatch(attach->xmatch.dfa, 422 - attach->xmatch.start[AA_CLASS_XMATCH], 421 + state = aa_dfa_leftmatch(attach->xmatch->dfa, 422 + attach->xmatch->start[AA_CLASS_XMATCH], 423 423 name, &count); 424 - index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; 425 - perm = attach->xmatch.perms[index].allow; 424 + index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; 425 + perm = attach->xmatch->perms[index].allow; 426 426 /* any accepting state means a valid match. */ 427 427 if (perm & MAY_EXEC) { 428 428 int ret = 0; ··· 525 525 /* TODO: move lookup parsing to unpack time so this is a straight 526 526 * index into the resultant label 527 527 */ 528 - for (*name = rules->file.trans.table[index]; !label && *name; 528 + for (*name = rules->file->trans.table[index]; !label && *name; 529 529 *name = next_name(xtype, *name)) { 530 530 if (xindex & AA_X_CHILD) { 531 531 struct aa_profile *new_profile; ··· 579 579 break; 580 580 case AA_X_TABLE: 581 581 /* TODO: fix when perm mapping done at unload */ 582 - stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK]; 582 + stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK]; 583 583 if (*stack != '&') { 584 584 /* released by caller */ 585 585 new = x_table_lookup(profile, xindex, lookupname); ··· 638 638 typeof(*rules), list); 639 639 struct aa_label *new = NULL; 640 640 const char *info = NULL, *name = NULL, *target = NULL; 641 - aa_state_t state = rules->file.start[AA_CLASS_FILE]; 641 + aa_state_t state = rules->file->start[AA_CLASS_FILE]; 642 642 struct aa_perms perms = {}; 643 643 bool nonewprivs = false; 644 644 int error = 0; ··· 672 672 } 673 673 674 674 /* find exec permissions for name */ 675 - state = aa_str_perms(&(rules->file), state, name, cond, &perms); 675 + state = aa_str_perms(rules->file, state, name, cond, &perms); 676 676 if (perms.allow & MAY_EXEC) { 677 677 /* exec permission determine how to transition */ 678 678 new = x_to_label(profile, bprm, name, perms.xindex, &target, ··· 738 738 { 739 739 struct aa_ruleset *rules = list_first_entry(&profile->rules, 740 740 typeof(*rules), list); 741 - aa_state_t state = rules->file.start[AA_CLASS_FILE]; 741 + aa_state_t state = rules->file->start[AA_CLASS_FILE]; 742 742 struct aa_perms perms = {}; 743 743 const char *xname = NULL, *info = "change_profile onexec"; 744 744 int error = -EACCES; ··· 771 771 } 772 772 773 773 /* find exec permissions for name */ 774 - state = aa_str_perms(&(rules->file), state, xname, cond, &perms); 774 + state = aa_str_perms(rules->file, state, xname, cond, &perms); 775 775 if (!(perms.allow & AA_MAY_ONEXEC)) { 776 776 info = "no change_onexec valid for executable"; 777 777 goto audit; ··· 780 780 * onexec permission is linked to exec with a standard pairing 781 781 * exec\0change_profile 782 782 */ 783 - state = aa_dfa_null_transition(rules->file.dfa, state); 783 + state = aa_dfa_null_transition(rules->file->dfa, state); 784 784 error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC, 785 785 state, &perms); 786 786 if (error) { ··· 1300 1300 1301 1301 if (!error) 1302 1302 error = change_profile_perms(profile, target, stack, request, 1303 - rules->file.start[AA_CLASS_FILE], 1303 + rules->file->start[AA_CLASS_FILE], 1304 1304 perms); 1305 1305 if (error) 1306 1306 error = aa_audit_file(subj_cred, profile, perms, op, request,
+6 -6
security/apparmor/file.c
··· 236 236 237 237 if (profile_unconfined(profile)) 238 238 return 0; 239 - aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], 239 + aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE], 240 240 name, cond, perms); 241 241 if (request & ~perms->allow) 242 242 e = -EACCES; ··· 353 353 354 354 error = -EACCES; 355 355 /* aa_str_perms - handles the case of the dfa being NULL */ 356 - state = aa_str_perms(&(rules->file), 357 - rules->file.start[AA_CLASS_FILE], lname, 356 + state = aa_str_perms(rules->file, 357 + rules->file->start[AA_CLASS_FILE], lname, 358 358 cond, &lperms); 359 359 360 360 if (!(lperms.allow & AA_MAY_LINK)) 361 361 goto audit; 362 362 363 363 /* test to see if target can be paired with link */ 364 - state = aa_dfa_null_transition(rules->file.dfa, state); 365 - aa_str_perms(&(rules->file), state, tname, cond, &perms); 364 + state = aa_dfa_null_transition(rules->file->dfa, state); 365 + aa_str_perms(rules->file, state, tname, cond, &perms); 366 366 367 367 /* force audit/quiet masks for link are stored in the second entry 368 368 * in the link pair. ··· 384 384 /* Do link perm subset test requiring allowed permission on link are 385 385 * a subset of the allowed permissions on target. 386 386 */ 387 - aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], 387 + aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE], 388 388 tname, cond, &perms); 389 389 390 390 /* AA_MAY_LINK is not considered in the subset test */
+2
security/apparmor/include/lib.h
··· 16 16 17 17 #include "match.h" 18 18 19 + extern struct aa_dfa *stacksplitdfa; 20 + 19 21 /* 20 22 * DEBUG remains global (no per profile flag) since it is mostly used in sysctl 21 23 * which is not related to profile accesses.
-6
security/apparmor/include/match.h
··· 102 102 struct table_header *tables[YYTD_ID_TSIZE]; 103 103 }; 104 104 105 - extern struct aa_dfa *nulldfa; 106 - extern struct aa_dfa *stacksplitdfa; 107 - 108 105 #define byte_to_byte(X) (X) 109 106 110 107 #define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX) \ ··· 118 121 { 119 122 return ALIGN(sizeof(struct table_header) + len * el_size, 8); 120 123 } 121 - 122 - int aa_setup_dfa_engine(void); 123 - void aa_teardown_dfa_engine(void); 124 124 125 125 #define aa_state_t unsigned int 126 126
+38 -13
security/apparmor/include/policy.h
··· 74 74 75 75 76 76 /* struct aa_policydb - match engine for a policy 77 + * count: refcount for the pdb 77 78 * dfa: dfa pattern match 78 79 * perms: table of permissions 79 80 * strs: table of strings, index by x 80 81 * start: set of start states for the different classes of data 81 82 */ 82 83 struct aa_policydb { 84 + struct kref count; 83 85 struct aa_dfa *dfa; 84 86 struct { 85 87 struct aa_perms *perms; ··· 91 89 aa_state_t start[AA_CLASS_LAST + 1]; 92 90 }; 93 91 94 - static inline void aa_destroy_policydb(struct aa_policydb *policy) 95 - { 96 - aa_put_dfa(policy->dfa); 97 - if (policy->perms) 98 - kvfree(policy->perms); 99 - aa_free_str_table(&policy->trans); 92 + extern struct aa_policydb *nullpdb; 100 93 94 + struct aa_policydb *aa_alloc_pdb(gfp_t gfp); 95 + void aa_pdb_free_kref(struct kref *kref); 96 + 97 + /** 98 + * aa_get_pdb - increment refcount on @pdb 99 + * @pdb: policydb (MAYBE NULL) 100 + * 101 + * Returns: pointer to @pdb if @pdb is NULL will return NULL 102 + * Requires: @pdb must be held with valid refcount when called 103 + */ 104 + static inline struct aa_policydb *aa_get_pdb(struct aa_policydb *pdb) 105 + { 106 + if (pdb) 107 + kref_get(&(pdb->count)); 108 + 109 + return pdb; 110 + } 111 + 112 + /** 113 + * aa_put_pdb - put a pdb refcount 114 + * @pdb: pdb to put refcount (MAYBE NULL) 115 + * 116 + * Requires: if @pdb != NULL that a valid refcount be held 117 + */ 118 + static inline void aa_put_pdb(struct aa_policydb *pdb) 119 + { 120 + if (pdb) 121 + kref_put(&pdb->count, aa_pdb_free_kref); 101 122 } 102 123 103 124 static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy, ··· 164 139 int size; 165 140 166 141 /* TODO: merge policy and file */ 167 - struct aa_policydb policy; 168 - struct aa_policydb file; 142 + struct aa_policydb *policy; 143 + struct aa_policydb *file; 169 144 struct aa_caps caps; 170 145 171 146 struct aa_rlimit rlimits; ··· 184 159 */ 185 160 struct aa_attachment { 186 161 const char *xmatch_str; 187 - struct aa_policydb xmatch; 162 + struct aa_policydb *xmatch; 188 163 unsigned int xmatch_len; 189 164 int xattr_count; 190 165 char **xattrs; ··· 292 267 unsigned char class) 293 268 { 294 269 if (class <= AA_CLASS_LAST) 295 - return rules->policy.start[class]; 270 + return rules->policy->start[class]; 296 271 else 297 - return aa_dfa_match_len(rules->policy.dfa, 298 - rules->policy.start[0], &class, 1); 272 + return aa_dfa_match_len(rules->policy->dfa, 273 + rules->policy->start[0], &class, 1); 299 274 } 300 275 301 276 static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) ··· 305 280 306 281 if (!state) 307 282 return DFA_NOMATCH; 308 - return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2); 283 + return aa_dfa_match_len(rules->policy->dfa, state, (char *) &be_af, 2); 309 284 } 310 285 311 286 static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
+2 -2
security/apparmor/ipc.c
··· 92 92 ad->subj_cred = cred; 93 93 ad->peer = peer; 94 94 /* TODO: secondary cache check <profile, profile, perm> */ 95 - state = aa_dfa_next(rules->policy.dfa, 96 - rules->policy.start[AA_CLASS_SIGNAL], 95 + state = aa_dfa_next(rules->policy->dfa, 96 + rules->policy->start[AA_CLASS_SIGNAL], 97 97 ad->signal); 98 98 aa_label_match(profile, rules, peer, state, false, request, &perms); 99 99 aa_apply_modes_to_perms(profile, &perms);
+9 -9
security/apparmor/label.c
··· 1270 1270 const char *ns_name; 1271 1271 1272 1272 if (profile->ns == tp->ns) 1273 - return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); 1273 + return aa_dfa_match(rules->policy->dfa, state, tp->base.hname); 1274 1274 1275 1275 /* try matching with namespace name and then profile */ 1276 1276 ns_name = aa_ns_name(profile->ns, tp->ns, true); 1277 - state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); 1278 - state = aa_dfa_match(rules->policy.dfa, state, ns_name); 1279 - state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); 1280 - return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); 1277 + state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1); 1278 + state = aa_dfa_match(rules->policy->dfa, state, ns_name); 1279 + state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1); 1280 + return aa_dfa_match(rules->policy->dfa, state, tp->base.hname); 1281 1281 } 1282 1282 1283 1283 /** ··· 1323 1323 label_for_each_cont(i, label, tp) { 1324 1324 if (!aa_ns_visible(profile->ns, tp->ns, subns)) 1325 1325 continue; 1326 - state = aa_dfa_match(rules->policy.dfa, state, "//&"); 1326 + state = aa_dfa_match(rules->policy->dfa, state, "//&"); 1327 1327 state = match_component(profile, rules, tp, state); 1328 1328 if (!state) 1329 1329 goto fail; 1330 1330 } 1331 - *perms = *aa_lookup_perms(&rules->policy, state); 1331 + *perms = *aa_lookup_perms(rules->policy, state); 1332 1332 aa_apply_modes_to_perms(profile, perms); 1333 1333 if ((perms->allow & request) != request) 1334 1334 return -EACCES; ··· 1381 1381 return 0; 1382 1382 1383 1383 next: 1384 - tmp = *aa_lookup_perms(&rules->policy, state); 1384 + tmp = *aa_lookup_perms(rules->policy, state); 1385 1385 aa_apply_modes_to_perms(profile, &tmp); 1386 1386 aa_perms_accum(perms, &tmp); 1387 1387 label_for_each_cont(i, label, tp) { ··· 1390 1390 state = match_component(profile, rules, tp, start); 1391 1391 if (!state) 1392 1392 goto fail; 1393 - tmp = *aa_lookup_perms(&rules->policy, state); 1393 + tmp = *aa_lookup_perms(rules->policy, state); 1394 1394 aa_apply_modes_to_perms(profile, &tmp); 1395 1395 aa_perms_accum(perms, &tmp); 1396 1396 }
+2 -2
security/apparmor/lib.c
··· 341 341 /* TODO: doesn't yet handle extended types */ 342 342 aa_state_t state; 343 343 344 - state = aa_dfa_next(rules->policy.dfa, 345 - rules->policy.start[AA_CLASS_LABEL], 344 + state = aa_dfa_next(rules->policy->dfa, 345 + rules->policy->start[AA_CLASS_LABEL], 346 346 type); 347 347 aa_label_match(profile, rules, label, state, false, request, perms); 348 348 }
+63
security/apparmor/lsm.c
··· 1887 1887 __initcall(apparmor_nf_ip_init); 1888 1888 #endif 1889 1889 1890 + static char nulldfa_src[] = { 1891 + #include "nulldfa.in" 1892 + }; 1893 + struct aa_dfa *nulldfa; 1894 + 1895 + static char stacksplitdfa_src[] = { 1896 + #include "stacksplitdfa.in" 1897 + }; 1898 + struct aa_dfa *stacksplitdfa; 1899 + struct aa_policydb *nullpdb; 1900 + 1901 + static int __init aa_setup_dfa_engine(void) 1902 + { 1903 + int error = -ENOMEM; 1904 + 1905 + nullpdb = aa_alloc_pdb(GFP_KERNEL); 1906 + if (!nullpdb) 1907 + return -ENOMEM; 1908 + 1909 + nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), 1910 + TO_ACCEPT1_FLAG(YYTD_DATA32) | 1911 + TO_ACCEPT2_FLAG(YYTD_DATA32)); 1912 + if (IS_ERR(nulldfa)) { 1913 + error = PTR_ERR(nulldfa); 1914 + goto fail; 1915 + } 1916 + nullpdb->dfa = aa_get_dfa(nulldfa); 1917 + nullpdb->perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL); 1918 + if (!nullpdb->perms) 1919 + goto fail; 1920 + nullpdb->size = 2; 1921 + 1922 + stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src, 1923 + sizeof(stacksplitdfa_src), 1924 + TO_ACCEPT1_FLAG(YYTD_DATA32) | 1925 + TO_ACCEPT2_FLAG(YYTD_DATA32)); 1926 + if (IS_ERR(stacksplitdfa)) { 1927 + error = PTR_ERR(stacksplitdfa); 1928 + goto fail; 1929 + } 1930 + 1931 + return 0; 1932 + 1933 + fail: 1934 + aa_put_pdb(nullpdb); 1935 + aa_put_dfa(nulldfa); 1936 + nullpdb = NULL; 1937 + nulldfa = NULL; 1938 + stacksplitdfa = NULL; 1939 + 1940 + return error; 1941 + } 1942 + 1943 + static void __init aa_teardown_dfa_engine(void) 1944 + { 1945 + aa_put_dfa(stacksplitdfa); 1946 + aa_put_dfa(nulldfa); 1947 + aa_put_pdb(nullpdb); 1948 + nullpdb = NULL; 1949 + stacksplitdfa = NULL; 1950 + nulldfa = NULL; 1951 + } 1952 + 1890 1953 static int __init apparmor_init(void) 1891 1954 { 1892 1955 int error;
-44
security/apparmor/match.c
··· 21 21 22 22 #define base_idx(X) ((X) & 0xffffff) 23 23 24 - static char nulldfa_src[] = { 25 - #include "nulldfa.in" 26 - }; 27 - struct aa_dfa *nulldfa; 28 - 29 - static char stacksplitdfa_src[] = { 30 - #include "stacksplitdfa.in" 31 - }; 32 - struct aa_dfa *stacksplitdfa; 33 - 34 - int __init aa_setup_dfa_engine(void) 35 - { 36 - int error; 37 - 38 - nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src), 39 - TO_ACCEPT1_FLAG(YYTD_DATA32) | 40 - TO_ACCEPT2_FLAG(YYTD_DATA32)); 41 - if (IS_ERR(nulldfa)) { 42 - error = PTR_ERR(nulldfa); 43 - nulldfa = NULL; 44 - return error; 45 - } 46 - 47 - stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src, 48 - sizeof(stacksplitdfa_src), 49 - TO_ACCEPT1_FLAG(YYTD_DATA32) | 50 - TO_ACCEPT2_FLAG(YYTD_DATA32)); 51 - if (IS_ERR(stacksplitdfa)) { 52 - aa_put_dfa(nulldfa); 53 - nulldfa = NULL; 54 - error = PTR_ERR(stacksplitdfa); 55 - stacksplitdfa = NULL; 56 - return error; 57 - } 58 - 59 - return 0; 60 - } 61 - 62 - void __init aa_teardown_dfa_engine(void) 63 - { 64 - aa_put_dfa(stacksplitdfa); 65 - aa_put_dfa(nulldfa); 66 - } 67 - 68 24 /** 69 25 * unpack_table - unpack a dfa table (one of accept, default, base, next check) 70 26 * @blob: data to unpack (NOT NULL)
+10 -10
security/apparmor/mount.c
··· 332 332 } 333 333 334 334 error = -EACCES; 335 - pos = do_match_mnt(&rules->policy, 336 - rules->policy.start[AA_CLASS_MOUNT], 335 + pos = do_match_mnt(rules->policy, 336 + rules->policy->start[AA_CLASS_MOUNT], 337 337 mntpnt, devname, type, flags, data, binary, &perms); 338 338 if (pos) { 339 339 info = mnt_info_table[pos]; ··· 606 606 if (error) 607 607 goto audit; 608 608 609 - state = aa_dfa_match(rules->policy.dfa, 610 - rules->policy.start[AA_CLASS_MOUNT], 609 + state = aa_dfa_match(rules->policy->dfa, 610 + rules->policy->start[AA_CLASS_MOUNT], 611 611 name); 612 - perms = *aa_lookup_perms(&rules->policy, state); 612 + perms = *aa_lookup_perms(rules->policy, state); 613 613 if (AA_MAY_UMOUNT & ~perms.allow) 614 614 error = -EACCES; 615 615 ··· 680 680 goto audit; 681 681 682 682 error = -EACCES; 683 - state = aa_dfa_match(rules->policy.dfa, 684 - rules->policy.start[AA_CLASS_MOUNT], 683 + state = aa_dfa_match(rules->policy->dfa, 684 + rules->policy->start[AA_CLASS_MOUNT], 685 685 new_name); 686 - state = aa_dfa_null_transition(rules->policy.dfa, state); 687 - state = aa_dfa_match(rules->policy.dfa, state, old_name); 688 - perms = *aa_lookup_perms(&rules->policy, state); 686 + state = aa_dfa_null_transition(rules->policy->dfa, state); 687 + state = aa_dfa_match(rules->policy->dfa, state, old_name); 688 + perms = *aa_lookup_perms(rules->policy, state); 689 689 690 690 if (AA_MAY_PIVOTROOT & perms.allow) 691 691 error = 0;
+2 -2
security/apparmor/net.c
··· 127 127 128 128 buffer[0] = cpu_to_be16(family); 129 129 buffer[1] = cpu_to_be16((u16) type); 130 - state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer, 130 + state = aa_dfa_match_len(rules->policy->dfa, state, (char *) &buffer, 131 131 4); 132 - perms = *aa_lookup_perms(&rules->policy, state); 132 + perms = *aa_lookup_perms(rules->policy, state); 133 133 aa_apply_modes_to_perms(profile, &perms); 134 134 135 135 return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
+40 -18
security/apparmor/policy.c
··· 98 98 }; 99 99 100 100 101 + static void aa_free_pdb(struct aa_policydb *policy) 102 + { 103 + if (policy) { 104 + aa_put_dfa(policy->dfa); 105 + if (policy->perms) 106 + kvfree(policy->perms); 107 + aa_free_str_table(&policy->trans); 108 + } 109 + } 110 + 111 + /** 112 + * aa_pdb_free_kref - free aa_policydb by kref (called by aa_put_pdb) 113 + * @kr: kref callback for freeing of a dfa (NOT NULL) 114 + */ 115 + void aa_pdb_free_kref(struct kref *kref) 116 + { 117 + struct aa_policydb *pdb = container_of(kref, struct aa_policydb, count); 118 + 119 + aa_free_pdb(pdb); 120 + } 121 + 122 + 123 + struct aa_policydb *aa_alloc_pdb(gfp_t gfp) 124 + { 125 + struct aa_policydb *pdb = kzalloc(sizeof(struct aa_policydb), gfp); 126 + 127 + if (!pdb) 128 + return NULL; 129 + 130 + kref_init(&pdb->count); 131 + 132 + return pdb; 133 + } 134 + 135 + 101 136 /** 102 137 * __add_profile - add a profiles to list and label tree 103 138 * @list: list to add it to (NOT NULL) ··· 235 200 for (i = 0; i < attach->xattr_count; i++) 236 201 kfree_sensitive(attach->xattrs[i]); 237 202 kfree_sensitive(attach->xattrs); 238 - aa_destroy_policydb(&attach->xmatch); 203 + aa_put_pdb(attach->xmatch); 239 204 } 240 205 241 206 static void free_ruleset(struct aa_ruleset *rules) 242 207 { 243 208 int i; 244 209 245 - aa_destroy_policydb(&rules->file); 246 - aa_destroy_policydb(&rules->policy); 210 + aa_put_pdb(rules->file); 211 + aa_put_pdb(rules->policy); 247 212 aa_free_cap_rules(&rules->caps); 248 213 aa_free_rlimit_rules(&rules->rlimits); 249 214 ··· 625 590 /* TODO: ideally we should inherit abi from parent */ 626 591 profile->label.flags |= FLAG_NULL; 627 592 rules = list_first_entry(&profile->rules, typeof(*rules), list); 628 - rules->file.dfa = aa_get_dfa(nulldfa); 629 - rules->file.perms = kcalloc(2, sizeof(struct aa_perms), gfp); 630 - if (!rules->file.perms) 631 - goto fail; 632 - rules->file.size = 2; 633 - rules->policy.dfa = aa_get_dfa(nulldfa); 634 - rules->policy.perms = kcalloc(2, sizeof(struct aa_perms), gfp); 635 - if (!rules->policy.perms) 636 - goto fail; 637 - rules->policy.size = 2; 593 + rules->file = aa_get_pdb(nullpdb); 594 + rules->policy = aa_get_pdb(nullpdb); 638 595 639 596 if (parent) { 640 597 profile->path_flags = parent->path_flags; ··· 637 610 } 638 611 639 612 return profile; 640 - 641 - fail: 642 - aa_free_profile(profile); 643 - 644 - return NULL; 645 613 } 646 614 647 615 /**
+48 -60
security/apparmor/policy_unpack.c
··· 703 703 return -EPROTO; 704 704 } 705 705 706 - static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy, 706 + static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy, 707 707 bool required_dfa, bool required_trans, 708 708 const char **info) 709 709 { 710 + struct aa_policydb *pdb; 710 711 void *pos = e->pos; 711 712 int i, flags, error = -EPROTO; 712 713 ssize_t size; 713 714 714 - size = unpack_perms_table(e, &policy->perms); 715 + pdb = aa_alloc_pdb(GFP_KERNEL); 716 + if (!pdb) 717 + return -ENOMEM; 718 + 719 + size = unpack_perms_table(e, &pdb->perms); 715 720 if (size < 0) { 716 721 error = size; 717 - policy->perms = NULL; 722 + pdb->perms = NULL; 718 723 *info = "failed to unpack - perms"; 719 724 goto fail; 720 725 } 721 - policy->size = size; 726 + pdb->size = size; 722 727 723 - if (policy->perms) { 728 + if (pdb->perms) { 724 729 /* perms table present accept is index */ 725 730 flags = TO_ACCEPT1_FLAG(YYTD_DATA32); 726 731 } else { ··· 734 729 TO_ACCEPT2_FLAG(YYTD_DATA32); 735 730 } 736 731 737 - policy->dfa = unpack_dfa(e, flags); 738 - if (IS_ERR(policy->dfa)) { 739 - error = PTR_ERR(policy->dfa); 740 - policy->dfa = NULL; 732 + pdb->dfa = unpack_dfa(e, flags); 733 + if (IS_ERR(pdb->dfa)) { 734 + error = PTR_ERR(pdb->dfa); 735 + pdb->dfa = NULL; 741 736 *info = "failed to unpack - dfa"; 742 737 goto fail; 743 - } else if (!policy->dfa) { 738 + } else if (!pdb->dfa) { 744 739 if (required_dfa) { 745 740 *info = "missing required dfa"; 746 741 goto fail; ··· 754 749 * sadly start was given different names for file and policydb 755 750 * but since it is optional we can try both 756 751 */ 757 - if (!aa_unpack_u32(e, &policy->start[0], "start")) 752 + if (!aa_unpack_u32(e, &pdb->start[0], "start")) 758 753 /* default start state */ 759 - policy->start[0] = DFA_START; 760 - if (!aa_unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) { 754 + pdb->start[0] = DFA_START; 755 + if (!aa_unpack_u32(e, &pdb->start[AA_CLASS_FILE], "dfa_start")) { 761 756 /* default start state for xmatch and file dfa */ 762 - policy->start[AA_CLASS_FILE] = DFA_START; 757 + pdb->start[AA_CLASS_FILE] = DFA_START; 763 758 } /* setup class index */ 764 759 for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) { 765 - policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0], 760 + pdb->start[i] = aa_dfa_next(pdb->dfa, pdb->start[0], 766 761 i); 767 762 } 768 - if (!unpack_trans_table(e, &policy->trans) && required_trans) { 763 + if (!unpack_trans_table(e, &pdb->trans) && required_trans) { 769 764 *info = "failed to unpack profile transition table"; 770 765 goto fail; 771 766 } ··· 773 768 /* TODO: move compat mapping here, requires dfa merging first */ 774 769 /* TODO: move verify here, it has to be done after compat mappings */ 775 770 out: 771 + *policy = pdb; 776 772 return 0; 777 773 778 774 fail: 775 + aa_put_pdb(pdb); 779 776 e->pos = pos; 780 777 return error; 781 778 } ··· 861 854 } 862 855 863 856 /* neither xmatch_len not xmatch_perms are optional if xmatch is set */ 864 - if (profile->attach.xmatch.dfa) { 857 + if (profile->attach.xmatch->dfa) { 865 858 if (!aa_unpack_u32(e, &tmp, NULL)) { 866 859 info = "missing xmatch len"; 867 860 goto fail; 868 861 } 869 862 profile->attach.xmatch_len = tmp; 870 - profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START; 871 - if (!profile->attach.xmatch.perms) { 872 - error = aa_compat_map_xmatch(&profile->attach.xmatch); 863 + profile->attach.xmatch->start[AA_CLASS_XMATCH] = DFA_START; 864 + if (!profile->attach.xmatch->perms) { 865 + error = aa_compat_map_xmatch(profile->attach.xmatch); 873 866 if (error) { 874 867 info = "failed to convert xmatch permission table"; 875 868 goto fail; ··· 986 979 if (error) 987 980 goto fail; 988 981 /* Fixup: drop when we get rid of start array */ 989 - if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0], 982 + if (aa_dfa_next(rules->policy->dfa, rules->policy->start[0], 990 983 AA_CLASS_FILE)) 991 - rules->policy.start[AA_CLASS_FILE] = 992 - aa_dfa_next(rules->policy.dfa, 993 - rules->policy.start[0], 984 + rules->policy->start[AA_CLASS_FILE] = 985 + aa_dfa_next(rules->policy->dfa, 986 + rules->policy->start[0], 994 987 AA_CLASS_FILE); 995 988 if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) 996 989 goto fail; 997 - if (!rules->policy.perms) { 998 - error = aa_compat_map_policy(&rules->policy, 990 + if (!rules->policy->perms) { 991 + error = aa_compat_map_policy(rules->policy, 999 992 e->version); 1000 993 if (error) { 1001 994 info = "failed to remap policydb permission table"; ··· 1003 996 } 1004 997 } 1005 998 } else { 1006 - rules->policy.dfa = aa_get_dfa(nulldfa); 1007 - rules->policy.perms = kcalloc(2, sizeof(struct aa_perms), 1008 - GFP_KERNEL); 1009 - if (!rules->policy.perms) 1010 - goto fail; 1011 - rules->policy.size = 2; 999 + rules->policy = aa_get_pdb(nullpdb); 1012 1000 } 1013 1001 /* get file rules */ 1014 1002 error = unpack_pdb(e, &rules->file, false, true, &info); 1015 1003 if (error) { 1016 1004 goto fail; 1017 - } else if (rules->file.dfa) { 1018 - if (!rules->file.perms) { 1019 - error = aa_compat_map_file(&rules->file); 1005 + } else if (rules->file->dfa) { 1006 + if (!rules->file->perms) { 1007 + error = aa_compat_map_file(rules->file); 1020 1008 if (error) { 1021 1009 info = "failed to remap file permission table"; 1022 1010 goto fail; 1023 1011 } 1024 1012 } 1025 - } else if (rules->policy.dfa && 1026 - rules->policy.start[AA_CLASS_FILE]) { 1027 - rules->file.dfa = aa_get_dfa(rules->policy.dfa); 1028 - rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE]; 1029 - rules->file.perms = kcalloc(rules->policy.size, 1030 - sizeof(struct aa_perms), 1031 - GFP_KERNEL); 1032 - if (!rules->file.perms) 1033 - goto fail; 1034 - memcpy(rules->file.perms, rules->policy.perms, 1035 - rules->policy.size * sizeof(struct aa_perms)); 1036 - rules->file.size = rules->policy.size; 1013 + } else if (rules->policy->dfa && 1014 + rules->policy->start[AA_CLASS_FILE]) { 1015 + rules->file = aa_get_pdb(rules->policy); 1037 1016 } else { 1038 - rules->file.dfa = aa_get_dfa(nulldfa); 1039 - rules->file.perms = kcalloc(2, sizeof(struct aa_perms), 1040 - GFP_KERNEL); 1041 - if (!rules->file.perms) 1042 - goto fail; 1043 - rules->file.size = 2; 1017 + rules->file = aa_get_pdb(nullpdb); 1044 1018 } 1045 1019 error = -EPROTO; 1046 1020 if (aa_unpack_nameX(e, AA_STRUCT, "data")) { ··· 1228 1240 if (!rules) 1229 1241 return 0; 1230 1242 1231 - if (rules->file.dfa && !verify_dfa_accept_index(rules->file.dfa, 1232 - rules->file.size)) { 1243 + if (rules->file->dfa && !verify_dfa_accept_index(rules->file->dfa, 1244 + rules->file->size)) { 1233 1245 audit_iface(profile, NULL, NULL, 1234 1246 "Unpack: file Invalid named transition", NULL, 1235 1247 -EPROTO); 1236 1248 return -EPROTO; 1237 1249 } 1238 - if (rules->policy.dfa && 1239 - !verify_dfa_accept_index(rules->policy.dfa, rules->policy.size)) { 1250 + if (rules->policy->dfa && 1251 + !verify_dfa_accept_index(rules->policy->dfa, rules->policy->size)) { 1240 1252 audit_iface(profile, NULL, NULL, 1241 1253 "Unpack: policy Invalid named transition", NULL, 1242 1254 -EPROTO); 1243 1255 return -EPROTO; 1244 1256 } 1245 1257 1246 - if (!verify_perms(&rules->file)) { 1258 + if (!verify_perms(rules->file)) { 1247 1259 audit_iface(profile, NULL, NULL, 1248 1260 "Unpack: Invalid perm index", NULL, -EPROTO); 1249 1261 return -EPROTO; 1250 1262 } 1251 - if (!verify_perms(&rules->policy)) { 1263 + if (!verify_perms(rules->policy)) { 1252 1264 audit_iface(profile, NULL, NULL, 1253 1265 "Unpack: Invalid perm index", NULL, -EPROTO); 1254 1266 return -EPROTO; 1255 1267 } 1256 - if (!verify_perms(&profile->attach.xmatch)) { 1268 + if (!verify_perms(profile->attach.xmatch)) { 1257 1269 audit_iface(profile, NULL, NULL, 1258 1270 "Unpack: Invalid perm index", NULL, -EPROTO); 1259 1271 return -EPROTO;