diff options
author | James Morris <james.l.morris@oracle.com> | 2014-09-12 22:40:22 +1000 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2014-09-12 22:40:22 +1000 |
commit | ac60ab4b4968b54fb5af20eac9dd78e36ad910c1 (patch) | |
tree | a47e414fb34d91eb012b121d8138c6cee1fe065b /security | |
parent | a0cfd75fdc46b56978ece383a7d6f6b04e9087ad (diff) | |
parent | a2d61ed525f3458a913147fd02b1a5cf15e7551b (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/Kconfig | 46 | ||||
-rw-r--r-- | security/integrity/Makefile | 6 | ||||
-rw-r--r-- | security/integrity/digsig_asymmetric.c | 5 | ||||
-rw-r--r-- | security/integrity/evm/Kconfig | 8 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 17 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 15 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 11 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 20 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 52 | ||||
-rw-r--r-- | security/integrity/ima/ima_template.c | 30 | ||||
-rw-r--r-- | security/integrity/integrity.h | 2 |
13 files changed, 101 insertions, 118 deletions
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 245c6d92065..b76235ae478 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 0793f4811cb..8d1f4bf5108 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 9eae4809006..37e0d98517a 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 d606f3d12d6..df586fa00ef 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 3bcb80df4d0..9685af330de 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 08758fbd496..e099875643c 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 57da4bd7ba0..8e4bb883fc1 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 d9cd5ce14d2..65c41a968cc 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 86bfd5c5df8..013ec3f0e42 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 0bd732843fe..d34e7dfc111 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 2917f980bf3..673a37e92ba 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 a076a967ec4..e854862c933 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 19b8e314ca9..c0379d13dbe 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 |