ima: read firmware only once
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 <zohar@linux.vnet.ibm.com>
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{.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 @@
{.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 @@
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 @@
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 @@
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 @@
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 @@
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_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);