From e79c26d04043b15de64f082d4da52e9fff7ca607 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 16 Apr 2018 11:23:58 -0700 Subject: [PATCH] apparmor: Add support for audit rule filtering This patch adds support to Apparmor for integrating with audit rule filtering. Right now it only handles SUBJ_ROLE, interpreting it as a single component of a label. This is sufficient to get Apparmor working with IMA's appraisal rules without any modifications on the IMA side. Signed-off-by: Matthew Garrett Signed-off-by: John Johansen --- security/apparmor/audit.c | 95 ++++++++++++++++++++++++++++++- security/apparmor/include/audit.h | 6 ++ security/apparmor/lsm.c | 7 +++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 8f9ecac7f8de..7ac7c8190cc4 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -19,7 +19,7 @@ #include "include/audit.h" #include "include/policy.h" #include "include/policy_ns.h" - +#include "include/secid.h" const char *const audit_mode_names[] = { "normal", @@ -163,3 +163,96 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, return aad(sa)->error; } + +struct aa_audit_rule { + char *profile; +}; + +void aa_audit_rule_free(void *vrule) +{ + struct aa_audit_rule *rule = vrule; + + if (rule) { + kfree(rule->profile); + kfree(rule); + } +} + +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) +{ + struct aa_audit_rule *rule; + + switch (field) { + case AUDIT_SUBJ_ROLE: + if (op != Audit_equal && op != Audit_not_equal) + return -EINVAL; + break; + default: + return -EINVAL; + } + + rule = kzalloc(sizeof(struct aa_audit_rule), GFP_KERNEL); + + if (!rule) + return -ENOMEM; + + rule->profile = kstrdup(rulestr, GFP_KERNEL); + + if (!rule->profile) { + kfree(rule); + return -ENOMEM; + } + + *vrule = rule; + + return 0; +} + +int aa_audit_rule_known(struct audit_krule *rule) +{ + int i; + + for (i = 0; i < rule->field_count; i++) { + struct audit_field *f = &rule->fields[i]; + + switch (f->type) { + case AUDIT_SUBJ_ROLE: + return 1; + } + } + + return 0; +} + +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, + struct audit_context *actx) +{ + struct aa_audit_rule *rule = vrule; + struct aa_label *label; + struct label_it i; + struct aa_profile *profile; + int found = 0; + + label = aa_secid_to_label(sid); + + if (!label) + return -ENOENT; + + label_for_each(i, label, profile) { + if (strcmp(rule->profile, profile->base.hname) == 0) { + found = 1; + break; + } + } + + switch (field) { + case AUDIT_SUBJ_ROLE: + switch (op) { + case Audit_equal: + return found; + case Audit_not_equal: + return !found; + } + } + return 0; +} diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 9c9be9c98c15..b8c8b1066b0a 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -189,4 +189,10 @@ static inline int complain_error(int error) return error; } +void aa_audit_rule_free(void *vrule); +int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule); +int aa_audit_rule_known(struct audit_krule *rule); +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, + struct audit_context *actx); + #endif /* __AA_AUDIT_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8299a5d13fee..10bf36aa477d 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1198,6 +1198,13 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), LSM_HOOK_INIT(task_kill, apparmor_task_kill), +#ifdef CONFIG_AUDIT + LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init), + LSM_HOOK_INIT(audit_rule_known, aa_audit_rule_known), + LSM_HOOK_INIT(audit_rule_match, aa_audit_rule_match), + LSM_HOOK_INIT(audit_rule_free, aa_audit_rule_free), +#endif + LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx), LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid), LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),