--- v31
+++ v26
@@ -1,284 +1,214 @@
-Integrity measurement may filter on security module information
-and needs to be clear in the case of multiple active security
-modules which applies. Provide a boot option ima_rules_lsm= to
-allow the user to specify an active security module to apply
-filters to. If not specified, use the first registered module
-that supports the audit_rule_match() LSM hook. Allow the user
-to specify in the IMA policy an lsm= option to specify the
-security module to use for a particular rule.
-
+Change the secid parameter of security_audit_rule_match
+to a lsmblob structure pointer. Pass the entry from the
+lsmblob structure for the approprite slot to the LSM hook.
+
+Change the users of security_audit_rule_match to use the
+lsmblob instead of a u32. The scaffolding function lsmblob_init()
+fills the blob with the value of the old secid, ensuring that
+it is available to the appropriate module hook. The sources of
+the secid, security_task_getsecid() and security_inode_getsecid(),
+will be converted to use the blob structure later in the series.
+At the point the use of lsmblob_init() is dropped.
+
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
+Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
+Cc: linux-audit@redhat.com
+Cc: linux-integrity@vger.kernel.org
To: Mimi Zohar <zohar@linux.ibm.com>
-To: linux-integrity@vger.kernel.org
---
- Documentation/ABI/testing/ima_policy | 8 ++++-
- include/linux/security.h | 14 ++++----
- security/integrity/ima/ima_policy.c | 51 ++++++++++++++++++++++++----
- security/security.c | 35 +++++++++++++++----
- 4 files changed, 89 insertions(+), 19 deletions(-)
-
-diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
-index 839fab811b18..64863e9d87ea 100644
---- a/Documentation/ABI/testing/ima_policy
-+++ b/Documentation/ABI/testing/ima_policy
-@@ -26,7 +26,7 @@ Description:
- [uid=] [euid=] [gid=] [egid=]
- [fowner=] [fgroup=]]
- lsm: [[subj_user=] [subj_role=] [subj_type=]
-- [obj_user=] [obj_role=] [obj_type=]]
-+ [obj_user=] [obj_role=] [obj_type=]] [lsm=]
- option: [[appraise_type=]] [template=] [permit_directio]
- [appraise_flag=] [appraise_algos=] [keyrings=]
- base:
-@@ -126,6 +126,12 @@ Description:
-
- measure subj_user=_ func=FILE_CHECK mask=MAY_READ
-
-+ It is possible to explicitly specify which security
-+ module a rule applies to using lsm=. If the security
-+ module specified is not active on the system the rule
-+ will be rejected. If lsm= is not specified the first
-+ security module registered on the system will be assumed.
-+
- Example of measure rules using alternate PCRs::
-
- measure func=KEXEC_KERNEL_CHECK pcr=4
+ include/linux/security.h | 7 ++++---
+ kernel/auditfilter.c | 6 ++++--
+ kernel/auditsc.c | 16 +++++++++++-----
+ security/integrity/ima/ima.h | 4 ++--
+ security/integrity/ima/ima_policy.c | 7 +++++--
+ security/security.c | 10 ++++++++--
+ 6 files changed, 34 insertions(+), 16 deletions(-)
+
diff --git a/include/linux/security.h b/include/linux/security.h
-index 1bc00edd3a32..9b853796bd4f 100644
+index ca9485105f00..916a0f606035 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
-@@ -1985,25 +1985,27 @@ static inline void security_audit_rule_free(struct audit_lsm_rules *lsmrules)
-
- #ifdef CONFIG_IMA_LSM_RULES
+@@ -1944,7 +1944,8 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
#ifdef CONFIG_SECURITY
--int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
--int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
--void ima_filter_rule_free(void *lsmrule);
-+int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
-+ int lsmslot);
-+int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
-+ int lsmslot);
-+void ima_filter_rule_free(void *lsmrule, int lsmslot);
+ int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
+ int security_audit_rule_known(struct audit_krule *krule);
+-int security_audit_rule_match(u32 secid, u32 field, u32 op, void **lsmrule);
++int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
++ void **lsmrule);
+ void security_audit_rule_free(void **lsmrule);
#else
-
- static inline int ima_filter_rule_init(u32 field, u32 op, char *rulestr,
-- void **lsmrule)
-+ void **lsmrule, int lsmslot)
- {
+@@ -1960,8 +1961,8 @@ static inline int security_audit_rule_known(struct audit_krule *krule)
return 0;
}
- static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
-- void *lsmrule)
-+ void *lsmrule, int lsmslot)
+-static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
+- void **lsmrule)
++static inline int security_audit_rule_match(struct lsmblob *blob, u32 field,
++ u32 op, void **lsmrule)
{
return 0;
}
-
--static inline void ima_filter_rule_free(void *lsmrule)
-+static inline void ima_filter_rule_free(void *lsmrule, int lsmslot)
- { }
-
- #endif /* CONFIG_SECURITY */
+diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
+index a2340e81cfa7..6a04d762d272 100644
+--- a/kernel/auditfilter.c
++++ b/kernel/auditfilter.c
+@@ -1331,6 +1331,7 @@ int audit_filter(int msgtype, unsigned int listtype)
+ struct audit_field *f = &e->rule.fields[i];
+ pid_t pid;
+ u32 sid;
++ struct lsmblob blob;
+
+ switch (f->type) {
+ case AUDIT_PID:
+@@ -1362,8 +1363,9 @@ int audit_filter(int msgtype, unsigned int listtype)
+ if (f->lsm_isset) {
+ security_task_getsecid_subj(current,
+ &sid);
+- result = security_audit_rule_match(sid,
+- f->type, f->op,
++ lsmblob_init(&blob, sid);
++ result = security_audit_rule_match(
++ &blob, f->type, f->op,
+ f->lsm_rules);
+ }
+ break;
+diff --git a/kernel/auditsc.c b/kernel/auditsc.c
+index 392afe3e2fd6..71d894dcdc01 100644
+--- a/kernel/auditsc.c
++++ b/kernel/auditsc.c
+@@ -472,6 +472,7 @@ static int audit_filter_rules(struct task_struct *tsk,
+ const struct cred *cred;
+ int i, need_sid = 1;
+ u32 sid;
++ struct lsmblob blob;
+ unsigned int sessionid;
+
+ cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
+@@ -670,8 +671,10 @@ static int audit_filter_rules(struct task_struct *tsk,
+ security_task_getsecid_subj(tsk, &sid);
+ need_sid = 0;
+ }
+- result = security_audit_rule_match(sid, f->type,
+- f->op, f->lsm_rules);
++ lsmblob_init(&blob, sid);
++ result = security_audit_rule_match(&blob,
++ f->type, f->op,
++ f->lsm_rules);
+ }
+ break;
+ case AUDIT_OBJ_USER:
+@@ -684,15 +687,17 @@ static int audit_filter_rules(struct task_struct *tsk,
+ if (f->lsm_isset) {
+ /* Find files that match */
+ if (name) {
++ lsmblob_init(&blob, name->osid);
+ result = security_audit_rule_match(
+- name->osid,
++ &blob,
+ f->type,
+ f->op,
+ f->lsm_rules);
+ } else if (ctx) {
+ list_for_each_entry(n, &ctx->names_list, list) {
++ lsmblob_init(&blob, name->osid);
+ if (security_audit_rule_match(
+- n->osid,
++ &blob,
+ f->type,
+ f->op,
+ f->lsm_rules)) {
+@@ -704,7 +709,8 @@ static int audit_filter_rules(struct task_struct *tsk,
+ /* Find ipc objects that match */
+ if (!ctx || ctx->type != AUDIT_IPC)
+ break;
+- if (security_audit_rule_match(ctx->ipc.osid,
++ lsmblob_init(&blob, ctx->ipc.osid);
++ if (security_audit_rule_match(&blob,
+ f->type, f->op,
+ f->lsm_rules))
+ ++result;
+diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
+index f0e448ed1f9f..55f3bd4f0b01 100644
+--- a/security/integrity/ima/ima.h
++++ b/security/integrity/ima/ima.h
+@@ -433,8 +433,8 @@ static inline void ima_filter_rule_free(void *lsmrule)
+ {
+ }
+
+-static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
+- void *lsmrule)
++static inline int ima_filter_rule_match(struct lsmblob *blob, u32 field,
++ u32 op, void *lsmrule)
+ {
+ return -EINVAL;
+ }
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
-index 320ca80aacab..22952efcc0b0 100644
+index d804b9a0dd95..a05841e1012b 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
-@@ -90,6 +90,7 @@ struct ima_rule_entry {
- bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */
- int pcr;
- unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
-+ int which; /* which LSM rule applies to */
- struct {
- void *rule; /* LSM file metadata specific */
- char *args_p; /* audit value */
-@@ -286,6 +287,20 @@ static int __init default_appraise_policy_setup(char *str)
- }
- __setup("ima_appraise_tcb", default_appraise_policy_setup);
-
-+static int ima_rules_lsm __ro_after_init;
-+
-+static int __init ima_rules_lsm_init(char *str)
-+{
-+ ima_rules_lsm = lsm_name_to_slot(str);
-+ if (ima_rules_lsm < 0) {
-+ ima_rules_lsm = 0;
-+ pr_err("rule lsm \"%s\" not registered", str);
-+ }
-+
-+ return 1;
-+}
-+__setup("ima_rules_lsm=", ima_rules_lsm_init);
-+
- static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
- {
- struct ima_rule_opt_list *opt_list;
-@@ -357,7 +372,7 @@ static void ima_lsm_free_rule(struct ima_rule_entry *entry)
- int i;
-
+@@ -607,6 +607,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
for (i = 0; i < MAX_LSM_RULES; i++) {
-- ima_filter_rule_free(entry->lsm[i].rule);
-+ ima_filter_rule_free(entry->lsm[i].rule, entry->which);
- kfree(entry->lsm[i].args_p);
- }
- }
-@@ -408,7 +423,8 @@ static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry)
-
- ima_filter_rule_init(nentry->lsm[i].type, Audit_equal,
- nentry->lsm[i].args_p,
-- &nentry->lsm[i].rule);
-+ &nentry->lsm[i].rule,
-+ entry->which);
- if (!nentry->lsm[i].rule)
- pr_warn("rule for LSM \'%s\' is undefined\n",
- nentry->lsm[i].args_p);
-@@ -624,14 +640,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
+ int rc = 0;
+ u32 osid;
++ struct lsmblob lsmdata;
+
+ if (!ima_lsm_isset(rule, i)) {
+ if (!rule->lsm[i].args_p)
+@@ -619,14 +620,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
+ case LSM_OBJ_ROLE:
+ case LSM_OBJ_TYPE:
security_inode_getsecid(inode, &osid);
- rc = ima_filter_rule_match(osid, rule->lsm[i].type,
+- rc = ima_filter_rule_match(osid, rule->lsm[i].type,
++ lsmblob_init(&lsmdata, osid);
++ rc = ima_filter_rule_match(&lsmdata, rule->lsm[i].type,
Audit_equal,
-- rule->lsm[i].rule);
-+ rule->lsm[i].rule,
-+ rule->which);
+ rule->lsm[i].rule);
break;
case LSM_SUBJ_USER:
case LSM_SUBJ_ROLE:
case LSM_SUBJ_TYPE:
- rc = ima_filter_rule_match(secid, rule->lsm[i].type,
+- rc = ima_filter_rule_match(secid, rule->lsm[i].type,
++ lsmblob_init(&lsmdata, secid);
++ rc = ima_filter_rule_match(&lsmdata, rule->lsm[i].type,
Audit_equal,
-- rule->lsm[i].rule);
-+ rule->lsm[i].rule,
-+ rule->which);
+ rule->lsm[i].rule);
break;
- default:
- break;
-@@ -1026,7 +1044,7 @@ enum policy_opt {
- Opt_fowner_lt, Opt_fgroup_lt,
- Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
- Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
-- Opt_label, Opt_err
-+ Opt_lsm, Opt_label, Opt_err
- };
-
- static const match_table_t policy_tokens = {
-@@ -1074,6 +1092,7 @@ static const match_table_t policy_tokens = {
- {Opt_template, "template=%s"},
- {Opt_keyrings, "keyrings=%s"},
- {Opt_label, "label=%s"},
-+ {Opt_lsm, "lsm=%s"},
- {Opt_err, NULL}
- };
-
-@@ -1092,7 +1111,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
- entry->lsm[lsm_rule].type = audit_type;
- result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal,
- entry->lsm[lsm_rule].args_p,
-- &entry->lsm[lsm_rule].rule);
-+ &entry->lsm[lsm_rule].rule,
-+ entry->which);
- if (!entry->lsm[lsm_rule].rule) {
- pr_warn("rule for LSM \'%s\' is undefined\n",
- entry->lsm[lsm_rule].args_p);
-@@ -1781,6 +1801,19 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
- &(template_desc->num_fields));
- entry->template = template_desc;
- break;
-+ case Opt_lsm:
-+ result = lsm_name_to_slot(args[0].from);
-+ if (result == LSMBLOB_INVALID) {
-+ int i;
-+
-+ for (i = 0; i < MAX_LSM_RULES; i++)
-+ entry->lsm[i].args_p = NULL;
-+ result = -EINVAL;
-+ break;
-+ }
-+ entry->which = result;
-+ result = 0;
-+ break;
- case Opt_err:
- ima_log_string(ab, "UNKNOWN", p);
- result = -EINVAL;
-@@ -1817,6 +1850,7 @@ ssize_t ima_parse_add_rule(char *rule)
- struct ima_rule_entry *entry;
- ssize_t result, len;
- int audit_info = 0;
-+ int i;
-
- p = strsep(&rule, "\n");
- len = strlen(p) + 1;
-@@ -1834,6 +1868,9 @@ ssize_t ima_parse_add_rule(char *rule)
-
- INIT_LIST_HEAD(&entry->list);
-
-+ for (i = 0; i < MAX_LSM_RULES; i++)
-+ entry->which = ima_rules_lsm;
-+
- result = ima_parse_rule(p, entry);
- if (result) {
- ima_free_rule(entry);
-@@ -2151,6 +2188,8 @@ int ima_policy_show(struct seq_file *m, void *v)
- seq_puts(m, "appraise_flag=check_blacklist ");
- if (entry->flags & IMA_PERMIT_DIRECTIO)
- seq_puts(m, "permit_directio ");
-+ if (entry->which >= 0)
-+ seq_printf(m, pt(Opt_lsm), lsm_slot_to_name(entry->which));
- rcu_read_unlock();
- seq_puts(m, "\n");
- return 0;
diff --git a/security/security.c b/security/security.c
-index 9f3a467fb992..580ef0c40be7 100644
+index 9471bcecc052..a5793b4bf684 100644
--- a/security/security.c
+++ b/security/security.c
-@@ -2705,19 +2705,42 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op,
- * The integrity subsystem uses the same hooks as
- * the audit subsystem.
- */
--int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
-+int ima_filter_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
-+ int lsmslot)
- {
-- return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
-+ struct security_hook_list *hp;
-+
-+ hlist_for_each_entry(hp, &security_hook_heads.audit_rule_init, list)
-+ if (hp->lsmid->slot == lsmslot)
-+ return hp->hook.audit_rule_init(field, op, rulestr,
-+ lsmrule);
-+
-+ return 0;
- }
-
--void ima_filter_rule_free(void *lsmrule)
-+void ima_filter_rule_free(void *lsmrule, int lsmslot)
- {
-- call_void_hook(audit_rule_free, lsmrule);
-+ struct security_hook_list *hp;
-+
-+ hlist_for_each_entry(hp, &security_hook_heads.audit_rule_free, list) {
-+ if (hp->lsmid->slot == lsmslot) {
-+ hp->hook.audit_rule_free(lsmrule);
-+ return;
-+ }
-+ }
- }
-
--int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
-+int ima_filter_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
-+ int lsmslot)
- {
-- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
-+ struct security_hook_list *hp;
-+
-+ hlist_for_each_entry(hp, &security_hook_heads.audit_rule_match, list)
-+ if (hp->lsmid->slot == lsmslot)
-+ return hp->hook.audit_rule_match(secid, field, op,
-+ lsmrule);
-+
-+ return 0;
- }
- #endif /* CONFIG_IMA_LSM_RULES */
-
+@@ -2669,11 +2669,14 @@ void security_audit_rule_free(void **lsmrule)
+ hlist_for_each_entry(hp, &security_hook_heads.audit_rule_free, list) {
+ if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+ continue;
++ if (lsmrule[hp->lsmid->slot] == NULL)
++ continue;
+ hp->hook.audit_rule_free(lsmrule[hp->lsmid->slot]);
+ }
+ }
+
+-int security_audit_rule_match(u32 secid, u32 field, u32 op, void **lsmrule)
++int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
++ void **lsmrule)
+ {
+ struct security_hook_list *hp;
+ int rc;
+@@ -2681,7 +2684,10 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void **lsmrule)
+ hlist_for_each_entry(hp, &security_hook_heads.audit_rule_match, list) {
+ if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+ continue;
+- rc = hp->hook.audit_rule_match(secid, field, op,
++ if (lsmrule[hp->lsmid->slot] == NULL)
++ continue;
++ rc = hp->hook.audit_rule_match(blob->secid[hp->lsmid->slot],
++ field, op,
+ &lsmrule[hp->lsmid->slot]);
+ if (rc)
+ return rc;
--
-2.31.1
-
+2.29.2
+