firmware_class: perform new LSM checks

This attaches LSM hooks to the existing firmware loading interfaces:
filesystem-found firmware and demand-loaded blobs. On errors, loads
are aborted and the failure code is returned to userspace.

Signed-off-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Kees Cook 2014-02-25 13:06:00 -08:00
parent 13752fe2d7
commit 6593d9245b
1 changed files with 26 additions and 4 deletions

View File

@ -28,6 +28,7 @@
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/reboot.h>
#include <linux/security.h>
#include <generated/utsrelease.h>
@ -308,12 +309,17 @@ static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
if (rc != size) {
if (rc > 0)
rc = -EIO;
vfree(buf);
return rc;
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 int fw_get_filesystem_firmware(struct device *device,
@ -617,6 +623,7 @@ static ssize_t firmware_loading_store(struct device *dev,
{
struct firmware_priv *fw_priv = to_firmware_priv(dev);
struct firmware_buf *fw_buf;
ssize_t written = count;
int loading = simple_strtol(buf, NULL, 10);
int i;
@ -640,6 +647,8 @@ static ssize_t firmware_loading_store(struct device *dev,
break;
case 0:
if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
int rc;
set_bit(FW_STATUS_DONE, &fw_buf->status);
clear_bit(FW_STATUS_LOADING, &fw_buf->status);
@ -649,10 +658,23 @@ static ssize_t firmware_loading_store(struct device *dev,
* see the mapped 'buf->data' once the loading
* is completed.
* */
if (fw_map_pages_buf(fw_buf))
rc = fw_map_pages_buf(fw_buf);
if (rc)
dev_err(dev, "%s: map pages failed\n",
__func__);
else
rc = security_kernel_fw_from_file(NULL,
fw_buf->data, fw_buf->size);
/*
* Same logic as fw_load_abort, only the DONE bit
* is ignored and we set ABORT only on failure.
*/
list_del_init(&fw_buf->pending_list);
if (rc) {
set_bit(FW_STATUS_ABORT, &fw_buf->status);
written = rc;
}
complete_all(&fw_buf->completion);
break;
}
@ -666,7 +688,7 @@ static ssize_t firmware_loading_store(struct device *dev,
}
out:
mutex_unlock(&fw_lock);
return count;
return written;
}
static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);