diff options
author | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2015-11-19 12:39:22 -0500 |
---|---|---|
committer | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2016-02-21 09:03:44 -0500 |
commit | e40ba6d56b41754b37b995dbc8035b2b3a6afd8a (patch) | |
tree | 0bbc573dde5374e434d6acd883b330f92645bfe2 /drivers/base | |
parent | 09596b94f7d28595602482e69ed954deab707437 (diff) |
firmware: replace call to fw_read_file_contents() with kernel version
Replace the fw_read_file_contents with kernel_file_read_from_path().
Although none of the upstreamed LSMs define a kernel_fw_from_file hook,
IMA is called by the security function to prevent unsigned firmware from
being loaded and to measure/appraise signed firmware, based on policy.
Instead of reading the firmware twice, once for measuring/appraising the
firmware and again for reading the firmware contents into memory, the
kernel_post_read_file() security hook calculates the file hash based on
the in memory file buffer. The firmware is read once.
This patch removes the LSM kernel_fw_from_file() hook and security call.
Changelog v4+:
- revert dropped buf->size assignment - reported by Sergey Senozhatsky
v3:
- remove kernel_fw_from_file hook
- use kernel_file_read_from_path() - requested by Luis
v2:
- reordered and squashed firmware patches
- fix MAX firmware size (Kees Cook)
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Acked-by: Kees Cook <keescook@chromium.org>
Acked-by: Luis R. Rodriguez <mcgrof@kernel.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/firmware_class.c | 52 |
1 files changed, 10 insertions, 42 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index c743a2f18c33..a414008ea64c 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -23,6 +23,7 @@ #include <linux/sched.h> #include <linux/file.h> #include <linux/list.h> +#include <linux/fs.h> #include <linux/async.h> #include <linux/pm.h> #include <linux/suspend.h> @@ -291,37 +292,6 @@ static const char * const fw_path[] = { module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); -static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf) -{ - int size; - char *buf; - int rc; - - if (!S_ISREG(file_inode(file)->i_mode)) - return -EINVAL; - size = i_size_read(file_inode(file)); - if (size <= 0) - return -EINVAL; - buf = vmalloc(size); - if (!buf) - return -ENOMEM; - rc = kernel_read(file, 0, buf, size); - if (rc != size) { - if (rc > 0) - rc = -EIO; - goto fail; - } - rc = security_kernel_fw_from_file(file, buf, size); - if (rc) - goto fail; - fw_buf->data = buf; - fw_buf->size = size; - return 0; -fail: - vfree(buf); - return rc; -} - static void fw_finish_direct_load(struct device *device, struct firmware_buf *buf) { @@ -334,6 +304,7 @@ static void fw_finish_direct_load(struct device *device, static int fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) { + loff_t size; int i, len; int rc = -ENOENT; char *path; @@ -343,8 +314,6 @@ static int fw_get_filesystem_firmware(struct device *device, return -ENOMEM; for (i = 0; i < ARRAY_SIZE(fw_path); i++) { - struct file *file; - /* skip the unset customized path */ if (!fw_path[i][0]) continue; @@ -356,18 +325,16 @@ static int fw_get_filesystem_firmware(struct device *device, break; } - file = filp_open(path, O_RDONLY, 0); - if (IS_ERR(file)) - continue; - rc = fw_read_file_contents(file, buf); - fput(file); + buf->size = 0; + rc = kernel_read_file_from_path(path, &buf->data, &size, + INT_MAX, READING_FIRMWARE); if (rc) { dev_warn(device, "loading %s failed with error %d\n", path, rc); continue; } - dev_dbg(device, "direct-loading %s\n", - buf->fw_id); + dev_dbg(device, "direct-loading %s\n", buf->fw_id); + buf->size = size; fw_finish_direct_load(device, buf); break; } @@ -689,8 +656,9 @@ static ssize_t firmware_loading_store(struct device *dev, dev_err(dev, "%s: map pages failed\n", __func__); else - rc = security_kernel_fw_from_file(NULL, - fw_buf->data, fw_buf->size); + rc = security_kernel_post_read_file(NULL, + fw_buf->data, fw_buf->size, + READING_FIRMWARE); /* * Same logic as fw_load_abort, only the DONE bit |