Instead of reading the firmware twice, once for measuring/appraising
the firmware and again loading it, this patch reads the firmware
once.  This patch removes ima_fw_from_file() and replaces it with a
new hook named ima_read_file_contents().

As ima_read_file_contents() re-appraises the file each time it is
read, there's no need for the firmware specific cache status.  This
patch removes the firmware specific cache status and replaces it
with the generic read status.

Signed-off-by: Mimi Zohar <zo...@linux.vnet.ibm.com>
---
 drivers/base/firmware_class.c         |  7 ++++++-
 include/linux/ima.h                   | 10 +++++++---
 security/integrity/ima/ima.h          |  2 +-
 security/integrity/ima/ima_appraise.c |  5 -----
 security/integrity/ima/ima_main.c     | 10 ++++++----
 security/integrity/ima/ima_policy.c   | 11 +++++------
 security/integrity/integrity.h        | 11 ++++-------
 security/security.c                   |  6 +-----
 8 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8524450..54361ea 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -29,6 +29,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/reboot.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 
 #include <generated/utsrelease.h>
 
@@ -350,7 +351,11 @@ static int fw_get_filesystem_firmware(struct device 
*device,
                file = filp_open(path, O_RDONLY, 0);
                if (IS_ERR(file))
                        continue;
-               rc = fw_read_file_contents(file, buf);
+       
+               rc = ima_read_file_contents(file, FIRMWARE_CHECK,
+                                           &buf->data, &buf->size);
+               if (rc == -EOPNOTSUPP)
+                       rc = fw_read_file_contents(file, buf);
                fput(file);
                if (rc)
                        dev_warn(device, "firmware, attempted to load %s, but 
failed with error %d\n",
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 3f8d130..84a4ef3 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, IMA_MAX_READ_CHECK};
+enum ima_read_hooks { KEXEC_CHECK = 1, INITRAMFS_CHECK, FIRMWARE_CHECK, 
IMA_MAX_READ_CHECK};
 
 #ifdef CONFIG_IMA
 extern int ima_bprm_check(struct linux_binprm *bprm);
@@ -22,6 +22,8 @@ extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
 extern int ima_module_check(struct file *file);
 extern int ima_fw_from_file(struct file *file, char *buf, size_t size);
+extern int ima_read_file_contents(struct file *file, enum ima_read_hooks func,
+                                 void **buf, size_t *size);
 extern int ima_read_file_from_fd(int fd, enum ima_read_hooks func,
                                 void **buf, size_t *size);
 
@@ -51,9 +53,11 @@ static inline int ima_module_check(struct file *file)
        return 0;
 }
 
-static inline int ima_fw_from_file(struct file *file, char *buf, size_t size)
+static inline int ima_read_file_contents(struct file *file,
+                                        enum ima_read_hooks func,
+                                        void **buf, size_t *size)
 {
-       return 0;
+       return -EOPNOTSUPP;
 }
 
 static inline int ima_read_file_from_fd(int fd, enum ima_read_hooks func,
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 3337d14..f7e8a92 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -160,7 +160,7 @@ void ima_free_template_entry(struct ima_template_entry 
*entry);
 const char *ima_d_path(struct path *path, char **pathbuf);
 
 /* IMA policy related functions */
-enum ima_hooks { FILE_CHECK = IMA_MAX_READ_CHECK, MMAP_CHECK, BPRM_CHECK, 
MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR};
+enum ima_hooks { FILE_CHECK = IMA_MAX_READ_CHECK, MMAP_CHECK, BPRM_CHECK, 
MODULE_CHECK, POST_SETATTR};
 
 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                     int flags);
diff --git a/security/integrity/ima/ima_appraise.c 
b/security/integrity/ima/ima_appraise.c
index e58df45..b83049b 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -77,7 +77,6 @@ enum integrity_status ima_get_cache_status(struct 
integrity_iint_cache *iint,
        case MODULE_CHECK:
                return iint->ima_module_status;
        case FIRMWARE_CHECK:
-               return iint->ima_firmware_status;
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
                return iint->ima_read_status;
@@ -101,8 +100,6 @@ static void ima_set_cache_status(struct 
integrity_iint_cache *iint,
                iint->ima_module_status = status;
                break;
        case FIRMWARE_CHECK:
-               iint->ima_firmware_status = status;
-               break;
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
                iint->ima_read_status = status;
@@ -127,8 +124,6 @@ static void ima_cache_flags(struct integrity_iint_cache 
*iint, int func)
                iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED);
                break;
        case FIRMWARE_CHECK:
-               iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED);
-               break;
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
                iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED);
diff --git a/security/integrity/ima/ima_main.c 
b/security/integrity/ima/ima_main.c
index 40c80a2..452b5c4 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -364,15 +364,17 @@ static int ima_read_and_process_file(struct file *file, 
enum ima_hooks func,
        return ret;
 }
 
-int ima_fw_from_file(struct file *file, char *buf, size_t size)
+int ima_read_file_contents(struct file *file, enum ima_read_hooks func,
+                          void **buf, size_t *buf_len)
 {
        if (!file) {
-               if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
-                   (ima_appraise & IMA_APPRAISE_ENFORCE))
+               if ((func == FIRMWARE_CHECK) &&
+                   ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
+                    (ima_appraise & IMA_APPRAISE_ENFORCE)))
                        return -EACCES; /* INTEGRITY_UNKNOWN */
                return 0;
        }
-       return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, NULL, 0);
+       return ima_read_and_process_file(file, func, buf, buf_len);
 }
 
 int ima_read_file_from_fd(int fd, enum ima_read_hooks func,
diff --git a/security/integrity/ima/ima_policy.c 
b/security/integrity/ima/ima_policy.c
index a1f2eb3..98a711c 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -99,7 +99,7 @@ static struct ima_rule_entry original_measurement_rules[] = {
        {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
         .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID},
        {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
-       {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
+       {.action = MEASURE, .read_func = FIRMWARE_CHECK, .flags = IMA_FUNC},
 };
 
 static struct ima_rule_entry default_measurement_rules[] = {
@@ -112,7 +112,7 @@ static struct ima_rule_entry default_measurement_rules[] = {
        {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
         .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID},
        {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
-       {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
+       {.action = MEASURE, .read_func = FIRMWARE_CHECK, .flags = IMA_FUNC},
 };
 
 static struct ima_rule_entry default_appraise_rules[] = {
@@ -306,7 +306,6 @@ static int get_subaction(struct ima_rule_entry *rule, int 
func)
        case MODULE_CHECK:
                return IMA_MODULE_APPRAISE;
        case FIRMWARE_CHECK:
-               return IMA_FIRMWARE_APPRAISE;
        case KEXEC_CHECK:
        case INITRAMFS_CHECK:
                return IMA_READ_APPRAISE;
@@ -578,8 +577,6 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry 
*entry)
                                entry->func = FILE_CHECK;
                        else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
                                entry->func = MODULE_CHECK;
-                       else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0)
-                               entry->func = FIRMWARE_CHECK;
                        else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
                                || (strcmp(args[0].from, "MMAP_CHECK") == 0))
                                entry->func = MMAP_CHECK;
@@ -589,6 +586,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry 
*entry)
                                entry->read_func = KEXEC_CHECK;
                        else if (strcmp(args[0].from, "INITRAMFS_CHECK") == 0)
                                entry->read_func = INITRAMFS_CHECK;
+                       else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0)
+                               entry->read_func = FIRMWARE_CHECK;
                        else
                                result = -EINVAL;
                        if (!result)
@@ -745,7 +744,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry 
*entry)
                result = -EINVAL;
        else if (entry->func == MODULE_CHECK)
                ima_appraise |= IMA_APPRAISE_MODULES;
-       else if (entry->func == FIRMWARE_CHECK)
+       else if (entry->read_func == FIRMWARE_CHECK)
                ima_appraise |= IMA_APPRAISE_FIRMWARE;
        audit_log_format(ab, "res=%d", !result);
        audit_log_end(ab);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 9a0ea4c..152fb7c 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -47,16 +47,14 @@
 #define IMA_BPRM_APPRAISED     0x00002000
 #define IMA_MODULE_APPRAISE    0x00004000
 #define IMA_MODULE_APPRAISED   0x00008000
-#define IMA_FIRMWARE_APPRAISE  0x00010000
-#define IMA_FIRMWARE_APPRAISED 0x00020000
-#define IMA_READ_APPRAISE      0x00040000
-#define IMA_READ_APPRAISED     0x00080000
+#define IMA_READ_APPRAISE      0x00010000
+#define IMA_READ_APPRAISED     0x00020000
 #define IMA_APPRAISE_SUBMASK   (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
                                 IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \
-                                IMA_FIRMWARE_APPRAISE | IMA_READ_APPRAISE)
+                                IMA_READ_APPRAISE )
 #define IMA_APPRAISED_SUBMASK  (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
                                 IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \
-                                IMA_FIRMWARE_APPRAISED | IMA_READ_APPRAISED)
+                                IMA_READ_APPRAISED)
 
 enum evm_ima_xattr_type {
        IMA_XATTR_DIGEST = 0x01,
@@ -112,7 +110,6 @@ struct integrity_iint_cache {
        enum integrity_status ima_mmap_status:4;
        enum integrity_status ima_bprm_status:4;
        enum integrity_status ima_module_status:4;
-       enum integrity_status ima_firmware_status:4;
        enum integrity_status ima_read_status:4;
        enum integrity_status evm_status:4;
        struct ima_digest_data *ima_hash;
diff --git a/security/security.c b/security/security.c
index 46f405c..09a8395 100644
--- a/security/security.c
+++ b/security/security.c
@@ -886,12 +886,8 @@ int security_kernel_create_files_as(struct cred *new, 
struct inode *inode)
 
 int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
 {
-       int ret;
 
-       ret = call_int_hook(kernel_fw_from_file, 0, file, buf, size);
-       if (ret)
-               return ret;
-       return ima_fw_from_file(file, buf, size);
+       return call_int_hook(kernel_fw_from_file, 0, file, buf, size);
 }
 EXPORT_SYMBOL_GPL(security_kernel_fw_from_file);
 
-- 
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