From 217af7e2f4deb629aaa49622685ccfee923898ca Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 29 Jul 2022 17:17:31 -0700 Subject: [PATCH] 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 --- security/apparmor/apparmorfs.c | 27 ++++--- security/apparmor/capability.c | 12 +-- security/apparmor/domain.c | 81 +++++++++++--------- security/apparmor/file.c | 14 ++-- security/apparmor/include/label.h | 9 ++- security/apparmor/include/perms.h | 3 +- security/apparmor/include/policy.h | 84 ++++++++++++-------- security/apparmor/ipc.c | 9 ++- security/apparmor/label.c | 45 ++++++----- security/apparmor/lib.c | 13 ++-- security/apparmor/lsm.c | 4 +- security/apparmor/mount.c | 31 ++++---- security/apparmor/net.c | 24 +++--- security/apparmor/policy.c | 44 +++++++---- security/apparmor/policy_ns.c | 4 +- security/apparmor/policy_unpack.c | 118 +++++++++++++++-------------- security/apparmor/resource.c | 15 ++-- 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, "\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 */ - 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 *perms) { /* TODO: doesn't yet handle extended types */ aa_state_t state; - state = aa_dfa_next(profile->policy.dfa, - profile->policy.start[AA_CLASS_LABEL], + state = aa_dfa_next(rules->policy.dfa, + rules->policy.start[AA_CLASS_LABEL], type); - aa_label_match(profile, label, state, false, request, perms); + aa_label_match(profile, rules, label, state, false, request, perms); } @@ -355,7 +357,8 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, aad(sa)->peer = &target->label; aad(sa)->request = request; - aa_profile_match_label(profile, &target->label, type, request, &perms); + aa_profile_match_label(profile, &profile->rules, &target->label, type, + request, &perms); aa_apply_modes_to_perms(profile, &perms); *deny |= request & perms.deny; return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 784709286a62..62f2ca32b959 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -166,9 +166,9 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, if (COMPLAIN_MODE(profile)) continue; *effective = cap_intersect(*effective, - profile->caps.allow); + profile->rules.caps.allow); *permitted = cap_intersect(*permitted, - profile->caps.allow); + profile->rules.caps.allow); } } rcu_read_unlock(); diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 02d8215cb9fd..d4724bdcb07f 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -303,13 +303,14 @@ static int match_mnt_path_str(struct aa_profile *profile, { struct aa_perms perms = { }; const char *mntpnt = NULL, *info = NULL; + struct aa_ruleset *rules = &profile->rules; int pos, error; AA_BUG(!profile); AA_BUG(!mntpath); AA_BUG(!buffer); - if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) + if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) return 0; error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer, @@ -324,8 +325,8 @@ static int match_mnt_path_str(struct aa_profile *profile, } error = -EACCES; - pos = do_match_mnt(&profile->policy, - profile->policy.start[AA_CLASS_MOUNT], + pos = do_match_mnt(&rules->policy, + rules->policy.start[AA_CLASS_MOUNT], mntpnt, devname, type, flags, data, binary, &perms); if (pos) { info = mnt_info_table[pos]; @@ -363,7 +364,7 @@ static int match_mnt(struct aa_profile *profile, const struct path *path, AA_BUG(!profile); AA_BUG(devpath && !devbuffer); - if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) + if (!RULE_MEDIATES(&profile->rules, AA_CLASS_MOUNT)) return 0; if (devpath) { @@ -565,6 +566,7 @@ out: static int profile_umount(struct aa_profile *profile, const struct path *path, char *buffer) { + struct aa_ruleset *rules = &profile->rules; struct aa_perms perms = { }; const char *name = NULL, *info = NULL; aa_state_t state; @@ -573,7 +575,7 @@ static int profile_umount(struct aa_profile *profile, const struct path *path, AA_BUG(!profile); AA_BUG(!path); - if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) + if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT)) return 0; error = aa_path_name(path, path_flags(profile, path), buffer, &name, @@ -581,10 +583,10 @@ static int profile_umount(struct aa_profile *profile, const struct path *path, if (error) goto audit; - state = aa_dfa_match(profile->policy.dfa, - profile->policy.start[AA_CLASS_MOUNT], + state = aa_dfa_match(rules->policy.dfa, + rules->policy.start[AA_CLASS_MOUNT], name); - perms = *aa_lookup_perms(&profile->policy, state); + perms = *aa_lookup_perms(&rules->policy, state); if (AA_MAY_UMOUNT & ~perms.allow) error = -EACCES; @@ -624,6 +626,7 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile, const struct path *old_path, char *old_buffer) { + struct aa_ruleset *rules = &profile->rules; const char *old_name, *new_name = NULL, *info = NULL; const char *trans_name = NULL; struct aa_perms perms = { }; @@ -635,7 +638,7 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile, AA_BUG(!old_path); if (profile_unconfined(profile) || - !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) + !RULE_MEDIATES(rules, AA_CLASS_MOUNT)) return aa_get_newest_label(&profile->label); error = aa_path_name(old_path, path_flags(profile, old_path), @@ -650,12 +653,12 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile, goto audit; error = -EACCES; - state = aa_dfa_match(profile->policy.dfa, - profile->policy.start[AA_CLASS_MOUNT], + state = aa_dfa_match(rules->policy.dfa, + rules->policy.start[AA_CLASS_MOUNT], new_name); - state = aa_dfa_null_transition(profile->policy.dfa, state); - state = aa_dfa_match(profile->policy.dfa, state, old_name); - perms = *aa_lookup_perms(&profile->policy, state); + state = aa_dfa_null_transition(rules->policy.dfa, state); + state = aa_dfa_match(rules->policy.dfa, state, old_name); + perms = *aa_lookup_perms(&rules->policy, state); if (AA_MAY_PIVOTROOT & perms.allow) error = 0; diff --git a/security/apparmor/net.c b/security/apparmor/net.c index d420d3aec3b8..ae789ee834ad 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -108,6 +108,7 @@ void audit_net_cb(struct audit_buffer *ab, void *va) int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, u32 request, u16 family, int type) { + struct aa_ruleset *rules = &profile->rules; struct aa_perms perms = { }; aa_state_t state; __be16 buffer[2]; @@ -117,15 +118,15 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, if (profile_unconfined(profile)) return 0; - state = PROFILE_MEDIATES(profile, AA_CLASS_NET); + state = RULE_MEDIATES(rules, AA_CLASS_NET); if (!state) return 0; buffer[0] = cpu_to_be16(family); buffer[1] = cpu_to_be16((u16) type); - state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer, + state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer, 4); - perms = *aa_lookup_perms(&profile->policy, state); + perms = *aa_lookup_perms(&rules->policy, state); aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, sa, audit_net_cb); @@ -216,25 +217,26 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, { int i, ret; struct aa_perms perms = { }; + struct aa_ruleset *rules = &profile->rules; - if (profile->secmark_count == 0) + if (rules->secmark_count == 0) return 0; - for (i = 0; i < profile->secmark_count; i++) { - if (!profile->secmark[i].secid) { - ret = apparmor_secmark_init(&profile->secmark[i]); + for (i = 0; i < rules->secmark_count; i++) { + if (!rules->secmark[i].secid) { + ret = apparmor_secmark_init(&rules->secmark[i]); if (ret) return ret; } - if (profile->secmark[i].secid == secid || - profile->secmark[i].secid == AA_SECID_WILDCARD) { - if (profile->secmark[i].deny) + if (rules->secmark[i].secid == secid || + rules->secmark[i].secid == AA_SECID_WILDCARD) { + if (rules->secmark[i].deny) perms.deny = ALL_PERMS_MASK; else perms.allow = ALL_PERMS_MASK; - if (profile->secmark[i].audit) + if (rules->secmark[i].audit) perms.audit = ALL_PERMS_MASK; } } diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 3c3a5263695d..74c0a3b34e9b 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -193,6 +193,30 @@ static void aa_free_data(void *ptr, void *arg) kfree_sensitive(data); } +static void free_attachment(struct aa_attachment *attach) +{ + int i; + + for (i = 0; i < attach->xattr_count; i++) + kfree_sensitive(attach->xattrs[i]); + kfree_sensitive(attach->xattrs); + aa_destroy_policydb(&attach->xmatch); +} + +static void free_ruleset(struct aa_ruleset *rules) +{ + int i; + + aa_destroy_policydb(&rules->file); + aa_destroy_policydb(&rules->policy); + aa_free_cap_rules(&rules->caps); + aa_free_rlimit_rules(&rules->rlimits); + + for (i = 0; i < rules->secmark_count; i++) + kfree_sensitive(rules->secmark[i].label); + kfree_sensitive(rules->secmark); +} + /** * aa_free_profile - free a profile * @profile: the profile to free (MAYBE NULL) @@ -206,7 +230,6 @@ static void aa_free_data(void *ptr, void *arg) void aa_free_profile(struct aa_profile *profile) { struct rhashtable *rht; - int i; AA_DEBUG("%s(%p)\n", __func__, profile); @@ -220,19 +243,10 @@ void aa_free_profile(struct aa_profile *profile) aa_put_ns(profile->ns); kfree_sensitive(profile->rename); - aa_destroy_policydb(&profile->file); - aa_free_cap_rules(&profile->caps); - aa_free_rlimit_rules(&profile->rlimits); - - for (i = 0; i < profile->xattr_count; i++) - kfree_sensitive(profile->xattrs[i]); - kfree_sensitive(profile->xattrs); - for (i = 0; i < profile->secmark_count; i++) - kfree_sensitive(profile->secmark[i].label); - kfree_sensitive(profile->secmark); + free_attachment(&profile->attach); + free_ruleset(&profile->rules); kfree_sensitive(profile->dirname); - aa_destroy_policydb(&profile->xmatch); - aa_destroy_policydb(&profile->policy); + if (profile->data) { rht = profile->data; profile->data = NULL; @@ -544,8 +558,8 @@ name: /* released on free_profile */ rcu_assign_pointer(profile->parent, aa_get_profile(parent)); profile->ns = aa_get_ns(parent->ns); - profile->file.dfa = aa_get_dfa(nulldfa); - profile->policy.dfa = aa_get_dfa(nulldfa); + profile->rules.file.dfa = aa_get_dfa(nulldfa); + profile->rules.policy.dfa = aa_get_dfa(nulldfa); mutex_lock_nested(&profile->ns->lock, profile->ns->level); p = __find_child(&parent->base.profiles, bname); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 43beaad083fe..cb10994cd3b6 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -91,8 +91,8 @@ static struct aa_profile *alloc_unconfined(const char *name) profile->label.flags |= FLAG_IX_ON_NAME_ERROR | FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; profile->mode = APPARMOR_UNCONFINED; - profile->file.dfa = aa_get_dfa(nulldfa); - profile->policy.dfa = aa_get_dfa(nulldfa); + profile->rules.file.dfa = aa_get_dfa(nulldfa); + profile->rules.policy.dfa = aa_get_dfa(nulldfa); return profile; } diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 5a78aaa0eea4..bbca7772dfa2 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -556,12 +556,12 @@ static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile) if (unpack_array(e, NULL, &size) != TRI_TRUE) goto fail; - profile->xattr_count = size; - profile->xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL); - if (!profile->xattrs) + profile->attach.xattr_count = size; + profile->attach.xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL); + if (!profile->attach.xattrs) goto fail; for (i = 0; i < size; i++) { - if (!unpack_strdup(e, &profile->xattrs[i], NULL)) + if (!unpack_strdup(e, &profile->attach.xattrs[i], NULL)) goto fail; } if (!unpack_nameX(e, AA_ARRAYEND, NULL)) @@ -579,6 +579,7 @@ fail: static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile) { + struct aa_ruleset *rules = &profile->rules; void *pos = e->pos; u16 size; int i; @@ -587,19 +588,19 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile) if (unpack_array(e, NULL, &size) != TRI_TRUE) goto fail; - profile->secmark = kcalloc(size, sizeof(struct aa_secmark), + rules->secmark = kcalloc(size, sizeof(struct aa_secmark), GFP_KERNEL); - if (!profile->secmark) + if (!rules->secmark) goto fail; - profile->secmark_count = size; + rules->secmark_count = size; for (i = 0; i < size; i++) { - if (!unpack_u8(e, &profile->secmark[i].audit, NULL)) + if (!unpack_u8(e, &rules->secmark[i].audit, NULL)) goto fail; - if (!unpack_u8(e, &profile->secmark[i].deny, NULL)) + if (!unpack_u8(e, &rules->secmark[i].deny, NULL)) goto fail; - if (!unpack_strdup(e, &profile->secmark[i].label, NULL)) + if (!unpack_strdup(e, &rules->secmark[i].label, NULL)) goto fail; } if (!unpack_nameX(e, AA_ARRAYEND, NULL)) @@ -611,12 +612,12 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile) return true; fail: - if (profile->secmark) { + if (rules->secmark) { for (i = 0; i < size; i++) - kfree(profile->secmark[i].label); - kfree(profile->secmark); - profile->secmark_count = 0; - profile->secmark = NULL; + kfree(rules->secmark[i].label); + kfree(rules->secmark); + rules->secmark_count = 0; + rules->secmark = NULL; } e->pos = pos; @@ -634,7 +635,7 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) u32 tmp = 0; if (!unpack_u32(e, &tmp, NULL)) goto fail; - profile->rlimits.mask = tmp; + profile->rules.rlimits.mask = tmp; if (unpack_array(e, NULL, &size) != TRI_TRUE || size > RLIM_NLIMITS) @@ -644,7 +645,7 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) int a = aa_map_resource(i); if (!unpack_u64(e, &tmp2, NULL)) goto fail; - profile->rlimits.limits[a].rlim_max = tmp2; + profile->rules.rlimits.limits[a].rlim_max = tmp2; } if (!unpack_nameX(e, AA_ARRAYEND, NULL)) goto fail; @@ -816,6 +817,7 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj) */ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) { + struct aa_ruleset *rules; struct aa_profile *profile = NULL; const char *tmpname, *tmpns = NULL, *name = NULL; const char *info = "failed to unpack profile"; @@ -850,27 +852,30 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) profile = aa_alloc_profile(name, NULL, GFP_KERNEL); if (!profile) return ERR_PTR(-ENOMEM); + rules = &profile->rules; /* profile renaming is optional */ (void) unpack_str(e, &profile->rename, "rename"); /* attachment string is optional */ - (void) unpack_str(e, &profile->attach, "attach"); + (void) unpack_str(e, &profile->attach.xmatch_str, "attach"); /* xmatch is optional and may be NULL */ - error = unpack_pdb(e, &profile->xmatch, false, false, &info); - if (error) + error = unpack_pdb(e, &profile->attach.xmatch, false, false, &info); + if (error) { + info = "bad xmatch"; goto fail; + } /* neither xmatch_len not xmatch_perms are optional if xmatch is set */ - if (profile->xmatch.dfa) { + if (profile->attach.xmatch.dfa) { if (!unpack_u32(e, &tmp, NULL)) { info = "missing xmatch len"; goto fail; } - profile->xmatch_len = tmp; - profile->xmatch.start[AA_CLASS_XMATCH] = DFA_START; - if (aa_compat_map_xmatch(&profile->xmatch)) { + profile->attach.xmatch_len = tmp; + profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START; + if (aa_compat_map_xmatch(&profile->attach.xmatch)) { info = "failed to convert xmatch permission table"; goto fail; } @@ -926,11 +931,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) profile->path_flags = PATH_MEDIATE_DELETED; info = "failed to unpack profile capabilities"; - if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL)) + if (!unpack_u32(e, &(rules->caps.allow.cap[0]), NULL)) goto fail; - if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL)) + if (!unpack_u32(e, &(rules->caps.audit.cap[0]), NULL)) goto fail; - if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL)) + if (!unpack_u32(e, &(rules->caps.quiet.cap[0]), NULL)) goto fail; if (!unpack_u32(e, &tmpcap.cap[0], NULL)) goto fail; @@ -938,11 +943,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) info = "failed to unpack upper profile capabilities"; if (unpack_nameX(e, AA_STRUCT, "caps64")) { /* optional upper half of 64 bit caps */ - if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL)) + if (!unpack_u32(e, &(rules->caps.allow.cap[1]), NULL)) goto fail; - if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL)) + if (!unpack_u32(e, &(rules->caps.audit.cap[1]), NULL)) goto fail; - if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL)) + if (!unpack_u32(e, &(rules->caps.quiet.cap[1]), NULL)) goto fail; if (!unpack_u32(e, &(tmpcap.cap[1]), NULL)) goto fail; @@ -953,9 +958,9 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) info = "failed to unpack extended profile capabilities"; if (unpack_nameX(e, AA_STRUCT, "capsx")) { /* optional extended caps mediation mask */ - if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL)) + if (!unpack_u32(e, &(rules->caps.extended.cap[0]), NULL)) goto fail; - if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL)) + if (!unpack_u32(e, &(rules->caps.extended.cap[1]), NULL)) goto fail; if (!unpack_nameX(e, AA_STRUCTEND, NULL)) goto fail; @@ -979,40 +984,41 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) if (unpack_nameX(e, AA_STRUCT, "policydb")) { /* generic policy dfa - optional and may be NULL */ info = "failed to unpack policydb"; - error = unpack_pdb(e, &profile->policy, true, false, &info); + error = unpack_pdb(e, &rules->policy, true, false, + &info); if (error) goto fail; /* Fixup: drop when we get rid of start array */ - if (aa_dfa_next(profile->policy.dfa, profile->policy.start[0], + if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0], AA_CLASS_FILE)) - profile->policy.start[AA_CLASS_FILE] = - aa_dfa_next(profile->policy.dfa, - profile->policy.start[0], + rules->policy.start[AA_CLASS_FILE] = + aa_dfa_next(rules->policy.dfa, + rules->policy.start[0], AA_CLASS_FILE); if (!unpack_nameX(e, AA_STRUCTEND, NULL)) goto fail; - if (aa_compat_map_policy(&profile->policy, e->version)) { + if (aa_compat_map_policy(&rules->policy, e->version)) { info = "failed to remap policydb permission table"; goto fail; } } else - profile->policy.dfa = aa_get_dfa(nulldfa); + rules->policy.dfa = aa_get_dfa(nulldfa); /* get file rules */ - error = unpack_pdb(e, &profile->file, false, true, &info); + error = unpack_pdb(e, &rules->file, false, true, &info); if (error) { goto fail; - } else if (profile->file.dfa) { - if (aa_compat_map_file(&profile->file)) { + } else if (rules->file.dfa) { + if (aa_compat_map_file(&rules->file)) { info = "failed to remap file permission table"; goto fail; } - } else if (profile->policy.dfa && - profile->policy.start[AA_CLASS_FILE]) { - profile->file.dfa = aa_get_dfa(profile->policy.dfa); - profile->file.start[AA_CLASS_FILE] = profile->policy.start[AA_CLASS_FILE]; + } else if (rules->policy.dfa && + rules->policy.start[AA_CLASS_FILE]) { + rules->file.dfa = aa_get_dfa(rules->policy.dfa); + rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE]; } else - profile->file.dfa = aa_get_dfa(nulldfa); + rules->file.dfa = aa_get_dfa(nulldfa); if (unpack_nameX(e, AA_STRUCT, "data")) { info = "out of memory"; @@ -1202,28 +1208,28 @@ static bool verify_perms(struct aa_policydb *pdb) */ static int verify_profile(struct aa_profile *profile) { - if ((profile->file.dfa && - !verify_dfa_xindex(profile->file.dfa, - profile->file.trans.size)) || - (profile->policy.dfa && - !verify_dfa_xindex(profile->policy.dfa, - profile->policy.trans.size))) { + if ((profile->rules.file.dfa && + !verify_dfa_xindex(profile->rules.file.dfa, + profile->rules.file.trans.size)) || + (profile->rules.policy.dfa && + !verify_dfa_xindex(profile->rules.policy.dfa, + profile->rules.policy.trans.size))) { audit_iface(profile, NULL, NULL, "Unpack: Invalid named transition", NULL, -EPROTO); return -EPROTO; } - if (!verify_perms(&profile->file)) { + if (!verify_perms(&profile->rules.file)) { audit_iface(profile, NULL, NULL, "Unpack: Invalid perm index", NULL, -EPROTO); return -EPROTO; } - if (!verify_perms(&profile->policy)) { + if (!verify_perms(&profile->rules.policy)) { audit_iface(profile, NULL, NULL, "Unpack: Invalid perm index", NULL, -EPROTO); return -EPROTO; } - if (!verify_perms(&profile->xmatch)) { + if (!verify_perms(&profile->attach.xmatch)) { audit_iface(profile, NULL, NULL, "Unpack: Invalid perm index", NULL, -EPROTO); return -EPROTO; diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index cc018469e22d..f28026804d13 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -82,10 +82,11 @@ int aa_map_resource(int resource) static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, struct rlimit *new_rlim) { + struct aa_ruleset *rules = &profile->rules; int e = 0; - if (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > - profile->rlimits.limits[resource].rlim_max) + if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max > + rules->rlimits.limits[resource].rlim_max) e = -EACCES; return audit_resource(profile, resource, new_rlim->rlim_max, NULL, NULL, e); @@ -153,12 +154,12 @@ void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l) * to the lesser of the tasks hard limit and the init tasks soft limit */ label_for_each_confined(i, old_l, old) { - if (old->rlimits.mask) { + if (old->rules.rlimits.mask) { int j; for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) { - if (old->rlimits.mask & mask) { + if (old->rules.rlimits.mask & mask) { rlim = current->signal->rlim + j; initrlim = init_task.signal->rlim + j; rlim->rlim_cur = min(rlim->rlim_max, @@ -172,15 +173,15 @@ void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l) label_for_each_confined(i, new_l, new) { int j; - if (!new->rlimits.mask) + if (!new->rules.rlimits.mask) continue; for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) { - if (!(new->rlimits.mask & mask)) + if (!(new->rules.rlimits.mask & mask)) continue; rlim = current->signal->rlim + j; rlim->rlim_max = min(rlim->rlim_max, - new->rlimits.limits[j].rlim_max); + new->rules.rlimits.limits[j].rlim_max); /* soft limit should not exceed hard limit */ rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max); } diff --git a/security/apparmor/task.c b/security/apparmor/task.c index b19900f85c14..7e64fba42ca3 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -223,7 +223,7 @@ static void audit_ptrace_cb(struct audit_buffer *ab, void *va) FLAGS_NONE, GFP_ATOMIC); } -/* assumes check for PROFILE_MEDIATES is already done */ +/* assumes check for RULE_MEDIATES is already done */ /* TODO: conditionals */ static int profile_ptrace_perm(struct aa_profile *profile, struct aa_label *peer, u32 request, @@ -232,8 +232,8 @@ static int profile_ptrace_perm(struct aa_profile *profile, struct aa_perms perms = { }; aad(sa)->peer = peer; - aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, - &perms); + aa_profile_match_label(profile, &profile->rules, peer, + AA_CLASS_PTRACE, request, &perms); aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); } @@ -243,7 +243,7 @@ static int profile_tracee_perm(struct aa_profile *tracee, struct common_audit_data *sa) { if (profile_unconfined(tracee) || unconfined(tracer) || - !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) + !RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE)) return 0; return profile_ptrace_perm(tracee, tracer, request, sa); @@ -256,7 +256,7 @@ static int profile_tracer_perm(struct aa_profile *tracer, if (profile_unconfined(tracer)) return 0; - if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) + if (RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE)) return profile_ptrace_perm(tracer, tracee, request, sa); /* profile uses the old style capability check for ptrace */