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>
This commit is contained in:
Mimi Zohar 2015-11-19 12:39:22 -05:00
parent 09596b94f7
commit e40ba6d56b
7 changed files with 21 additions and 90 deletions

View file

@ -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