Call ima_read_and_process_file() to measure and appraise the IMA policy.
This patch defines a new policy hook named POLICY_CHECK.

Signed-off-by: Mimi Zohar <zo...@linux.vnet.ibm.com>
---
 include/linux/ima.h                   |  2 +-
 security/integrity/digsig.c           |  2 +-
 security/integrity/iint.c             | 21 ++++++++++++++++-----
 security/integrity/ima/ima.h          |  1 +
 security/integrity/ima/ima_appraise.c |  3 +++
 security/integrity/ima/ima_fs.c       | 12 +++++++++---
 security/integrity/ima/ima_policy.c   | 15 +++++++++++++--
 security/integrity/integrity.h        |  4 +++-
 8 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 7bd4e07..27d960c 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -13,7 +13,7 @@
 #include <linux/fs.h>
 struct linux_binprm;
 
-enum ima_read_hooks { KEXEC_CHECK = 1, INITRAMFS_CHECK, FIRMWARE_CHECK, 
IMA_MAX_READ_CHECK};
+enum ima_read_hooks { KEXEC_CHECK = 1, INITRAMFS_CHECK, FIRMWARE_CHECK, 
POLICY_CHECK, IMA_MAX_READ_CHECK};
 
 #ifdef CONFIG_IMA
 extern int ima_bprm_check(struct linux_binprm *bprm);
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 8ef1511..e58a5f6 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -104,7 +104,7 @@ int __init integrity_load_x509(const unsigned int id, const 
char *path)
        if (!keyring[id])
                return -EINVAL;
 
-       rc = integrity_read_file(path, &data);
+       rc = integrity_read_file(path, &data, 0);
        if (rc < 0)
                return rc;
 
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 8a45576..4d149c9 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -205,7 +205,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
  * size, read entire file content to the buffer and closes the file
  *
  */
-int integrity_read_file(const char *path, char **data)
+int integrity_read_file(const char *path, char **data,
+                              enum ima_read_hooks read_func)
 {
        struct file *file;
        loff_t size;
@@ -222,6 +223,11 @@ int integrity_read_file(const char *path, char **data)
                return rc;
        }
 
+       if (!S_ISREG(file_inode(file)->i_mode)) {
+               rc = -EACCES;
+               goto out;
+       }
+
        size = i_size_read(file_inode(file));
        if (size <= 0)
                goto out;
@@ -232,13 +238,18 @@ int integrity_read_file(const char *path, char **data)
                goto out;
        }
 
-       rc = integrity_kernel_read(file, 0, buf, size);
+       rc = ima_read_and_process_file(file, read_func, buf, size);
+       if (rc == -EOPNOTSUPP) {
+               rc = integrity_kernel_read(file, 0, buf, size);
+               if (rc > 0 && rc != size)
+                       rc = -EIO;
+       }
        if (rc < 0)
                kfree(buf);
-       else if (rc != size)
-               rc = -EIO;
-       else
+       else {
+               rc = size;
                *data = buf;
+       }
 out:
        fput(file);
        return rc;
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 548b258..40a24c3 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -180,6 +180,7 @@ int ima_policy_show(struct seq_file *m, void *v);
 #define IMA_APPRAISE_LOG       0x04
 #define IMA_APPRAISE_MODULES   0x08
 #define IMA_APPRAISE_FIRMWARE  0x10
+#define IMA_APPRAISE_POLICY    0x20
 
 #ifdef CONFIG_IMA_APPRAISE
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
diff --git a/security/integrity/ima/ima_appraise.c 
b/security/integrity/ima/ima_appraise.c
index b83049b..1e1a759 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -79,6 +79,7 @@ enum integrity_status ima_get_cache_status(struct 
integrity_iint_cache *iint,
        case FIRMWARE_CHECK:
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
+       case POLICY_CHECK:
                return iint->ima_read_status;
        case FILE_CHECK:
        default:
@@ -102,6 +103,7 @@ static void ima_set_cache_status(struct 
integrity_iint_cache *iint,
        case FIRMWARE_CHECK:
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
+       case POLICY_CHECK:
                iint->ima_read_status = status;
                break;
        case FILE_CHECK:
@@ -126,6 +128,7 @@ static void ima_cache_flags(struct integrity_iint_cache 
*iint, int func)
        case FIRMWARE_CHECK:
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
+       case POLICY_CHECK:
                iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED);
                break;
        case FILE_CHECK:
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index f902b6b..fdc5326 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -268,13 +268,12 @@ static ssize_t ima_read_policy(char *path)
        datap = path;
        strsep(&datap, "\n");
 
-       rc = integrity_read_file(path, &data);
+       rc = integrity_read_file(path, &data, POLICY_CHECK);
        if (rc < 0)
                return rc;
 
        size = rc;
        datap = data;
-
        while (size > 0 && (p = strsep(&datap, "\n"))) {
                pr_debug("rule: %s\n", p);
                rc = ima_parse_add_rule(p);
@@ -324,7 +323,14 @@ static ssize_t ima_write_policy(struct file *file, const 
char __user *buf,
 
        if (data[0] == '/')
                result = ima_read_policy(data);
-       else
+       else if (ima_appraise & IMA_APPRAISE_POLICY) {
+               pr_err("IMA: signed policy required\n");
+               integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
+                                   "policy_update", "signed policy required",
+                                   1, 0);
+               if (ima_appraise & IMA_APPRAISE_ENFORCE)
+                       result = -EACCES;
+       } else
                result = ima_parse_add_rule(data);
 out:
        if (result < 0)
diff --git a/security/integrity/ima/ima_policy.c 
b/security/integrity/ima/ima_policy.c
index a65cb2a..87614a6 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -116,6 +116,7 @@ static struct ima_rule_entry default_measurement_rules[] = {
         .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID},
        {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
        {.action = MEASURE, .read_func = FIRMWARE_CHECK, .flags = IMA_FUNC},
+       {.action = MEASURE, .read_func = POLICY_CHECK, .flags = IMA_FUNC},
 };
 
 static struct ima_rule_entry default_appraise_rules[] = {
@@ -307,6 +308,7 @@ static int get_subaction(struct ima_rule_entry *rule, int 
func)
        case FIRMWARE_CHECK:
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
+       case POLICY_CHECK:
                return IMA_READ_APPRAISE;
        case FILE_CHECK:
        default:
@@ -613,6 +615,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry 
*entry)
                                entry->read_func = INITRAMFS_CHECK;
                        else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0)
                                entry->read_func = FIRMWARE_CHECK;
+                       else if (strcmp(args[0].from, "POLICY_CHECK") == 0)
+                               entry->read_func = POLICY_CHECK;
                        else
                                result = -EINVAL;
                        if (!result)
@@ -771,6 +775,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry 
*entry)
                temp_ima_appraise |= IMA_APPRAISE_MODULES;
        else if (entry->read_func == FIRMWARE_CHECK)
                temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
+       else if (entry->read_func == POLICY_CHECK)
+               temp_ima_appraise |= IMA_APPRAISE_POLICY;
        audit_log_format(ab, "res=%d", !result);
        audit_log_end(ab);
        return result;
@@ -857,7 +863,8 @@ static char *mask_tokens[] = {
 enum {
        func_file = 0, func_mmap, func_bprm,
        func_module, func_post,
-       func_kexec, func_initramfs, func_firmware
+       func_kexec, func_initramfs, func_firmware,
+       func_policy
 };
 
 static char *func_tokens[] = {
@@ -868,7 +875,8 @@ static char *func_tokens[] = {
        "POST_SETATTR",
        "KEXEC_CHECK",
        "INITRAMFS_CHECK",
-       "FIRMWARE_CHECK"
+       "FIRMWARE_CHECK",
+       "POLICY_CHECK"
 };
 
 void *ima_policy_start(struct seq_file *m, loff_t *pos)
@@ -956,6 +964,9 @@ int ima_policy_show(struct seq_file *m, void *v)
                        case FIRMWARE_CHECK:
                                seq_printf(m, pt(Opt_func), ft(func_firmware));
                                break;
+                       case POLICY_CHECK:
+                               seq_printf(m, pt(Opt_func), ft(func_policy));
+                               break;
                        default:
                                snprintf(tbuf, sizeof(tbuf), "%d", entry->func);
                                seq_printf(m, pt(Opt_func), tbuf);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index e6c37a4..a11d37c 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -15,6 +15,7 @@
 #include <linux/integrity.h>
 #include <crypto/sha.h>
 #include <linux/key.h>
+#include <linux/ima.h>
 
 /* iint action cache flags */
 #define IMA_MEASURE            0x00000001
@@ -122,7 +123,8 @@ struct integrity_iint_cache *integrity_iint_find(struct 
inode *inode);
 
 int integrity_kernel_read(struct file *file, loff_t offset,
                          char *addr, unsigned long count);
-int integrity_read_file(const char *path, char **data);
+int integrity_read_file(const char *path, char **data,
+                       enum ima_read_hooks read_hooks);
 
 #define INTEGRITY_KEYRING_EVM          0
 #define INTEGRITY_KEYRING_IMA          1
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to