diff options
author | John Johansen <john.johansen@canonical.com> | 2022-07-29 17:17:31 -0700 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2022-10-03 14:49:04 -0700 |
commit | 217af7e2f4deb629aaa49622685ccfee923898ca (patch) | |
tree | 02cec1dca247db53b3cd4acb711d2a77b512ab12 /security/apparmor | |
parent | 3bf3d728a58d7dcf2bbf179e3263fb8651f6097b (diff) | |
download | linux-217af7e2f4deb629aaa49622685ccfee923898ca.tar.gz linux-217af7e2f4deb629aaa49622685ccfee923898ca.tar.bz2 linux-217af7e2f4deb629aaa49622685ccfee923898ca.zip |
apparmor: refactor profile rules and attachments
In preparation for moving from a single set of rules and a single
attachment to multiple rulesets and attachments separate from the
profile refactor attachment information and ruleset info into their
own structures.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor')
-rw-r--r-- | security/apparmor/apparmorfs.c | 27 | ||||
-rw-r--r-- | security/apparmor/capability.c | 12 | ||||
-rw-r--r-- | security/apparmor/domain.c | 81 | ||||
-rw-r--r-- | security/apparmor/file.c | 14 | ||||
-rw-r--r-- | security/apparmor/include/label.h | 9 | ||||
-rw-r--r-- | security/apparmor/include/perms.h | 3 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 84 | ||||
-rw-r--r-- | security/apparmor/ipc.c | 9 | ||||
-rw-r--r-- | security/apparmor/label.c | 45 | ||||
-rw-r--r-- | security/apparmor/lib.c | 13 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 4 | ||||
-rw-r--r-- | security/apparmor/mount.c | 31 | ||||
-rw-r--r-- | security/apparmor/net.c | 24 | ||||
-rw-r--r-- | security/apparmor/policy.c | 44 | ||||
-rw-r--r-- | security/apparmor/policy_ns.c | 4 | ||||
-rw-r--r-- | security/apparmor/policy_unpack.c | 118 | ||||
-rw-r--r-- | security/apparmor/resource.c | 15 | ||||
-rw-r--r-- | security/apparmor/task.c | 10 |
18 files changed, 308 insertions, 239 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index fb9d2ccb34d6..84ef8b400b40 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -611,30 +611,29 @@ static const struct file_operations aa_fs_ns_revision_fops = { static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, const char *match_str, size_t match_len) { + struct aa_ruleset *rules = &profile->rules; struct aa_perms tmp = { }; - struct aa_dfa *dfa; aa_state_t state = DFA_NOMATCH; if (profile_unconfined(profile)) return; - if (profile->file.dfa && *match_str == AA_CLASS_FILE) { - dfa = profile->file.dfa; - state = aa_dfa_match_len(dfa, - profile->file.start[AA_CLASS_FILE], + if (rules->file.dfa && *match_str == AA_CLASS_FILE) { + state = aa_dfa_match_len(rules->file.dfa, + rules->file.start[AA_CLASS_FILE], match_str + 1, match_len - 1); if (state) { struct path_cond cond = { }; - tmp = *(aa_lookup_fperms(&(profile->file), state, &cond)); + tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); } - } else if (profile->policy.dfa) { - if (!PROFILE_MEDIATES(profile, *match_str)) + } else if (rules->policy.dfa) { + if (!RULE_MEDIATES(rules, *match_str)) return; /* no change to current perms */ - dfa = profile->policy.dfa; - state = aa_dfa_match_len(dfa, profile->policy.start[0], + state = aa_dfa_match_len(rules->policy.dfa, + rules->policy.start[0], match_str, match_len); if (state) - tmp = *aa_lookup_perms(&profile->policy, state); + tmp = *aa_lookup_perms(&rules->policy, state); } aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum_raw(perms, &tmp); @@ -1093,9 +1092,9 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v) struct aa_proxy *proxy = seq->private; struct aa_label *label = aa_get_label_rcu(&proxy->label); struct aa_profile *profile = labels_profile(label); - if (profile->attach) - seq_printf(seq, "%s\n", profile->attach); - else if (profile->xmatch.dfa) + if (profile->attach.xmatch_str) + seq_printf(seq, "%s\n", profile->attach.xmatch_str); + else if (profile->attach.xmatch.dfa) seq_puts(seq, "<unknown>\n"); else seq_printf(seq, "%s\n", profile->base.name); diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 6cabd6109f12..b66ec63e2a48 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -64,6 +64,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, int cap, int error) { + struct aa_ruleset *rules = &profile->rules; struct audit_cache *ent; int type = AUDIT_APPARMOR_AUTO; @@ -72,13 +73,13 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, if (likely(!error)) { /* test if auditing is being forced */ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) && - !cap_raised(profile->caps.audit, cap))) + !cap_raised(rules->caps.audit, cap))) return 0; type = AUDIT_APPARMOR_AUDIT; } else if (KILL_MODE(profile) || - cap_raised(profile->caps.kill, cap)) { + cap_raised(rules->caps.kill, cap)) { type = AUDIT_APPARMOR_KILL; - } else if (cap_raised(profile->caps.quiet, cap) && + } else if (cap_raised(rules->caps.quiet, cap) && AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_ALL) { /* quiet auditing */ @@ -114,10 +115,11 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, static int profile_capable(struct aa_profile *profile, int cap, unsigned int opts, struct common_audit_data *sa) { + struct aa_ruleset *rules = &profile->rules; int error; - if (cap_raised(profile->caps.allow, cap) && - !cap_raised(profile->caps.denied, cap)) + if (cap_raised(rules->caps.allow, cap) && + !cap_raised(rules->caps.denied, cap)) error = 0; else error = -EPERM; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 4cb046cf3a14..ad035d14cfc5 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -81,19 +81,20 @@ static inline aa_state_t match_component(struct aa_profile *profile, struct aa_profile *tp, bool stack, aa_state_t state) { + struct aa_ruleset *rules = &profile->rules; const char *ns_name; if (stack) - state = aa_dfa_match(profile->file.dfa, state, "&"); + state = aa_dfa_match(rules->file.dfa, state, "&"); if (profile->ns == tp->ns) - return aa_dfa_match(profile->file.dfa, state, tp->base.hname); + return aa_dfa_match(rules->file.dfa, state, tp->base.hname); /* try matching with namespace name and then profile */ ns_name = aa_ns_name(profile->ns, tp->ns, true); - state = aa_dfa_match_len(profile->file.dfa, state, ":", 1); - state = aa_dfa_match(profile->file.dfa, state, ns_name); - state = aa_dfa_match_len(profile->file.dfa, state, ":", 1); - return aa_dfa_match(profile->file.dfa, state, tp->base.hname); + state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); + state = aa_dfa_match(rules->file.dfa, state, ns_name); + state = aa_dfa_match_len(rules->file.dfa, state, ":", 1); + return aa_dfa_match(rules->file.dfa, state, tp->base.hname); } /** @@ -117,6 +118,7 @@ static int label_compound_match(struct aa_profile *profile, aa_state_t state, bool subns, u32 request, struct aa_perms *perms) { + struct aa_ruleset *rules = &profile->rules; struct aa_profile *tp; struct label_it i; struct path_cond cond = { }; @@ -139,12 +141,12 @@ next: label_for_each_cont(i, label, tp) { if (!aa_ns_visible(profile->ns, tp->ns, subns)) continue; - state = aa_dfa_match(profile->file.dfa, state, "//&"); + state = aa_dfa_match(rules->file.dfa, state, "//&"); state = match_component(profile, tp, false, state); if (!state) goto fail; } - *perms = *(aa_lookup_fperms(&(profile->file), state, &cond)); + *perms = *(aa_lookup_fperms(&(rules->file), state, &cond)); aa_apply_modes_to_perms(profile, perms); if ((perms->allow & request) != request) return -EACCES; @@ -177,6 +179,7 @@ static int label_components_match(struct aa_profile *profile, aa_state_t start, bool subns, u32 request, struct aa_perms *perms) { + struct aa_ruleset *rules = &profile->rules; struct aa_profile *tp; struct label_it i; struct aa_perms tmp; @@ -197,7 +200,7 @@ static int label_components_match(struct aa_profile *profile, return 0; next: - tmp = *(aa_lookup_fperms(&(profile->file), state, &cond)); + tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); label_for_each_cont(i, label, tp) { @@ -206,7 +209,7 @@ next: state = match_component(profile, tp, stack, start); if (!state) goto fail; - tmp = *(aa_lookup_fperms(&(profile->file), state, &cond)); + tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); } @@ -296,18 +299,19 @@ static int aa_xattrs_match(const struct linux_binprm *bprm, ssize_t size; struct dentry *d; char *value = NULL; - int value_size = 0, ret = profile->xattr_count; + struct aa_attachment *attach = &profile->attach; + int value_size = 0, ret = attach->xattr_count; - if (!bprm || !profile->xattr_count) + if (!bprm || !attach->xattr_count) return 0; might_sleep(); /* transition from exec match to xattr set */ - state = aa_dfa_outofband_transition(profile->xmatch.dfa, state); + state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); d = bprm->file->f_path.dentry; - for (i = 0; i < profile->xattr_count; i++) { - size = vfs_getxattr_alloc(&init_user_ns, d, profile->xattrs[i], + for (i = 0; i < attach->xattr_count; i++) { + size = vfs_getxattr_alloc(&init_user_ns, d, attach->xattrs[i], &value, value_size, GFP_KERNEL); if (size >= 0) { u32 index, perm; @@ -317,20 +321,20 @@ static int aa_xattrs_match(const struct linux_binprm *bprm, * that not present xattr can be distinguished from a 0 * length value or rule that matches any value */ - state = aa_dfa_null_transition(profile->xmatch.dfa, + state = aa_dfa_null_transition(attach->xmatch.dfa, state); /* Check xattr value */ - state = aa_dfa_match_len(profile->xmatch.dfa, state, + state = aa_dfa_match_len(attach->xmatch.dfa, state, value, size); - index = ACCEPT_TABLE(profile->xmatch.dfa)[state]; - perm = profile->xmatch.perms[index].allow; + index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; + perm = attach->xmatch.perms[index].allow; if (!(perm & MAY_EXEC)) { ret = -EINVAL; goto out; } } /* transition to next element */ - state = aa_dfa_outofband_transition(profile->xmatch.dfa, state); + state = aa_dfa_outofband_transition(attach->xmatch.dfa, state); if (size < 0) { /* * No xattr match, so verify if transition to @@ -382,6 +386,8 @@ static struct aa_label *find_attach(const struct linux_binprm *bprm, rcu_read_lock(); restart: list_for_each_entry_rcu(profile, head, base.list) { + struct aa_attachment *attach = &profile->attach; + if (profile->label.flags & FLAG_NULL && &profile->label == ns_unconfined(profile->ns)) continue; @@ -397,16 +403,16 @@ restart: * as another profile, signal a conflict and refuse to * match. */ - if (profile->xmatch.dfa) { + if (attach->xmatch.dfa) { unsigned int count; aa_state_t state; u32 index, perm; - state = aa_dfa_leftmatch(profile->xmatch.dfa, - profile->xmatch.start[AA_CLASS_XMATCH], + state = aa_dfa_leftmatch(attach->xmatch.dfa, + attach->xmatch.start[AA_CLASS_XMATCH], name, &count); - index = ACCEPT_TABLE(profile->xmatch.dfa)[state]; - perm = profile->xmatch.perms[index].allow; + index = ACCEPT_TABLE(attach->xmatch.dfa)[state]; + perm = attach->xmatch.perms[index].allow; /* any accepting state means a valid match. */ if (perm & MAY_EXEC) { int ret = 0; @@ -414,7 +420,7 @@ restart: if (count < candidate_len) continue; - if (bprm && profile->xattr_count) { + if (bprm && attach->xattr_count) { long rev = READ_ONCE(ns->revision); if (!aa_get_profile_not0(profile)) @@ -453,7 +459,7 @@ restart: * xattrs, or a longer match */ candidate = profile; - candidate_len = max(count, profile->xmatch_len); + candidate_len = max(count, attach->xmatch_len); candidate_xattrs = ret; conflict = false; } @@ -497,6 +503,7 @@ static const char *next_name(int xtype, const char *name) struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, const char **name) { + struct aa_ruleset *rules = &profile->rules; struct aa_label *label = NULL; u32 xtype = xindex & AA_X_TYPE_MASK; int index = xindex & AA_X_INDEX_MASK; @@ -507,7 +514,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, /* TODO: move lookup parsing to unpack time so this is a straight * index into the resultant label */ - for (*name = profile->file.trans.table[index]; !label && *name; + for (*name = rules->file.trans.table[index]; !label && *name; *name = next_name(xtype, *name)) { if (xindex & AA_X_CHILD) { struct aa_profile *new_profile; @@ -546,6 +553,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile, const char **lookupname, const char **info) { + struct aa_ruleset *rules = &profile->rules; struct aa_label *new = NULL; struct aa_ns *ns = profile->ns; u32 xtype = xindex & AA_X_TYPE_MASK; @@ -558,7 +566,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile, break; case AA_X_TABLE: /* TODO: fix when perm mapping done at unload */ - stack = profile->file.trans.table[xindex & AA_X_INDEX_MASK]; + stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK]; if (*stack != '&') { /* released by caller */ new = x_table_lookup(profile, xindex, lookupname); @@ -612,9 +620,10 @@ static struct aa_label *profile_transition(struct aa_profile *profile, char *buffer, struct path_cond *cond, bool *secure_exec) { + struct aa_ruleset *rules = &profile->rules; struct aa_label *new = NULL; const char *info = NULL, *name = NULL, *target = NULL; - aa_state_t state = profile->file.start[AA_CLASS_FILE]; + aa_state_t state = rules->file.start[AA_CLASS_FILE]; struct aa_perms perms = {}; bool nonewprivs = false; int error = 0; @@ -648,7 +657,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile, } /* find exec permissions for name */ - state = aa_str_perms(&(profile->file), state, name, cond, &perms); + state = aa_str_perms(&(rules->file), state, name, cond, &perms); if (perms.allow & MAY_EXEC) { /* exec permission determine how to transition */ new = x_to_label(profile, bprm, name, perms.xindex, &target, @@ -710,7 +719,8 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec, char *buffer, struct path_cond *cond, bool *secure_exec) { - aa_state_t state = profile->file.start[AA_CLASS_FILE]; + struct aa_ruleset *rules = &profile->rules; + aa_state_t state = rules->file.start[AA_CLASS_FILE]; struct aa_perms perms = {}; const char *xname = NULL, *info = "change_profile onexec"; int error = -EACCES; @@ -743,7 +753,7 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec, } /* find exec permissions for name */ - state = aa_str_perms(&(profile->file), state, xname, cond, &perms); + state = aa_str_perms(&(rules->file), state, xname, cond, &perms); if (!(perms.allow & AA_MAY_ONEXEC)) { info = "no change_onexec valid for executable"; goto audit; @@ -752,7 +762,7 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec, * onexec permission is linked to exec with a standard pairing * exec\0change_profile */ - state = aa_dfa_null_transition(profile->file.dfa, state); + state = aa_dfa_null_transition(rules->file.dfa, state); error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC, state, &perms); if (error) { @@ -1249,12 +1259,13 @@ static int change_profile_perms_wrapper(const char *op, const char *name, struct aa_label *target, bool stack, u32 request, struct aa_perms *perms) { + struct aa_ruleset *rules = &profile->rules; const char *info = NULL; int error = 0; if (!error) error = change_profile_perms(profile, target, stack, request, - profile->file.start[AA_CLASS_FILE], + rules->file.start[AA_CLASS_FILE], perms); if (error) error = aa_audit_file(profile, perms, op, request, name, diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 69d936d04f94..ef5d98f81a2b 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -224,11 +224,12 @@ int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name, u32 request, struct path_cond *cond, int flags, struct aa_perms *perms) { + struct aa_ruleset *rules = &profile->rules; int e = 0; if (profile_unconfined(profile)) return 0; - aa_str_perms(&(profile->file), profile->file.start[AA_CLASS_FILE], + aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], name, cond, perms); if (request & ~perms->allow) e = -EACCES; @@ -316,6 +317,7 @@ static int profile_path_link(struct aa_profile *profile, const struct path *target, char *buffer2, struct path_cond *cond) { + struct aa_ruleset *rules = &profile->rules; const char *lname, *tname = NULL; struct aa_perms lperms = {}, perms; const char *info = NULL; @@ -336,16 +338,16 @@ static int profile_path_link(struct aa_profile *profile, error = -EACCES; /* aa_str_perms - handles the case of the dfa being NULL */ - state = aa_str_perms(&(profile->file), - profile->file.start[AA_CLASS_FILE], lname, + state = aa_str_perms(&(rules->file), + rules->file.start[AA_CLASS_FILE], lname, cond, &lperms); if (!(lperms.allow & AA_MAY_LINK)) goto audit; /* test to see if target can be paired with link */ - state = aa_dfa_null_transition(profile->file.dfa, state); - aa_str_perms(&(profile->file), state, tname, cond, &perms); + state = aa_dfa_null_transition(rules->file.dfa, state); + aa_str_perms(&(rules->file), state, tname, cond, &perms); /* force audit/quiet masks for link are stored in the second entry * in the link pair. @@ -367,7 +369,7 @@ static int profile_path_link(struct aa_profile *profile, /* Do link perm subset test requiring allowed permission on link are * a subset of the allowed permissions on target. */ - aa_str_perms(&(profile->file), profile->file.start[AA_CLASS_FILE], + aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE], tname, cond, &perms); /* AA_MAY_LINK is not considered in the subset test */ diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 1130ba10a152..2a72e6b17d68 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -261,7 +261,7 @@ for ((I).i = (I).j = 0; \ struct label_it i; \ int ret = 0; \ label_for_each(i, (L), profile) { \ - if (PROFILE_MEDIATES(profile, (C))) { \ + if (RULE_MEDIATES(&profile->rules, (C))) { \ ret = 1; \ break; \ } \ @@ -357,9 +357,10 @@ static inline const char *aa_label_str_split(const char *str) struct aa_perms; -int aa_label_match(struct aa_profile *profile, struct aa_label *label, - aa_state_t state, bool subns, u32 request, - struct aa_perms *perms); +struct aa_ruleset; +int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules, + struct aa_label *label, aa_state_t state, bool subns, + u32 request, struct aa_perms *perms); /** diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index 9fa71957ac3a..797a7a00644d 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -207,7 +207,8 @@ void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms); void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend); void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend); -void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, +void aa_profile_match_label(struct aa_profile *profile, + struct aa_ruleset *rules, struct aa_label *label, int type, u32 request, struct aa_perms *perms); int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, u32 request, int type, u32 *deny, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 2c39bd389f87..9ee2c05e2895 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -123,6 +123,43 @@ struct aa_data { struct rhash_head head; }; +/* struct aa_ruleset - data covering mediation rules + * @size: the memory consumed by this ruleset + * @policy: general match rules governing policy + * @file: The set of rules governing basic file access and domain transitions + * @caps: capabilities for the profile + * @rlimits: rlimits for the profile + * @secmark_count: number of secmark entries + * @secmark: secmark label match info + */ +struct aa_ruleset { + int size; + + /* TODO: merge policy and file */ + struct aa_policydb policy; + struct aa_policydb file; + struct aa_caps caps; + + struct aa_rlimit rlimits; + + int secmark_count; + struct aa_secmark *secmark; +}; + +/* struct aa_attachment - data and rules for a profiles attachment + * @xmatch_str: human readable attachment string + * @xmatch: optional extended matching for unconfined executables names + * @xmatch_len: xmatch prefix len, used to determine xmatch priority + * @xattr_count: number of xattrs in table + * @xattrs: table of xattrs + */ +struct aa_attachment { + const char *xmatch_str; + struct aa_policydb xmatch; + unsigned int xmatch_len; + int xattr_count; + char **xattrs; +}; /* struct aa_profile - basic confinement data * @base - base components of the profile (name, refcount, lists, lock ...) @@ -130,18 +167,13 @@ struct aa_data { * @parent: parent of profile * @ns: namespace the profile is in * @rename: optional profile name that this profile renamed - * @attach: human readable attachment string - * @xmatch: optional extended matching for unconfined executables names - * @xmatch_len: xmatch prefix len, used to determine xmatch priority + * * @audit: the auditing mode of the profile * @mode: the enforcement mode of the profile * @path_flags: flags controlling path generation behavior * @disconnected: what to prepend if attach_disconnected is specified - * @size: the memory consumed by this profiles rules - * @policy: general match rules governing policy - * @file: The set of rules governing basic file access and domain transitions - * @caps: capabilities for the profile - * @rlimits: rlimits for the profile + * @attach: attachment rules for the profile + * @rules: rules to be enforced * * @dents: dentries for the profiles file entries in apparmorfs * @dirname: name of the profile dir in apparmorfs @@ -166,27 +198,13 @@ struct aa_profile { struct aa_ns *ns; const char *rename; - const char *attach; - struct aa_policydb xmatch; - unsigned int xmatch_len; - enum audit_mode audit; long mode; u32 path_flags; const char *disconnected; - int size; - struct aa_policydb policy; - struct aa_policydb file; - struct aa_caps caps; - - int xattr_count; - char **xattrs; - - struct aa_rlimit rlimits; - - int secmark_count; - struct aa_secmark *secmark; + struct aa_attachment attach; + struct aa_ruleset rules; struct aa_loaddata *rawdata; unsigned char *hash; @@ -247,24 +265,24 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) return labels_profile(aa_get_newest_label(&p->label)); } -static inline aa_state_t PROFILE_MEDIATES(struct aa_profile *profile, - unsigned char class) +static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules, + unsigned char class) { if (class <= AA_CLASS_LAST) - return profile->policy.start[class]; + return rules->policy.start[class]; else - return aa_dfa_match_len(profile->policy.dfa, - profile->policy.start[0], &class, 1); + return aa_dfa_match_len(rules->policy.dfa, + rules->policy.start[0], &class, 1); } -static inline aa_state_t PROFILE_MEDIATES_AF(struct aa_profile *profile, - u16 AF) { - aa_state_t state = PROFILE_MEDIATES(profile, AA_CLASS_NET); +static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) +{ + aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NET); __be16 be_af = cpu_to_be16(AF); if (!state) return DFA_NOMATCH; - return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); + return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2); } /** diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 4ecaf2ba26c5..dc2fa548312d 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -78,19 +78,20 @@ static int profile_signal_perm(struct aa_profile *profile, struct aa_label *peer, u32 request, struct common_audit_data *sa) { + struct aa_ruleset *rules = &profile->rules; struct aa_perms perms; aa_state_t state; if (profile_unconfined(profile) || - !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL)) + !RULE_MEDIATES(rules, AA_CLASS_SIGNAL)) return 0; aad(sa)->peer = peer; /* TODO: secondary cache check <profile, profile, perm> */ - state = aa_dfa_next(profile->policy.dfa, - profile->policy.start[AA_CLASS_SIGNAL], + state = aa_dfa_next(rules->policy.dfa, + rules->policy.start[AA_CLASS_SIGNAL], aad(sa)->signal); - aa_label_match(profile, peer, state, false, request, &perms); + aa_label_match(profile, rules, peer, state, false, request, &perms); aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, sa, audit_signal_cb); } diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 3a967003fa7c..98dadd960977 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1266,20 +1266,21 @@ static inline bool label_is_visible(struct aa_profile *profile, * visibility test. */ static inline aa_state_t match_component(struct aa_profile *profile, + struct aa_ruleset *rules, struct aa_profile *tp, aa_state_t state) { const char *ns_name; if (profile->ns == tp->ns) - return aa_dfa_match(profile->policy.dfa, state, tp->base.hname); + return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); /* try matching with namespace name and then profile */ ns_name = aa_ns_name(profile->ns, tp->ns, true); - state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1); - state = aa_dfa_match(profile->policy.dfa, state, ns_name); - state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1); - return aa_dfa_match(profile->policy.dfa, state, tp->base.hname); + state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); + state = aa_dfa_match(rules->policy.dfa, state, ns_name); + state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1); + return aa_dfa_match(rules->policy.dfa, state, tp->base.hname); } /** @@ -1298,6 +1299,7 @@ static inline aa_state_t match_component(struct aa_profile *profile, * check to be stacked. */ static int label_compound_match(struct aa_profile *profile, + struct aa_ruleset *rules, struct aa_label *label, aa_state_t state, bool subns, u32 request, struct aa_perms *perms) @@ -1309,7 +1311,7 @@ static int label_compound_match(struct aa_profile *profile, label_for_each(i, label, tp) { if (!aa_ns_visible(profile->ns, tp->ns, subns)) continue; - state = match_component(profile, tp, state); + state = match_component(profile, rules, tp, state); if (!state) goto fail; goto next; @@ -1323,12 +1325,12 @@ next: label_for_each_cont(i, label, tp) { if (!aa_ns_visible(profile->ns, tp->ns, subns)) continue; - state = aa_dfa_match(profile->policy.dfa, state, "//&"); - state = match_component(profile, tp, state); + state = aa_dfa_match(rules->policy.dfa, state, "//&"); + state = match_component(profile, rules, tp, state); if (!state) goto fail; } - *perms = *aa_lookup_perms(&profile->policy, state); + *perms = *aa_lookup_perms(&rules->policy, state); aa_apply_modes_to_perms(profile, perms); if ((perms->allow & request) != request) return -EACCES; @@ -1343,6 +1345,7 @@ fail: /** * label_components_match - find perms for all subcomponents of a label * @profile: profile to find perms for + * @rules: ruleset to search * @label: label to check access permissions for * @start: state to start match in * @subns: whether to do permission checks on components in a subns @@ -1356,6 +1359,7 @@ fail: * check to be stacked. */ static int label_components_match(struct aa_profile *profile, + struct aa_ruleset *rules, struct aa_label *label, aa_state_t start, bool subns, u32 request, struct aa_perms *perms) @@ -1369,7 +1373,7 @@ static int label_components_match(struct aa_profile *profile, label_for_each(i, label, tp) { if (!aa_ns_visible(profile->ns, tp->ns, subns)) continue; - state = match_component(profile, tp, start); + state = match_component(profile, rules, tp, start); if (!state) goto fail; goto next; @@ -1379,16 +1383,16 @@ static int label_components_match(struct aa_profile *profile, return 0; next: - tmp = *aa_lookup_perms(&profile->policy, state); + tmp = *aa_lookup_perms(&rules->policy, state); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); label_for_each_cont(i, label, tp) { if (!aa_ns_visible(profile->ns, tp->ns, subns)) continue; - state = match_component(profile, tp, start); + state = match_component(profile, rules, tp, start); if (!state) goto fail; - tmp = *aa_lookup_perms(&profile->policy, state); + tmp = *aa_lookup_perms(&rules->policy, state); aa_apply_modes_to_perms(profile, &tmp); aa_perms_accum(perms, &tmp); } @@ -1406,6 +1410,7 @@ fail: /** * aa_label_match - do a multi-component label match * @profile: profile to match against (NOT NULL) + * @rules: ruleset to search * @label: label to match (NOT NULL) * @state: state to start in * @subns: whether to match subns components @@ -1414,18 +1419,18 @@ fail: * * Returns: the state the match finished in, may be the none matching state */ -int aa_label_match(struct aa_profile *profile, struct aa_label *label, - aa_state_t state, bool subns, u32 request, - struct aa_perms *perms) +int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules, + struct aa_label *label, aa_state_t state, bool subns, + u32 request, struct aa_perms *perms) { - int error = label_compound_match(profile, label, state, subns, request, - perms); + int error = label_compound_match(profile, rules, label, state, subns, + request, perms); if (!error) return error; *perms = allperms; - return label_components_match(profile, label, state, subns, request, - perms); + return label_components_match(profile, rules, label, state, subns, + request, perms); } diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 10e3b11e02ad..ec73e51ca7e3 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -331,16 +331,18 @@ void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) perms->prompt = ALL_PERMS_MASK; } -void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, +void aa_profile_match_label(struct aa_profile *profile, + struct aa_ruleset *rules, + struct aa_label *label, int type, u32 request, struct aa_perms *perm |