summaryrefslogtreecommitdiffstats
path: root/security/integrity/ima
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-07 15:40:37 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-07 15:40:37 -0700
commit00d535a386c071a06e111fd846f6beda445126a5 (patch)
treef0ebe350b705281ba9816d9e023c2442a2bc0304 /security/integrity/ima
parent289cf155d95df07ac1e692dfaa7036f10235c77c (diff)
parentb5c90a7526fe39164c2204f0404ce8f8ff21e522 (diff)
downloadlinux-stable-00d535a386c071a06e111fd846f6beda445126a5.tar.gz
linux-stable-00d535a386c071a06e111fd846f6beda445126a5.tar.bz2
linux-stable-00d535a386c071a06e111fd846f6beda445126a5.zip
Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull integrity updates from James Morris: "From Mimi: - add run time support for specifying additional security xattrs included in the security.evm HMAC/signature - some code clean up and bug fixes" * 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: EVM: unlock on error path in evm_read_xattrs() EVM: prevent array underflow in evm_write_xattrs() EVM: Fix null dereference on xattr when xattr fails to allocate EVM: fix memory leak of temporary buffer 'temp' IMA: use list_splice_tail_init_rcu() instead of its open coded variant ima: use match_string() helper ima: fix updating the ima_appraise flag ima: based on policy verify firmware signatures (pre-allocated buffer) ima: define a new policy condition based on the filesystem name EVM: Allow runtime modification of the set of verified xattrs EVM: turn evm_config_xattrnames into a list integrity: Add an integrity directory in securityfs ima: Remove unused variable ima_initialized ima: Unify logging ima: Reflect correct permissions for policy
Diffstat (limited to 'security/integrity/ima')
-rw-r--r--security/integrity/ima/ima.h1
-rw-r--r--security/integrity/ima/ima_fs.c18
-rw-r--r--security/integrity/ima/ima_kexec.c2
-rw-r--r--security/integrity/ima/ima_main.c19
-rw-r--r--security/integrity/ima/ima_policy.c70
-rw-r--r--security/integrity/ima/ima_template_lib.c2
6 files changed, 71 insertions, 41 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 35fe91aa1fc9..354bb5716ce3 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -53,7 +53,6 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
extern int ima_policy_flag;
/* set during initialization */
-extern int ima_initialized;
extern int ima_used_chip;
extern int ima_hash_algo;
extern int ima_appraise;
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index fa540c0469da..ae9d5c766a3c 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -15,6 +15,9 @@
* implemenents security file system for reporting
* current measurement list and IMA statistics
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fcntl.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -336,7 +339,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
if (data[0] == '/') {
result = ima_read_policy(data);
} else if (ima_appraise & IMA_APPRAISE_POLICY) {
- pr_err("IMA: signed policy file (specified as an absolute pathname) required\n");
+ pr_err("signed policy file (specified as an absolute pathname) required\n");
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
"policy_update", "signed policy required",
1, 0);
@@ -356,6 +359,7 @@ out:
}
static struct dentry *ima_dir;
+static struct dentry *ima_symlink;
static struct dentry *binary_runtime_measurements;
static struct dentry *ascii_runtime_measurements;
static struct dentry *runtime_measurements_count;
@@ -417,7 +421,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
valid_policy = 0;
}
- pr_info("IMA: policy update %s\n", cause);
+ pr_info("policy update %s\n", cause);
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
"policy_update", cause, !valid_policy, 0);
@@ -434,6 +438,8 @@ static int ima_release_policy(struct inode *inode, struct file *file)
ima_policy = NULL;
#elif defined(CONFIG_IMA_WRITE_POLICY)
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#elif defined(CONFIG_IMA_READ_POLICY)
+ inode->i_mode &= ~S_IWUSR;
#endif
return 0;
}
@@ -448,10 +454,15 @@ static const struct file_operations ima_measure_policy_ops = {
int __init ima_fs_init(void)
{
- ima_dir = securityfs_create_dir("ima", NULL);
+ ima_dir = securityfs_create_dir("ima", integrity_dir);
if (IS_ERR(ima_dir))
return -1;
+ ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
+ NULL);
+ if (IS_ERR(ima_symlink))
+ goto out;
+
binary_runtime_measurements =
securityfs_create_file("binary_runtime_measurements",
S_IRUSR | S_IRGRP, ima_dir, NULL,
@@ -491,6 +502,7 @@ out:
securityfs_remove(runtime_measurements_count);
securityfs_remove(ascii_runtime_measurements);
securityfs_remove(binary_runtime_measurements);
+ securityfs_remove(ima_symlink);
securityfs_remove(ima_dir);
securityfs_remove(ima_policy);
return -1;
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index e473eee913cb..16bd18747cfa 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -10,6 +10,8 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
#include <linux/kexec.h>
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 74d0bd7e76d7..dca44cf7838e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -32,8 +32,6 @@
#include "ima.h"
-int ima_initialized;
-
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise = IMA_APPRAISE_ENFORCE;
#else
@@ -61,14 +59,11 @@ static int __init hash_setup(char *str)
goto out;
}
- for (i = 0; i < HASH_ALGO__LAST; i++) {
- if (strcmp(str, hash_algo_name[i]) == 0) {
- ima_hash_algo = i;
- break;
- }
- }
- if (i == HASH_ALGO__LAST)
+ i = match_string(hash_algo_name, HASH_ALGO__LAST, str);
+ if (i < 0)
return 1;
+
+ ima_hash_algo = i;
out:
hash_setup_done = 1;
return 1;
@@ -449,6 +444,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
static 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,
@@ -517,10 +513,9 @@ static int __init init_ima(void)
error = ima_init();
}
- if (!error) {
- ima_initialized = 1;
+ if (!error)
ima_update_policy_flag();
- }
+
return error;
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index d89bebf85421..cdcc9a7b4e24 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -33,6 +33,7 @@
#define IMA_INMASK 0x0040
#define IMA_EUID 0x0080
#define IMA_PCR 0x0100
+#define IMA_FSNAME 0x0200
#define UNKNOWN 0
#define MEASURE 0x0001 /* same as IMA_MEASURE */
@@ -74,6 +75,7 @@ struct ima_rule_entry {
void *args_p; /* audit value */
int type; /* audit type */
} lsm[MAX_LSM_RULES];
+ char *fsname;
};
/*
@@ -273,6 +275,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
if ((rule->flags & IMA_FSMAGIC)
&& rule->fsmagic != inode->i_sb->s_magic)
return false;
+ if ((rule->flags & IMA_FSNAME)
+ && strcmp(rule->fsname, inode->i_sb->s_type->name))
+ return false;
if ((rule->flags & IMA_FSUUID) &&
!uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid))
return false;
@@ -435,6 +440,17 @@ void ima_update_policy_flag(void)
ima_policy_flag &= ~IMA_APPRAISE;
}
+static int ima_appraise_flag(enum ima_hooks func)
+{
+ if (func == MODULE_CHECK)
+ return IMA_APPRAISE_MODULES;
+ else if (func == FIRMWARE_CHECK)
+ return IMA_APPRAISE_FIRMWARE;
+ else if (func == POLICY_CHECK)
+ return IMA_APPRAISE_POLICY;
+ return 0;
+}
+
/**
* ima_init_policy - initialize the default measure rules.
*
@@ -473,9 +489,11 @@ void __init ima_init_policy(void)
* Insert the appraise rules requiring file signatures, prior to
* any other appraise rules.
*/
- for (i = 0; i < secure_boot_entries; i++)
- list_add_tail(&secure_boot_rules[i].list,
- &ima_default_rules);
+ for (i = 0; i < secure_boot_entries; i++) {
+ list_add_tail(&secure_boot_rules[i].list, &ima_default_rules);
+ temp_ima_appraise |=
+ ima_appraise_flag(secure_boot_rules[i].func);
+ }
for (i = 0; i < appraise_entries; i++) {
list_add_tail(&default_appraise_rules[i].list,
@@ -509,22 +527,9 @@ int ima_check_policy(void)
*/
void ima_update_policy(void)
{
- struct list_head *first, *last, *policy;
-
- /* append current policy with the new rules */
- first = (&ima_temp_rules)->next;
- last = (&ima_temp_rules)->prev;
- policy = &ima_policy_rules;
-
- synchronize_rcu();
+ struct list_head *policy = &ima_policy_rules;
- last->next = policy;
- rcu_assign_pointer(list_next_rcu(policy->prev), first);
- first->prev = policy->prev;
- policy->prev = last;
-
- /* prepare for the next policy rules addition */
- INIT_LIST_HEAD(&ima_temp_rules);
+ list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu);
if (ima_rules != policy) {
ima_policy_flag = 0;
@@ -540,7 +545,7 @@ enum {
Opt_audit, Opt_hash, Opt_dont_hash,
Opt_obj_user, Opt_obj_role, Opt_obj_type,
Opt_subj_user, Opt_subj_role, Opt_subj_type,
- Opt_func, Opt_mask, Opt_fsmagic,
+ Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname,
Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
@@ -565,6 +570,7 @@ static match_table_t policy_tokens = {
{Opt_func, "func=%s"},
{Opt_mask, "mask=%s"},
{Opt_fsmagic, "fsmagic=%s"},
+ {Opt_fsname, "fsname=%s"},
{Opt_fsuuid, "fsuuid=%s"},
{Opt_uid_eq, "uid=%s"},
{Opt_euid_eq, "euid=%s"},
@@ -776,6 +782,17 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
if (!result)
entry->flags |= IMA_FSMAGIC;
break;
+ case Opt_fsname:
+ ima_log_string(ab, "fsname", args[0].from);
+
+ entry->fsname = kstrdup(args[0].from, GFP_KERNEL);
+ if (!entry->fsname) {
+ result = -ENOMEM;
+ break;
+ }
+ result = 0;
+ entry->flags |= IMA_FSNAME;
+ break;
case Opt_fsuuid:
ima_log_string(ab, "fsuuid", args[0].from);
@@ -917,12 +934,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
}
if (!result && (entry->action == UNKNOWN))
result = -EINVAL;
- else if (entry->func == MODULE_CHECK)
- temp_ima_appraise |= IMA_APPRAISE_MODULES;
- else if (entry->func == FIRMWARE_CHECK)
- temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
- else if (entry->func == POLICY_CHECK)
- temp_ima_appraise |= IMA_APPRAISE_POLICY;
+ else if (entry->action == APPRAISE)
+ temp_ima_appraise |= ima_appraise_flag(entry->func);
+
audit_log_format(ab, "res=%d", !result);
audit_log_end(ab);
return result;
@@ -1104,6 +1118,12 @@ int ima_policy_show(struct seq_file *m, void *v)
seq_puts(m, " ");
}
+ if (entry->flags & IMA_FSNAME) {
+ snprintf(tbuf, sizeof(tbuf), "%s", entry->fsname);
+ seq_printf(m, pt(Opt_fsname), tbuf);
+ seq_puts(m, " ");
+ }
+
if (entry->flags & IMA_PCR) {
snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr);
seq_printf(m, pt(Opt_pcr), tbuf);
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 5afaa53decc5..43752002c222 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -13,6 +13,8 @@
* Library of supported template fields.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "ima_template_lib.h"
static bool ima_template_hash_algo_allowed(u8 algo)