[PATCH 3/8] !!!! UNCOMPILED & UNTESTED !!!! ima: Move policy related variables into ima_namespace

From: Plummy McPlumbface
Date: Sat Dec 18 2021 - 06:19:55 EST


Move variables related to the IMA policy into the ima_namespace. This way
the IMA policy of an IMA namespace can be set and displayed using a
front-end like SecurityFS.

Implement ima_ns_from_file() to get the IMA namespace via the user
namespace of the SecurityFS superblock that a file belongs to.

To get the current ima_namespace use get_current_ns() when a function, that
is related to a policy rule, is called. In other cases where file attributes
are changed, use the init_ima_ns, since these functions are related to
IMA appraisal and changes to file attributes are only relevant to the
init_ima_ns until IMA namespaces also support IMA appraisal.

Signed-off-by: Plummy McPlumbface <plummy@mcblumbface.events>
---
security/integrity/ima/ima.h | 6 ++++
security/integrity/ima/ima_init_ima_ns.c | 4 +++
security/integrity/ima/ima_policy.c | 41 +++++++++++-------------
3 files changed, 29 insertions(+), 22 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 1febb618b982..a24cc4f7106a 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -117,6 +117,12 @@ struct ima_kexec_hdr {
};

struct ima_namespace {
+ struct list_head ima_default_rules;
+ /* ns's policy rules */
+ struct list_head ima_policy_rules;
+ struct list_head ima_temp_rules;
+ /* Pointer to ns's current policy */
+ struct list_head __rcu *ima_rules;
/* current content of the policy */
int ima_policy_flag;
} __randomize_layout;
diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c
index 56640881ce72..8647e1906374 100644
--- a/security/integrity/ima/ima_init_ima_ns.c
+++ b/security/integrity/ima/ima_init_ima_ns.c
@@ -15,6 +15,10 @@

int ima_init_namespace(struct ima_namespace *ns)
{
+ INIT_LIST_HEAD(&ns->ima_default_rules);
+ INIT_LIST_HEAD(&ns->ima_policy_rules);
+ INIT_LIST_HEAD(&ns->ima_temp_rules);
+ ns->ima_rules = (struct list_head __rcu *)(&ns->ima_default_rules);
ns->ima_policy_flag = 0;

return 0;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 835e5079bf9c..66d005be3577 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -232,11 +232,6 @@ static struct ima_rule_entry critical_data_rules[] __ro_after_init = {
/* An array of architecture specific rules */
static struct ima_rule_entry *arch_policy_entry __ro_after_init;

-static LIST_HEAD(ima_default_rules);
-static LIST_HEAD(ima_policy_rules);
-static LIST_HEAD(ima_temp_rules);
-static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules);
-
static int ima_policy __initdata;

static int __init default_measure_policy_setup(char *str)
@@ -458,7 +453,7 @@ static void ima_lsm_update_rules(struct ima_namespace *ns)
struct ima_rule_entry *entry, *e;
int result;

- list_for_each_entry_safe(entry, e, &ima_policy_rules, list) {
+ list_for_each_entry_safe(entry, e, &ns->ima_policy_rules, list) {
if (!ima_rule_contains_lsm_cond(entry))
continue;

@@ -705,7 +700,7 @@ int ima_match_policy(struct ima_namespace *ns,
*template_desc = ima_template_desc_current();

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {

if (!(entry->action & actmask))
@@ -770,7 +765,7 @@ void ima_update_policy_flags(struct ima_namespace *ns)
struct list_head *ima_rules_tmp;

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
/*
* SETXATTR_CHECK rules do not implement a full policy check
@@ -826,7 +821,7 @@ static void add_rules(struct ima_namespace *ns,
struct ima_rule_entry *entry;

if (policy_rule & IMA_DEFAULT_POLICY)
- list_add_tail(&entries[i].list, &ima_default_rules);
+ list_add_tail(&entries[i].list, &ns->ima_default_rules);

if (policy_rule & IMA_CUSTOM_POLICY) {
entry = kmemdup(&entries[i], sizeof(*entry),
@@ -834,7 +829,7 @@ static void add_rules(struct ima_namespace *ns,
if (!entry)
continue;

- list_add_tail(&entry->list, &ima_policy_rules);
+ list_add_tail(&entry->list, &ns->ima_policy_rules);
}
if (entries[i].action == APPRAISE) {
if (entries != build_appraise_rules)
@@ -978,7 +973,7 @@ void __init ima_init_policy(struct ima_namespace *ns)
/* Make sure we have a valid policy, at least containing some rules. */
int ima_check_policy(struct ima_namespace *ns)
{
- if (list_empty(&ima_temp_rules))
+ if (list_empty(&ns->ima_temp_rules))
return -EINVAL;
return 0;
}
@@ -996,14 +991,15 @@ int ima_check_policy(struct ima_namespace *ns)
*/
void ima_update_policy(struct ima_namespace *ns)
{
- struct list_head *policy = &ima_policy_rules;
+ struct list_head *policy = &ns->ima_policy_rules;

- list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu);
+ list_splice_tail_init_rcu(&ns->ima_temp_rules, policy,
+ synchronize_rcu);

- if (ima_rules != (struct list_head __rcu *)policy) {
+ if (ns->ima_rules != (struct list_head __rcu *)policy) {
ns->ima_policy_flag = 0;

- rcu_assign_pointer(ima_rules, policy);
+ rcu_assign_pointer(ns->ima_rules, policy);
/*
* IMA architecture specific policy rules are specified
* as strings and converted to an array of ima_entry_rules
@@ -1106,7 +1102,8 @@ static int ima_lsm_rule_init(struct ima_namespace *ns,
pr_warn("rule for LSM \'%s\' is undefined\n",
entry->lsm[lsm_rule].args_p);

- if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) {
+ if (ns->ima_rules ==
+ (struct list_head __rcu *)(&ns->ima_default_rules)) {
kfree(entry->lsm[lsm_rule].args_p);
entry->lsm[lsm_rule].args_p = NULL;
result = -EINVAL;
@@ -1854,7 +1851,7 @@ ssize_t ima_parse_add_rule(struct ima_namespace *ns, char *rule)
return result;
}

- list_add_tail(&entry->list, &ima_temp_rules);
+ list_add_tail(&entry->list, &ns->ima_temp_rules);

return len;
}
@@ -1871,7 +1868,7 @@ void ima_delete_rules(struct ima_namespace *ns)
struct ima_rule_entry *entry, *tmp;

temp_ima_appraise = 0;
- list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
+ list_for_each_entry_safe(entry, tmp, &ns->ima_temp_rules, list) {
list_del(&entry->list);
ima_free_rule(entry);
}
@@ -1903,7 +1900,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos)
struct list_head *ima_rules_tmp;

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
if (!l--) {
rcu_read_unlock();
@@ -1924,8 +1921,8 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
rcu_read_unlock();
(*pos)++;

- return (&entry->list == &ima_default_rules ||
- &entry->list == &ima_policy_rules) ? NULL : entry;
+ return (&entry->list == &ns->ima_default_rules ||
+ &entry->list == &ns->ima_policy_rules) ? NULL : entry;
}

void ima_policy_stop(struct seq_file *m, void *v)
@@ -2192,7 +2189,7 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
func = read_idmap[id] ?: FILE_CHECK;

rcu_read_lock();
- ima_rules_tmp = rcu_dereference(ima_rules);
+ ima_rules_tmp = rcu_dereference(ns->ima_rules);
list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
if (entry->action != APPRAISE)
continue;
--
2.30.2