diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/digsig.c | 8 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 10 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 73 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 1 | ||||
-rw-r--r-- | security/loadpin/loadpin.c | 17 | ||||
-rw-r--r-- | security/security.c | 28 | ||||
-rw-r--r-- | security/selinux/hooks.c | 8 |
7 files changed, 110 insertions, 35 deletions
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index e9cbadade74b..0f518dcfde05 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -10,6 +10,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/cred.h> +#include <linux/kernel_read_file.h> #include <linux/key-type.h> #include <linux/digsig.h> #include <linux/vmalloc.h> @@ -169,17 +170,18 @@ int __init integrity_add_key(const unsigned int id, const void *data, int __init integrity_load_x509(const unsigned int id, const char *path) { - void *data; - loff_t size; + void *data = NULL; + size_t size; int rc; key_perm_t perm; - rc = kernel_read_file_from_path(path, &data, &size, 0, + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, READING_X509_CERTIFICATE); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); return rc; } + size = rc; perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index e3fcad871861..ea8ff8a07b36 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -13,6 +13,7 @@ */ #include <linux/fcntl.h> +#include <linux/kernel_read_file.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/seq_file.h> @@ -272,9 +273,9 @@ static const struct file_operations ima_ascii_measurements_ops = { static ssize_t ima_read_policy(char *path) { - void *data; + void *data = NULL; char *datap; - loff_t size; + size_t size; int rc, pathlen = strlen(path); char *p; @@ -283,11 +284,14 @@ static ssize_t ima_read_policy(char *path) datap = path; strsep(&datap, "\n"); - rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY); + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, + READING_POLICY); if (rc < 0) { pr_err("Unable to open file: %s (%d)", path, rc); return rc; } + size = rc; + rc = 0; datap = data; while (size > 0 && (p = strsep(&datap, "\n"))) { diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 8a91711ca79b..82c9d62bcb11 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/file.h> #include <linux/binfmts.h> +#include <linux/kernel_read_file.h> #include <linux/mount.h> #include <linux/mman.h> #include <linux/slab.h> @@ -601,6 +602,7 @@ void ima_post_path_mknod(struct dentry *dentry) * ima_read_file - pre-measure/appraise hook decision based on policy * @file: pointer to the file to be measured/appraised/audit * @read_id: caller identifier + * @contents: whether a subsequent call will be made to ima_post_read_file() * * Permit reading a file based on policy. The policy rules are written * in terms of the policy identifier. Appraising the integrity of @@ -608,22 +610,37 @@ void ima_post_path_mknod(struct dentry *dentry) * * For permission return 0, otherwise return -EACCES. */ -int ima_read_file(struct file *file, enum kernel_read_file_id read_id) +int ima_read_file(struct file *file, enum kernel_read_file_id read_id, + bool contents) { + enum ima_hooks func; + u32 secid; + /* - * READING_FIRMWARE_PREALLOC_BUFFER - * * Do devices using pre-allocated memory run the risk of the * firmware being accessible to the device prior to the completion * of IMA's signature verification any more than when using two - * buffers? + * buffers? It may be desirable to include the buffer address + * in this API and walk all the dma_map_single() mappings to check. */ - return 0; + + /* + * There will be a call made to ima_post_read_file() with + * a filled buffer, so we don't need to perform an extra + * read early here. + */ + if (contents) + return 0; + + /* Read entire file for all partial reads. */ + func = read_idmap[read_id] ?: FILE_CHECK; + security_task_getsecid(current, &secid); + return process_measurement(file, current_cred(), secid, NULL, + 0, MAY_READ, func); } const int read_idmap[READING_MAX_ID] = { [READING_FIRMWARE] = FIRMWARE_CHECK, - [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, [READING_MODULE] = MODULE_CHECK, [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, @@ -649,15 +666,6 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, enum ima_hooks func; u32 secid; - if (!file && read_id == READING_FIRMWARE) { - if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && - (ima_appraise & IMA_APPRAISE_ENFORCE)) { - pr_err("Prevent firmware loading_store.\n"); - return -EACCES; /* INTEGRITY_UNKNOWN */ - } - return 0; - } - /* permit signed certs */ if (!file && read_id == READING_X509_CERTIFICATE) return 0; @@ -677,6 +685,8 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, /** * ima_load_data - appraise decision based on policy * @id: kernel load data caller identifier + * @contents: whether the full contents will be available in a later + * call to ima_post_load_data(). * * Callers of this LSM hook can not measure, appraise, or audit the * data provided by userspace. Enforce policy rules requring a file @@ -684,7 +694,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, * * For permission return 0, otherwise return -EACCES. */ -int ima_load_data(enum kernel_load_data_id id) +int ima_load_data(enum kernel_load_data_id id, bool contents) { bool ima_enforce, sig_enforce; @@ -705,7 +715,7 @@ int ima_load_data(enum kernel_load_data_id id) } break; case LOADING_FIRMWARE: - if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE)) { + if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE) && !contents) { pr_err("Prevent firmware sysfs fallback loading.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */ } @@ -724,6 +734,35 @@ int ima_load_data(enum kernel_load_data_id id) return 0; } +/** + * ima_post_load_data - appraise decision based on policy + * @buf: pointer to in memory file contents + * @size: size of in memory file contents + * @id: kernel load data caller identifier + * @description: @id-specific description of contents + * + * Measure/appraise/audit in memory buffer based on policy. Policy rules + * are written in terms of a policy identifier. + * + * On success return 0. On integrity appraisal error, assuming the file + * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. + */ +int ima_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id load_id, + char *description) +{ + if (load_id == LOADING_FIRMWARE) { + if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && + (ima_appraise & IMA_APPRAISE_ENFORCE)) { + pr_err("Prevent firmware loading_store.\n"); + return -EACCES; /* INTEGRITY_UNKNOWN */ + } + return 0; + } + + return 0; +} + /* * process_buffer_measurement - Measure the buffer to ima log. * @inode: inode associated with the object being measured (NULL for KEY_CHECK) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index b4de33074b37..3b0b43e18ecf 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -9,6 +9,7 @@ #include <linux/init.h> #include <linux/list.h> +#include <linux/kernel_read_file.h> #include <linux/fs.h> #include <linux/security.h> #include <linux/magic.h> diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 670a1aebb8a1..b12f7d986b1e 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/fs.h> +#include <linux/kernel_read_file.h> #include <linux/lsm_hooks.h> #include <linux/mount.h> #include <linux/blkdev.h> @@ -117,11 +118,21 @@ static void loadpin_sb_free_security(struct super_block *mnt_sb) } } -static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) +static int loadpin_read_file(struct file *file, enum kernel_read_file_id id, + bool contents) { struct super_block *load_root; const char *origin = kernel_read_file_id_str(id); + /* + * If we will not know that we'll be seeing the full contents + * then we cannot trust a load will be complete and unchanged + * off disk. Treat all contents=false hooks as if there were + * no associated file struct. + */ + if (!contents) + file = NULL; + /* If the file id is excluded, ignore the pinning. */ if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && ignore_read_file_id[id]) { @@ -176,9 +187,9 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) return 0; } -static int loadpin_load_data(enum kernel_load_data_id id) +static int loadpin_load_data(enum kernel_load_data_id id, bool contents) { - return loadpin_read_file(NULL, (enum kernel_read_file_id) id); + return loadpin_read_file(NULL, (enum kernel_read_file_id) id, contents); } static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = { diff --git a/security/security.c b/security/security.c index 70a7ad357bc6..a28045dc9e7f 100644 --- a/security/security.c +++ b/security/security.c @@ -16,6 +16,7 @@ #include <linux/export.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/kernel_read_file.h> #include <linux/lsm_hooks.h> #include <linux/integrity.h> #include <linux/ima.h> @@ -1671,14 +1672,15 @@ int security_kernel_module_request(char *kmod_name) return integrity_kernel_module_request(kmod_name); } -int security_kernel_read_file(struct file *file, enum kernel_read_file_id id) +int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, + bool contents) { int ret; - ret = call_int_hook(kernel_read_file, 0, file, id); + ret = call_int_hook(kernel_read_file, 0, file, id, contents); if (ret) return ret; - return ima_read_file(file, id); + return ima_read_file(file, id, contents); } EXPORT_SYMBOL_GPL(security_kernel_read_file); @@ -1694,17 +1696,31 @@ int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, } EXPORT_SYMBOL_GPL(security_kernel_post_read_file); -int security_kernel_load_data(enum kernel_load_data_id id) +int security_kernel_load_data(enum kernel_load_data_id id, bool contents) { int ret; - ret = call_int_hook(kernel_load_data, 0, id); + ret = call_int_hook(kernel_load_data, 0, id, contents); if (ret) return ret; - return ima_load_data(id); + return ima_load_data(id, contents); } EXPORT_SYMBOL_GPL(security_kernel_load_data); +int security_kernel_post_load_data(char *buf, loff_t size, + enum kernel_load_data_id id, + char *description) +{ + int ret; + + ret = call_int_hook(kernel_post_load_data, 0, buf, size, id, + description); + if (ret) + return ret; + return ima_post_load_data(buf, size, id, description); +} +EXPORT_SYMBOL_GPL(security_kernel_post_load_data); + int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2dabd58b126a..6b1826fc3658 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -24,6 +24,7 @@ #include <linux/init.h> #include <linux/kd.h> #include <linux/kernel.h> +#include <linux/kernel_read_file.h> #include <linux/tracehook.h> #include <linux/errno.h> #include <linux/sched/signal.h> @@ -4005,13 +4006,14 @@ static int selinux_kernel_module_from_file(struct file *file) } static int selinux_kernel_read_file(struct file *file, - enum kernel_read_file_id id) + enum kernel_read_file_id id, + bool contents) { int rc = 0; switch (id) { case READING_MODULE: - rc = selinux_kernel_module_from_file(file); + rc = selinux_kernel_module_from_file(contents ? file : NULL); break; default: break; @@ -4020,7 +4022,7 @@ static int selinux_kernel_read_file(struct file *file, return rc; } -static int selinux_kernel_load_data(enum kernel_load_data_id id) +static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents) { int rc = 0; |