summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/integrity/Kconfig46
-rw-r--r--security/integrity/Makefile6
-rw-r--r--security/integrity/digsig_asymmetric.c5
-rw-r--r--security/integrity/evm/Kconfig8
-rw-r--r--security/integrity/evm/evm_main.c17
-rw-r--r--security/integrity/ima/Kconfig2
-rw-r--r--security/integrity/ima/ima.h15
-rw-r--r--security/integrity/ima/ima_api.c5
-rw-r--r--security/integrity/ima/ima_appraise.c11
-rw-r--r--security/integrity/ima/ima_crypto.c20
-rw-r--r--security/integrity/ima/ima_main.c52
-rw-r--r--security/integrity/ima/ima_template.c30
-rw-r--r--security/integrity/integrity.h2
13 files changed, 101 insertions, 118 deletions
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 245c6d92065b..b76235ae4786 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -1,11 +1,23 @@
#
config INTEGRITY
- def_bool y
- depends on IMA || EVM
+ bool "Integrity subsystem"
+ depends on SECURITY
+ default y
+ help
+ This option enables the integrity subsystem, which is comprised
+ of a number of different components including the Integrity
+ Measurement Architecture (IMA), Extended Verification Module
+ (EVM), IMA-appraisal extension, digital signature verification
+ extension and audit measurement log support.
+
+ Each of these components can be enabled/disabled separately.
+ Refer to the individual components for additional details.
+
+if INTEGRITY
config INTEGRITY_SIGNATURE
boolean "Digital signature verification using multiple keyrings"
- depends on INTEGRITY && KEYS
+ depends on KEYS
default n
select SIGNATURE
help
@@ -17,9 +29,21 @@ config INTEGRITY_SIGNATURE
This is useful for evm and module keyrings, when keys are
usually only added from initramfs.
+config INTEGRITY_ASYMMETRIC_KEYS
+ boolean "Enable asymmetric keys support"
+ depends on INTEGRITY_SIGNATURE
+ default n
+ select ASYMMETRIC_KEY_TYPE
+ select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ select PUBLIC_KEY_ALGO_RSA
+ select X509_CERTIFICATE_PARSER
+ help
+ This option enables digital signature verification using
+ asymmetric keys.
+
config INTEGRITY_AUDIT
bool "Enables integrity auditing support "
- depends on INTEGRITY && AUDIT
+ depends on AUDIT
default y
help
In addition to enabling integrity auditing support, this
@@ -32,17 +56,7 @@ config INTEGRITY_AUDIT
be enabled by specifying 'integrity_audit=1' on the kernel
command line.
-config INTEGRITY_ASYMMETRIC_KEYS
- boolean "Enable asymmetric keys support"
- depends on INTEGRITY_SIGNATURE
- default n
- select ASYMMETRIC_KEY_TYPE
- select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
- select PUBLIC_KEY_ALGO_RSA
- select X509_CERTIFICATE_PARSER
- help
- This option enables digital signature verification using
- asymmetric keys.
-
source security/integrity/ima/Kconfig
source security/integrity/evm/Kconfig
+
+endif # if INTEGRITY
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 0793f4811cb7..8d1f4bf51087 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -3,11 +3,11 @@
#
obj-$(CONFIG_INTEGRITY) += integrity.o
-obj-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
-obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
-obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
integrity-y := iint.o
+integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
+integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
+integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
subdir-$(CONFIG_IMA) += ima
obj-$(CONFIG_IMA) += ima/
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 9eae4809006b..37e0d98517a8 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
+#include <linux/ratelimit.h>
#include <linux/key-type.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
@@ -45,8 +46,8 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
}
if (IS_ERR(key)) {
- pr_warn("Request for unknown key '%s' err %ld\n",
- name, PTR_ERR(key));
+ pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
+ name, PTR_ERR(key));
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index d606f3d12d6b..df586fa00ef1 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -1,6 +1,5 @@
config EVM
boolean "EVM support"
- depends on SECURITY
select KEYS
select ENCRYPTED_KEYS
select CRYPTO_HMAC
@@ -12,10 +11,6 @@ config EVM
If you are unsure how to answer this question, answer N.
-if EVM
-
-menu "EVM options"
-
config EVM_ATTR_FSUUID
bool "FSUUID (version 2)"
default y
@@ -47,6 +42,3 @@ config EVM_EXTRA_SMACK_XATTRS
additional info to the calculation, requires existing EVM
labeled file systems to be relabeled.
-endmenu
-
-endif
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 3bcb80df4d01..9685af330de5 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -126,14 +126,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
if (rc <= 0) {
- if (rc == 0)
- evm_status = INTEGRITY_FAIL; /* empty */
- else if (rc == -ENODATA) {
+ evm_status = INTEGRITY_FAIL;
+ if (rc == -ENODATA) {
rc = evm_find_protected_xattrs(dentry);
if (rc > 0)
evm_status = INTEGRITY_NOLABEL;
else if (rc == 0)
evm_status = INTEGRITY_NOXATTRS; /* new file */
+ } else if (rc == -EOPNOTSUPP) {
+ evm_status = INTEGRITY_UNKNOWN;
}
goto out;
}
@@ -284,6 +285,13 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
goto out;
}
evm_status = evm_verify_current_integrity(dentry);
+ if (evm_status == INTEGRITY_NOXATTRS) {
+ struct integrity_iint_cache *iint;
+
+ iint = integrity_iint_find(dentry->d_inode);
+ if (iint && (iint->flags & IMA_NEW_FILE))
+ return 0;
+ }
out:
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
@@ -352,7 +360,6 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
return;
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
- return;
}
/**
@@ -372,7 +379,6 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
mutex_lock(&inode->i_mutex);
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
mutex_unlock(&inode->i_mutex);
- return;
}
/**
@@ -414,7 +420,6 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
- return;
}
/*
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 08758fbd496f..e099875643c5 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -2,8 +2,6 @@
#
config IMA
bool "Integrity Measurement Architecture(IMA)"
- depends on SECURITY
- select INTEGRITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 57da4bd7ba0c..8e4bb883fc13 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -90,10 +90,7 @@ extern struct list_head ima_measurements; /* list of all measurements */
/* Internal IMA function definitions */
int ima_init(void);
-void ima_cleanup(void);
int ima_fs_init(void);
-void ima_fs_cleanup(void);
-int ima_inode_alloc(struct inode *inode);
int ima_add_template_entry(struct ima_template_entry *entry, int violation,
const char *op, struct inode *inode,
const unsigned char *filename);
@@ -110,8 +107,6 @@ void ima_print_digest(struct seq_file *m, u8 *digest, int size);
struct ima_template_desc *ima_template_desc_current(void);
int ima_init_template(void);
-int ima_init_template(void);
-
/*
* used to protect h_table and sha_table
*/
@@ -151,12 +146,6 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(struct path *path, char **pathbuf);
-/* rbtree tree calls to lookup, insert, delete
- * integrity data associated with an inode.
- */
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
-struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
-
/* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
@@ -177,7 +166,7 @@ void ima_delete_rules(void);
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len);
+ int xattr_len, int opened);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
@@ -193,7 +182,7 @@ static inline int ima_appraise_measurement(int func,
struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len)
+ int xattr_len, int opened)
{
return INTEGRITY_UNKNOWN;
}
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index d9cd5ce14d2b..65c41a968cc1 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -330,10 +330,9 @@ const char *ima_d_path(struct path *path, char **pathbuf)
{
char *pathname = NULL;
- /* We will allow 11 spaces for ' (deleted)' to be appended */
- *pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
+ *pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
if (*pathbuf) {
- pathname = d_path(path, *pathbuf, PATH_MAX + 11);
+ pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
if (IS_ERR(pathname)) {
kfree(*pathbuf);
*pathbuf = NULL;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 86bfd5c5df85..013ec3f0e42d 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -183,7 +183,7 @@ int ima_read_xattr(struct dentry *dentry,
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len)
+ int xattr_len, int opened)
{
static const char op[] = "appraise_data";
char *cause = "unknown";
@@ -192,8 +192,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0;
- if (!ima_appraise)
- return 0;
if (!inode->i_op->getxattr)
return INTEGRITY_UNKNOWN;
@@ -202,8 +200,11 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
goto out;
cause = "missing-hash";
- status =
- (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
+ status = INTEGRITY_NOLABEL;
+ if (opened & FILE_CREATED) {
+ iint->flags |= IMA_NEW_FILE;
+ status = INTEGRITY_PASS;
+ }
goto out;
}
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 0bd732843fe7..d34e7dfc1118 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -80,24 +80,24 @@ static int ima_kernel_read(struct file *file, loff_t offset,
{
mm_segment_t old_fs;
char __user *buf = addr;
- ssize_t ret;
+ ssize_t ret = -EINVAL;
if (!(file->f_mode & FMODE_READ))
return -EBADF;
- if (!file->f_op->read && !file->f_op->aio_read)
- return -EINVAL;
old_fs = get_fs();
set_fs(get_ds());
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, &offset);
- else
+ else if (file->f_op->aio_read)
ret = do_sync_read(file, buf, count, &offset);
+ else if (file->f_op->read_iter)
+ ret = new_sync_read(file, buf, count, &offset);
set_fs(old_fs);
return ret;
}
-int ima_init_crypto(void)
+int __init ima_init_crypto(void)
{
long rc;
@@ -116,7 +116,10 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
struct crypto_shash *tfm = ima_shash_tfm;
int rc;
- if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) {
+ if (algo < 0 || algo >= HASH_ALGO__LAST)
+ algo = ima_hash_algo;
+
+ if (algo != ima_hash_algo) {
tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
if (IS_ERR(tfm)) {
rc = PTR_ERR(tfm);
@@ -200,7 +203,10 @@ static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
struct crypto_ahash *tfm = ima_ahash_tfm;
int rc;
- if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
+ if (algo < 0 || algo >= HASH_ALGO__LAST)
+ algo = ima_hash_algo;
+
+ if (algo != ima_hash_algo || !tfm) {
tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
if (!IS_ERR(tfm)) {
if (algo == ima_hash_algo)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2917f980bf30..673a37e92ba3 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -124,11 +124,13 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
return;
mutex_lock(&inode->i_mutex);
- if (atomic_read(&inode->i_writecount) == 1 &&
- iint->version != inode->i_version) {
- iint->flags &= ~IMA_DONE_MASK;
- if (iint->flags & IMA_APPRAISE)
- ima_update_xattr(iint, file);
+ if (atomic_read(&inode->i_writecount) == 1) {
+ if ((iint->version != inode->i_version) ||
+ (iint->flags & IMA_NEW_FILE)) {
+ iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
+ if (iint->flags & IMA_APPRAISE)
+ ima_update_xattr(iint, file);
+ }
}
mutex_unlock(&inode->i_mutex);
}
@@ -154,15 +156,15 @@ void ima_file_free(struct file *file)
ima_check_last_writer(iint, inode, file);
}
-static int process_measurement(struct file *file, const char *filename,
- int mask, int function)
+static int process_measurement(struct file *file, int mask, int function,
+ int opened)
{
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint;
struct ima_template_desc *template_desc;
char *pathbuf = NULL;
const char *pathname = NULL;
- int rc = -ENOMEM, action, must_appraise, _func;
+ int rc = -ENOMEM, action, must_appraise;
struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
int xattr_len = 0;
@@ -180,7 +182,8 @@ static int process_measurement(struct file *file, const char *filename,
must_appraise = action & IMA_APPRAISE;
/* Is the appraise rule hook specific? */
- _func = (action & IMA_FILE_APPRAISE) ? FILE_CHECK : function;
+ if (action & IMA_FILE_APPRAISE)
+ function = FILE_CHECK;
mutex_lock(&inode->i_mutex);
@@ -199,15 +202,13 @@ static int process_measurement(struct file *file, const char *filename,
/* Nothing to do, just return existing appraised status */
if (!action) {
if (must_appraise)
- rc = ima_get_cache_status(iint, _func);
+ rc = ima_get_cache_status(iint, function);
goto out_digsig;
}
template_desc = ima_template_desc_current();
- if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
- if (action & IMA_APPRAISE_SUBMASK)
- xattr_ptr = &xattr_value;
- } else
+ if ((action & IMA_APPRAISE_SUBMASK) ||
+ strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
xattr_ptr = &xattr_value;
rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
@@ -217,14 +218,14 @@ static int process_measurement(struct file *file, const char *filename,
goto out_digsig;
}
- pathname = filename ?: ima_d_path(&file->f_path, &pathbuf);
+ pathname = ima_d_path(&file->f_path, &pathbuf);
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len);
if (action & IMA_APPRAISE_SUBMASK)
- rc = ima_appraise_measurement(_func, iint, file, pathname,
- xattr_value, xattr_len);
+ rc = ima_appraise_measurement(function, iint, file, pathname,
+ xattr_value, xattr_len, opened);
if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname);
kfree(pathbuf);
@@ -253,7 +254,7 @@ out:
int ima_file_mmap(struct file *file, unsigned long prot)
{
if (file && (prot & PROT_EXEC))
- return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK);
+ return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0);
return 0;
}
@@ -272,10 +273,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
*/
int ima_bprm_check(struct linux_binprm *bprm)
{
- return process_measurement(bprm->file,
- (strcmp(bprm->filename, bprm->interp) == 0) ?
- bprm->filename : bprm->interp,
- MAY_EXEC, BPRM_CHECK);
+ return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0);
}
/**
@@ -288,12 +286,12 @@ int ima_bprm_check(struct linux_binprm *bprm)
* 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_file_check(struct file *file, int mask)
+int ima_file_check(struct file *file, int mask, int opened)
{
ima_rdwr_violation_check(file);
- return process_measurement(file, NULL,
+ return process_measurement(file,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
- FILE_CHECK);
+ FILE_CHECK, opened);
}
EXPORT_SYMBOL_GPL(ima_file_check);
@@ -316,7 +314,7 @@ int ima_module_check(struct file *file)
#endif
return 0; /* We rely on module signature checking */
}
- return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
+ return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0);
}
int ima_fw_from_file(struct file *file, char *buf, size_t size)
@@ -327,7 +325,7 @@ int ima_fw_from_file(struct file *file, char *buf, size_t size)
return -EACCES; /* INTEGRITY_UNKNOWN */
return 0;
}
- return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK);
+ return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0);
}
static int __init init_ima(void)
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index a076a967ec47..e854862c9337 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -152,24 +152,6 @@ out:
return result;
}
-static int init_defined_templates(void)
-{
- int i = 0;
- int result = 0;
-
- /* Init defined templates. */
- for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
- struct ima_template_desc *template = &defined_templates[i];
-
- result = template_desc_init_fields(template->fmt,
- &(template->fields),
- &(template->num_fields));
- if (result < 0)
- return result;
- }
- return result;
-}
-
struct ima_template_desc *ima_template_desc_current(void)
{
if (!ima_template)
@@ -178,13 +160,11 @@ struct ima_template_desc *ima_template_desc_current(void)
return ima_template;
}
-int ima_init_template(void)
+int __init ima_init_template(void)
{
- int result;
-
- result = init_defined_templates();
- if (result < 0)
- return result;
+ struct ima_template_desc *template = ima_template_desc_current();
- return 0;
+ return template_desc_init_fields(template->fmt,
+ &(template->fields),
+ &(template->num_fields));
}
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 19b8e314ca96..c0379d13dbe1 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -31,6 +31,7 @@
#define IMA_DIGSIG 0x01000000
#define IMA_DIGSIG_REQUIRED 0x02000000
#define IMA_PERMIT_DIRECTIO 0x04000000
+#define IMA_NEW_FILE 0x08000000
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
IMA_APPRAISE_SUBMASK)
@@ -116,7 +117,6 @@ struct integrity_iint_cache {
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
*/
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
#define INTEGRITY_KEYRING_EVM 0
OpenPOWER on IntegriCloud