The first write on the ima policy file permits to override the default
policy defined with the ima_policy= boot parameter. This can be done
by adding the /etc/ima/ima-policy which allows loading the custom policy
during boot. It is also possible to load custom policy at runtime through
file operations:

cp custom_ima_policy /sys/kernel/security/ima/policy
cat custom_ima_policy > /sys/kernel/security/ima/policy

or by writing the absolute path of the file containing the custom policy:

echo /path/of/custom_ima_policy > /sys/kernel/security/ima/policy

In these cases, file signature can be necessary to load the policy
(func=POLICY_CHECK). Custom policy can also be set at runtime by directly
writing the policy stream on the ima policy file:

echo -e "measure func=BPRM_CHECK mask=MAY_EXEC\n" \
        "audit func=BPRM_CHECK mask=MAY_EXEC\n" \
     > /sys/kernel/security/ima/policy

In this case, there is no mechanism to verify the integrity of the new
policy.

Add a new entry in the ima measurements list containing the ascii custom
ima policy buffer when not verified at load time.

Signed-off-by: Enrico Bravi <enrico.br...@polito.it>
---
 security/integrity/ima/ima.h        |  3 ++
 security/integrity/ima/ima_fs.c     | 11 ++++
 security/integrity/ima/ima_policy.c | 81 ++++++++++++++++++++++++++++-
 3 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index c0d3b716d11f..27cba2e612a5 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -46,6 +46,8 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
 /* current content of the policy */
 extern int ima_policy_flag;
 
+extern bool override_ima_policy;
+
 /* bitset of digests algorithms allowed in the setxattr hook */
 extern atomic_t ima_setxattr_allowed_hash_algorithms;
 
@@ -414,6 +416,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
 void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
 void ima_policy_stop(struct seq_file *m, void *v);
 int ima_policy_show(struct seq_file *m, void *v);
+void ima_measure_override_policy(size_t file_len);
 
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE   0x01
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index e4a79a9b2d58..8c516de4aebe 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -309,6 +309,9 @@ static const struct file_operations 
ima_ascii_measurements_ops = {
        .release = seq_release,
 };
 
+static size_t text_policy_len;
+bool override_ima_policy;
+
 static ssize_t ima_read_policy(char *path)
 {
        void *data = NULL;
@@ -383,6 +386,7 @@ static ssize_t ima_write_policy(struct file *file, const 
char __user *buf,
                result = -EACCES;
        } else {
                result = ima_parse_add_rule(data);
+               text_policy_len += (result + 1);
        }
        mutex_unlock(&ima_write_mutex);
 out_free:
@@ -532,6 +536,10 @@ static int ima_release_policy(struct inode *inode, struct 
file *file)
        }
 
        ima_update_policy();
+       if (unlikely(override_ima_policy && text_policy_len)) {
+               ima_measure_override_policy(text_policy_len);
+               override_ima_policy = false;
+       }
 #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
        securityfs_remove(ima_policy);
        ima_policy = NULL;
@@ -558,6 +566,9 @@ int __init ima_fs_init(void)
        ascii_securityfs_measurement_lists = NULL;
        binary_securityfs_measurement_lists = NULL;
 
+       text_policy_len = 0;
+       override_ima_policy = false;
+
        ima_dir = securityfs_create_dir("ima", integrity_dir);
        if (IS_ERR(ima_dir))
                return PTR_ERR(ima_dir);
diff --git a/security/integrity/ima/ima_policy.c 
b/security/integrity/ima/ima_policy.c
index 21a8e54c383f..34753bce4668 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/rculist.h>
 #include <linux/seq_file.h>
+#include <linux/vmalloc.h>
 #include <linux/ima.h>
 
 #include "ima.h"
@@ -1044,6 +1045,8 @@ void ima_update_policy(void)
        if (ima_rules != (struct list_head __rcu *)policy) {
                ima_policy_flag = 0;
 
+               override_ima_policy = true;
+
                rcu_assign_pointer(ima_rules, policy);
                /*
                 * IMA architecture specific policy rules are specified
@@ -1982,7 +1985,6 @@ const char *const func_tokens[] = {
        __ima_hooks(__ima_hook_stringify)
 };
 
-#ifdef CONFIG_IMA_READ_POLICY
 enum {
        mask_exec = 0, mask_write, mask_read, mask_append
 };
@@ -1994,6 +1996,7 @@ static const char *const mask_tokens[] = {
        "^MAY_APPEND"
 };
 
+#ifdef CONFIG_IMA_READ_POLICY
 void *ima_policy_start(struct seq_file *m, loff_t *pos)
 {
        loff_t l = *pos;
@@ -2028,6 +2031,7 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t 
*pos)
 void ima_policy_stop(struct seq_file *m, void *v)
 {
 }
+#endif /* CONFIG_IMA_READ_POLICY */
 
 #define pt(token)      policy_tokens[token].pattern
 #define mt(token)      mask_tokens[token]
@@ -2276,7 +2280,6 @@ int ima_policy_show(struct seq_file *m, void *v)
        seq_puts(m, "\n");
        return 0;
 }
-#endif /* CONFIG_IMA_READ_POLICY */
 
 #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
 /*
@@ -2333,3 +2336,77 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
        return found;
 }
 #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */
+
+void ima_measure_override_policy(size_t file_len)
+{
+       struct ima_iint_cache iint = {};
+       const char event_name[] = "ima-policy-override";
+       struct ima_event_data event_data = {.iint = &iint,
+                                           .filename = event_name};
+       struct ima_max_digest_data hash;
+       struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
+                                               struct ima_digest_data, hdr);
+       static const char op[] = "measure_ima_policy_override";
+       struct ima_template_entry *entry = NULL;
+       static char *audit_cause = "ENOMEM";
+       struct ima_template_desc *template;
+       struct ima_rule_entry *rule_entry;
+       struct list_head *ima_rules_tmp;
+       struct seq_file file;
+       int result = -ENOMEM;
+       int violation = 0;
+
+       file.buf = vmalloc(file_len);
+       if (!file.buf)
+               goto out;
+
+       file.read_pos = 0;
+       file.size = file_len;
+       file.count = 0;
+
+       rcu_read_lock();
+       ima_rules_tmp = rcu_dereference(ima_rules);
+       list_for_each_entry_rcu(rule_entry, ima_rules_tmp, list) {
+               ima_policy_show(&file, rule_entry);
+       }
+       rcu_read_unlock();
+
+       event_data.buf = file.buf;
+       event_data.buf_len = file.count;
+
+       template = ima_template_desc_buf();
+       if (!template) {
+               audit_cause = "ima_template_desc_buf";
+               goto out_free;
+       }
+
+       iint.ima_hash = hash_hdr;
+       iint.ima_hash->algo = ima_hash_algo;
+       iint.ima_hash->length = hash_digest_size[ima_hash_algo];
+
+       result = ima_calc_buffer_hash(file.buf, file.count, iint.ima_hash);
+       if (result < 0) {
+               audit_cause = "hashing_error";
+               goto out_free;
+       }
+
+       result = ima_alloc_init_template(&event_data, &entry, template);
+       if (result < 0) {
+               audit_cause = "alloc_entry";
+               goto out_free;
+       }
+
+       result = ima_store_template(entry, violation, NULL, event_data.buf,
+                                   CONFIG_IMA_MEASURE_PCR_IDX);
+       if (result < 0) {
+               audit_cause = "store_entry";
+               ima_free_template_entry(entry);
+       }
+
+out_free:
+       kvfree(file.buf);
+out:
+       if (result < 0)
+               integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, event_name,
+                                   op, audit_cause, result, 1);
+}

base-commit: ffd294d346d185b70e28b1a28abe367bbfe53c04
-- 
2.47.1


Reply via email to