lkml.org 
[lkml]   [2021]   [Mar]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH v25 04/25] IMA: avoid label collisions with stacked LSMs
Date
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 securty 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.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
To: Mimi Zohar <zohar@linux.ibm.com>
To: linux-integrity@vger.kernel.org
---
Documentation/ABI/testing/ima_policy | 8 ++-
security/integrity/ima/ima_policy.c | 77 ++++++++++++++++++++--------
2 files changed, 62 insertions(+), 23 deletions(-)

diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index 070779e8d836..84dd19bc4344 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -25,7 +25,7 @@ Description:
base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
[euid=] [fowner=] [fsname=]]
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=] [keyrings=]
base:
@@ -117,6 +117,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
+ modules 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
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index ce4b8a70ca43..42a11f2c1068 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -79,8 +79,9 @@ struct ima_rule_entry {
bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */
bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */
int pcr;
+ int which_lsm; /* which of the rules to use */
struct {
- void *rules[LSMBLOB_ENTRIES]; /* LSM file metadata specific */
+ void *rule; /* LSM file metadata specific */
char *args_p; /* audit value */
int type; /* audit type */
} lsm[MAX_LSM_RULES];
@@ -92,17 +93,15 @@ struct ima_rule_entry {

/**
* ima_lsm_isset - Is a rule set for any of the active security modules
- * @rules: The set of IMA rules to check
+ * @entry: the rule entry to examine
+ * @lsm_rule: the specific rule type in question
*
- * If a rule is set for any LSM return true, otherwise return false.
+ * If a rule is set return true, otherwise return false.
*/
-static inline bool ima_lsm_isset(void *rules[])
+static inline bool ima_lsm_isset(struct ima_rule_entry *entry, int lsm_rule)
{
- int i;
-
- for (i = 0; i < LSMBLOB_ENTRIES; i++)
- if (rules[i])
- return true;
+ if (entry->lsm[lsm_rule].rule)
+ return true;
return false;
}

@@ -282,6 +281,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;
@@ -351,11 +364,10 @@ static void ima_free_rule_opt_list(struct ima_rule_opt_list *opt_list)
static void ima_lsm_free_rule(struct ima_rule_entry *entry)
{
int i;
- int r;

for (i = 0; i < MAX_LSM_RULES; i++) {
- for (r = 0; r < LSMBLOB_ENTRIES; r++)
- ima_filter_rule_free(entry->lsm[i].rules[r]);
+ if (entry->lsm[i].rule)
+ ima_filter_rule_free(entry->lsm[i].rule);
kfree(entry->lsm[i].args_p);
}
}
@@ -406,8 +418,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].rules[0]);
- if (!ima_lsm_isset(nentry->lsm[i].rules))
+ &nentry->lsm[i].rule);
+ if (!ima_lsm_isset(nentry, i))
pr_warn("rule for LSM \'%s\' is undefined\n",
nentry->lsm[i].args_p);
}
@@ -596,7 +608,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
int rc = 0;
u32 osid;

- if (!ima_lsm_isset(rule->lsm[i].rules)) {
+ if (!ima_lsm_isset(rule, i)) {
if (!rule->lsm[i].args_p)
continue;
else
@@ -609,14 +621,14 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
security_inode_getsecid(inode, &osid);
rc = ima_filter_rule_match(osid, rule->lsm[i].type,
Audit_equal,
- rule->lsm[i].rules);
+ 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,
Audit_equal,
- rule->lsm[i].rules);
+ rule->lsm[i].rule);
default:
break;
}
@@ -964,7 +976,7 @@ enum {
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
Opt_appraise_type, Opt_appraise_flag,
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 = {
@@ -1002,6 +1014,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}
};

@@ -1010,7 +1023,7 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
{
int result;

- if (ima_lsm_isset(entry->lsm[lsm_rule].rules))
+ if (ima_lsm_isset(entry, lsm_rule))
return -EINVAL;

entry->lsm[lsm_rule].args_p = match_strdup(args);
@@ -1020,8 +1033,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].rules[0]);
- if (!ima_lsm_isset(entry->lsm[lsm_rule].rules)) {
+ &entry->lsm[lsm_rule].rule);
+ if (!ima_lsm_isset(entry, lsm_rule)) {
pr_warn("rule for LSM \'%s\' is undefined\n",
entry->lsm[lsm_rule].args_p);

@@ -1559,6 +1572,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_lsm = result;
+ result = 0;
+ break;
case Opt_err:
ima_log_string(ab, "UNKNOWN", p);
result = -EINVAL;
@@ -1595,6 +1621,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;
@@ -1612,6 +1639,9 @@ ssize_t ima_parse_add_rule(char *rule)

INIT_LIST_HEAD(&entry->list);

+ for (i = 0; i < MAX_LSM_RULES; i++)
+ entry->which_lsm = ima_rules_lsm;
+
result = ima_parse_rule(p, entry);
if (result) {
ima_free_rule(entry);
@@ -1828,7 +1858,7 @@ int ima_policy_show(struct seq_file *m, void *v)
}

for (i = 0; i < MAX_LSM_RULES; i++) {
- if (ima_lsm_isset(entry->lsm[i].rules)) {
+ if (ima_lsm_isset(entry, i)) {
switch (i) {
case LSM_OBJ_USER:
seq_printf(m, pt(Opt_obj_user),
@@ -1870,6 +1900,9 @@ 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_lsm >= 0)
+ seq_printf(m, pt(Opt_lsm),
+ lsm_slot_to_name(entry->which_lsm));
rcu_read_unlock();
seq_puts(m, "\n");
return 0;
--
2.29.2
\
 
 \ /
  Last update: 2021-03-09 15:49    [W:0.115 / U:0.980 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site