diff options
Diffstat (limited to 'security')
24 files changed, 506 insertions, 263 deletions
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 21d756832b75..979be65d22c4 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -36,6 +36,7 @@ config INTEGRITY_ASYMMETRIC_KEYS select ASYMMETRIC_KEY_TYPE select ASYMMETRIC_PUBLIC_KEY_SUBTYPE select PUBLIC_KEY_ALGO_RSA + select CRYPTO_RSA select X509_CERTIFICATE_PARSER help This option enables digital signature verification using @@ -45,7 +46,6 @@ config INTEGRITY_TRUSTED_KEYRING bool "Require all keys on the integrity keyrings be signed" depends on SYSTEM_TRUSTED_KEYRING depends on INTEGRITY_ASYMMETRIC_KEYS - select KEYS_DEBUG_PROC_KEYS default y help This option requires that all keys added to the .ima and diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 5ade2a7517a6..80052ed8d467 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -16,6 +16,7 @@ #include <linux/ratelimit.h> #include <linux/key-type.h> #include <crypto/public_key.h> +#include <crypto/hash_info.h> #include <keys/asymmetric-type.h> #include <keys/system_keyring.h> @@ -94,7 +95,7 @@ int asymmetric_verify(struct key *keyring, const char *sig, if (siglen != __be16_to_cpu(hdr->sig_size)) return -EBADMSG; - if (hdr->hash_algo >= PKEY_HASH__LAST) + if (hdr->hash_algo >= HASH_ALGO__LAST) return -ENOPKG; key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid)); @@ -103,16 +104,13 @@ int asymmetric_verify(struct key *keyring, const char *sig, memset(&pks, 0, sizeof(pks)); - pks.pkey_hash_algo = hdr->hash_algo; + pks.pkey_algo = "rsa"; + pks.hash_algo = hash_algo_name[hdr->hash_algo]; pks.digest = (u8 *)data; pks.digest_size = datalen; - pks.nr_mpi = 1; - pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen); - - if (pks.rsa.s) - ret = verify_signature(key, &pks); - - mpi_free(pks.rsa.s); + pks.s = hdr->sig; + pks.s_size = siglen; + ret = verify_signature(key, &pks); key_put(key); pr_debug("%s() = %d\n", __func__, ret); return ret; diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index f7160253f17f..e6ea9d4b1de9 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -23,6 +23,7 @@ #include <linux/integrity.h> #include <linux/evm.h> #include <crypto/hash.h> +#include <crypto/algapi.h> #include "evm.h" int evm_initialized; @@ -148,7 +149,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, xattr_value_len, calc.digest); if (rc) break; - rc = memcmp(xattr_data->digest, calc.digest, + rc = crypto_memneq(xattr_data->digest, calc.digest, sizeof(calc.digest)); if (rc) rc = -EINVAL; diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 8f1ab37f2897..345b75997e4c 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -77,7 +77,7 @@ static void iint_free(struct integrity_iint_cache *iint) iint->ima_file_status = INTEGRITY_UNKNOWN; iint->ima_mmap_status = INTEGRITY_UNKNOWN; iint->ima_bprm_status = INTEGRITY_UNKNOWN; - iint->ima_module_status = INTEGRITY_UNKNOWN; + iint->ima_read_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; kmem_cache_free(iint_cache, iint); } @@ -157,7 +157,7 @@ static void init_once(void *foo) iint->ima_file_status = INTEGRITY_UNKNOWN; iint->ima_mmap_status = INTEGRITY_UNKNOWN; iint->ima_bprm_status = INTEGRITY_UNKNOWN; - iint->ima_module_status = INTEGRITY_UNKNOWN; + iint->ima_read_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; } diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 585af61ed399..5d0f61163d98 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -19,10 +19,12 @@ #include <linux/types.h> #include <linux/crypto.h> +#include <linux/fs.h> #include <linux/security.h> #include <linux/hash.h> #include <linux/tpm.h> #include <linux/audit.h> +#include <crypto/hash_info.h> #include "../integrity.h" @@ -106,6 +108,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, const unsigned char *filename); int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); +int ima_calc_buffer_hash(const void *buf, loff_t len, + struct ima_digest_data *hash); int ima_calc_field_array_hash(struct ima_field_data *field_data, struct ima_template_desc *desc, int num_fields, struct ima_digest_data *hash); @@ -136,13 +140,25 @@ static inline unsigned long ima_hash_key(u8 *digest) return hash_long(*digest, IMA_HASH_BITS); } +enum ima_hooks { + FILE_CHECK = 1, + MMAP_CHECK, + BPRM_CHECK, + POST_SETATTR, + MODULE_CHECK, + FIRMWARE_CHECK, + KEXEC_KERNEL_CHECK, + KEXEC_INITRAMFS_CHECK, + POLICY_CHECK, + MAX_CHECK +}; + /* LIM API function definitions */ -int ima_get_action(struct inode *inode, int mask, int function); -int ima_must_measure(struct inode *inode, int mask, int function); +int ima_get_action(struct inode *inode, int mask, enum ima_hooks func); +int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct integrity_iint_cache *iint, - struct file *file, - struct evm_ima_xattr_data **xattr_value, - int *xattr_len); + struct file *file, void *buf, loff_t size, + enum hash_algo algo); void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, @@ -157,8 +173,6 @@ void ima_free_template_entry(struct ima_template_entry *entry); const char *ima_d_path(struct path *path, char **pathbuf); /* IMA policy related functions */ -enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR }; - int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, int flags); void ima_init_policy(void); @@ -178,23 +192,25 @@ int ima_policy_show(struct seq_file *m, void *v); #define IMA_APPRAISE_LOG 0x04 #define IMA_APPRAISE_MODULES 0x08 #define IMA_APPRAISE_FIRMWARE 0x10 +#define IMA_APPRAISE_POLICY 0x20 #ifdef CONFIG_IMA_APPRAISE -int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, +int ima_appraise_measurement(enum ima_hooks func, + struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, 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, - int func); -void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, - struct ima_digest_data *hash); + enum ima_hooks func); +enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, + int xattr_len); int ima_read_xattr(struct dentry *dentry, struct evm_ima_xattr_data **xattr_value); #else -static inline int ima_appraise_measurement(int func, +static inline int ima_appraise_measurement(enum ima_hooks func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, @@ -216,15 +232,16 @@ static inline void ima_update_xattr(struct integrity_iint_cache *iint, } static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache - *iint, int func) + *iint, + enum ima_hooks func) { return INTEGRITY_UNKNOWN; } -static inline void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, - int xattr_len, - struct ima_digest_data *hash) +static inline enum hash_algo +ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len) { + return ima_hash_algo; } static inline int ima_read_xattr(struct dentry *dentry, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 1d950fbb2aec..370e42dfc5c5 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -18,7 +18,7 @@ #include <linux/fs.h> #include <linux/xattr.h> #include <linux/evm.h> -#include <crypto/hash_info.h> + #include "ima.h" /* @@ -156,7 +156,7 @@ err_out: * ima_get_action - appraise & measure decision based on policy. * @inode: pointer to inode to measure * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) - * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK) + * @func: caller identifier * * The policy is defined in terms of keypairs: * subj=, obj=, type=, func=, mask=, fsmagic= @@ -168,13 +168,13 @@ err_out: * Returns IMA_MEASURE, IMA_APPRAISE mask. * */ -int ima_get_action(struct inode *inode, int mask, int function) +int ima_get_action(struct inode *inode, int mask, enum ima_hooks func) { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; flags &= ima_policy_flag; - return ima_match_policy(inode, function, mask, flags); + return ima_match_policy(inode, func, mask, flags); } /* @@ -188,9 +188,8 @@ int ima_get_action(struct inode *inode, int mask, int function) * Return 0 on success, error code otherwise */ int ima_collect_measurement(struct integrity_iint_cache *iint, - struct file *file, - struct evm_ima_xattr_data **xattr_value, - int *xattr_len) + struct file *file, void *buf, loff_t size, + enum hash_algo algo) { const char *audit_cause = "failed"; struct inode *inode = file_inode(file); @@ -201,9 +200,6 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, char digest[IMA_MAX_DIGEST_SIZE]; } hash; - if (xattr_value) - *xattr_len = ima_read_xattr(file->f_path.dentry, xattr_value); - if (!(iint->flags & IMA_COLLECTED)) { u64 i_version = file_inode(file)->i_version; @@ -213,13 +209,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, goto out; } - /* use default hash algorithm */ - hash.hdr.algo = ima_hash_algo; - - if (xattr_value) - ima_get_hash_algo(*xattr_value, *xattr_len, &hash.hdr); + hash.hdr.algo = algo; - result = ima_calc_file_hash(file, &hash.hdr); + result = (!buf) ? ima_calc_file_hash(file, &hash.hdr) : + ima_calc_buffer_hash(buf, size, &hash.hdr); if (!result) { int length = sizeof(hash.hdr) + hash.hdr.length; void *tmpbuf = krealloc(iint->ima_hash, length, diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 1873b5536f80..6b4694aedae8 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -15,7 +15,6 @@ #include <linux/magic.h> #include <linux/ima.h> #include <linux/evm.h> -#include <crypto/hash_info.h> #include "ima.h" @@ -68,25 +67,25 @@ static int ima_fix_xattr(struct dentry *dentry, /* Return specific func appraised cached result */ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, - int func) + enum ima_hooks func) { switch (func) { case MMAP_CHECK: return iint->ima_mmap_status; case BPRM_CHECK: return iint->ima_bprm_status; - case MODULE_CHECK: - return iint->ima_module_status; - case FIRMWARE_CHECK: - return iint->ima_firmware_status; case FILE_CHECK: - default: + case POST_SETATTR: return iint->ima_file_status; + case MODULE_CHECK ... MAX_CHECK - 1: + default: + return iint->ima_read_status; } } static void ima_set_cache_status(struct integrity_iint_cache *iint, - int func, enum integrity_status status) + enum ima_hooks func, + enum integrity_status status) { switch (func) { case MMAP_CHECK: @@ -95,20 +94,19 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, case BPRM_CHECK: iint->ima_bprm_status = status; break; - case MODULE_CHECK: - iint->ima_module_status = status; - break; - case FIRMWARE_CHECK: - iint->ima_firmware_status = status; - break; case FILE_CHECK: - default: + case POST_SETATTR: iint->ima_file_status = status; break; + case MODULE_CHECK ... MAX_CHECK - 1: + default: + iint->ima_read_status = status; + break; } } -static void ima_cache_flags(struct integrity_iint_cache *iint, int func) +static void ima_cache_flags(struct integrity_iint_cache *iint, + enum ima_hooks func) { switch (func) { case MMAP_CHECK: @@ -117,49 +115,51 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) case BPRM_CHECK: iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED); break; - case MODULE_CHECK: - iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); - break; - case FIRMWARE_CHECK: - iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED); - break; case FILE_CHECK: - default: + case POST_SETATTR: iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); break; + case MODULE_CHECK ... MAX_CHECK - 1: + default: + iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED); + break; } } -void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, - struct ima_digest_data *hash) +enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, + int xattr_len) { struct signature_v2_hdr *sig; if (!xattr_value || xattr_len < 2) - return; + /* return default hash algo */ + return ima_hash_algo; switch (xattr_value->type) { case EVM_IMA_XATTR_DIGSIG: sig = (typeof(sig))xattr_value; if (sig->version != 2 || xattr_len <= sizeof(*sig)) - return; - hash->algo = sig->hash_algo; + return ima_hash_algo; + return sig->hash_algo; break; case IMA_XATTR_DIGEST_NG: - hash->algo = xattr_value->digest[0]; + return xattr_value->digest[0]; break; case IMA_XATTR_DIGEST: /* this is for backward compatibility */ if (xattr_len == 21) { unsigned int zero = 0; if (!memcmp(&xattr_value->digest[16], &zero, 4)) - hash->algo = HASH_ALGO_MD5; + return HASH_ALGO_MD5; else - hash->algo = HASH_ALGO_SHA1; + return HASH_ALGO_SHA1; } else if (xattr_len == 17) - hash->algo = HASH_ALGO_MD5; + return HASH_ALGO_MD5; break; } + + /* return default hash algo */ + return ima_hash_algo; } int ima_read_xattr(struct dentry *dentry, @@ -182,7 +182,8 @@ int ima_read_xattr(struct dentry *dentry, * * Return 0 on success, error code otherwise */ -int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, +int ima_appraise_measurement(enum ima_hooks func, + struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, int opened) @@ -296,7 +297,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) if (iint->flags & IMA_DIGSIG) return; - rc = ima_collect_measurement(iint, file, NULL, NULL); + rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); if (rc < 0) return; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 6eb62936c672..38f2ed830dd6 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -24,7 +24,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <crypto/hash.h> -#include <crypto/hash_info.h> + #include "ima.h" struct ahash_completion { @@ -519,6 +519,124 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, return rc; } +static int calc_buffer_ahash_atfm(const void *buf, loff_t len, + struct ima_digest_data *hash, + struct crypto_ahash *tfm) +{ + struct ahash_request *req; + struct scatterlist sg; + struct ahash_completion res; + int rc, ahash_rc = 0; + + hash->length = crypto_ahash_digestsize(tfm); + + req = ahash_request_alloc(tfm, GFP_KERNEL); + if (!req) + return -ENOMEM; + + init_completion(&res.completion); + ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + ahash_complete, &res); + + rc = ahash_wait(crypto_ahash_init(req), &res); + if (rc) + goto out; + + sg_init_one(&sg, buf, len); + ahash_request_set_crypt(req, &sg, NULL, len); + + ahash_rc = crypto_ahash_update(req); + + /* wait for the update request to complete */ + rc = ahash_wait(ahash_rc, &res); + if (!rc) { + ahash_request_set_crypt(req, NULL, hash->digest, 0); + rc = ahash_wait(crypto_ahash_final(req), &res); + } +out: + ahash_request_free(req); + return rc; +} + +static int calc_buffer_ahash(const void *buf, loff_t len, + struct ima_digest_data *hash) +{ + struct crypto_ahash *tfm; + int rc; + + tfm = ima_alloc_atfm(hash->algo); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + rc = calc_buffer_ahash_atfm(buf, len, hash, tfm); + + ima_free_atfm(tfm); + + return rc; +} + +static int calc_buffer_shash_tfm(const void *buf, loff_t size, + struct ima_digest_data *hash, + struct crypto_shash *tfm) +{ + SHASH_DESC_ON_STACK(shash, tfm); + unsigned int len; + int rc; + + shash->tfm = tfm; + shash->flags = 0; + + hash->length = crypto_shash_digestsize(tfm); + + rc = crypto_shash_init(shash); + if (rc != 0) + return rc; + + while (size) { + len = size < PAGE_SIZE ? size : PAGE_SIZE; + rc = crypto_shash_update(shash, buf, len); + if (rc) + break; + buf += len; + size -= len; + } + + if (!rc) + rc = crypto_shash_final(shash, hash->digest); + return rc; +} + +static int calc_buffer_shash(const void *buf, loff_t len, + struct ima_digest_data *hash) +{ + struct crypto_shash *tfm; + int rc; + + tfm = ima_alloc_tfm(hash->algo); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + rc = calc_buffer_shash_tfm(buf, len, hash, tfm); + + ima_free_tfm(tfm); + return rc; +} + +int ima_calc_buffer_hash(const void *buf, loff_t len, + struct ima_digest_data *hash) +{ + int rc; + + if (ima_ahash_minsize && len >= ima_ahash_minsize) { + rc = calc_buffer_ahash(buf, len, hash); + if (!rc) + return 0; + } + + return calc_buffer_shash(buf, len, hash); +} + static void __init ima_pcrread(int idx, u8 *pcr) { if (!ima_used_chip) diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index f355231997b4..60d011aaec38 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -22,6 +22,7 @@ #include <linux/rculist.h> #include <linux/rcupdate.h> #include <linux/parser.h> +#include <linux/vmalloc.h> #include "ima.h" @@ -258,6 +259,43 @@ static const struct file_operations ima_ascii_measurements_ops = { .release = seq_release, }; +static ssize_t ima_read_policy(char *path) +{ + void *data; + char *datap; + loff_t size; + int rc, pathlen = strlen(path); + + char *p; + + /* remove \n */ + datap = path; + strsep(&datap, "\n"); + + rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY); + if (rc < 0) { + pr_err("Unable to open file: %s (%d)", path, rc); + return rc; + } + + datap = data; + while (size > 0 && (p = strsep(&datap, "\n"))) { + pr_debug("rule: %s\n", p); + rc = ima_parse_add_rule(p); + if (rc < 0) + break; + size -= rc; + } + + vfree(data); + if (rc < 0) + return rc; + else if (size) + return -EINVAL; + else + return pathlen; +} + static ssize_t ima_write_policy(struct file *file, const char __user *buf, size_t datalen, loff_t *ppos) { @@ -286,9 +324,20 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, result = mutex_lock_interruptible(&ima_write_mutex); if (result < 0) goto out_free; - result = ima_parse_add_rule(data); - mutex_unlock(&ima_write_mutex); + 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"); + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, + "policy_update", "signed policy required", + 1, 0); + if (ima_appraise & IMA_APPRAISE_ENFORCE) + result = -EACCES; + } else { + result = ima_parse_add_rule(data); + } + mutex_unlock(&ima_write_mutex); out_free: kfree(data); out: diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index bd79f254d204..5d679a685616 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -21,7 +21,7 @@ #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/err.h> -#include <crypto/hash_info.h> + #include "ima.h" /* name for boot aggregate entry */ diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 9d96551d0196..391f41751021 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -24,7 +24,6 @@ #include <linux/slab.h> #include <linux/xattr.h> #include <linux/ima.h> -#include <crypto/hash_info.h> #include "ima.h" @@ -154,8 +153,8 @@ void ima_file_free(struct file *file) ima_check_last_writer(iint, inode, file); } -static int process_measurement(struct file *file, int mask, int function, - int opened) +static int process_measurement(struct file *file, char *buf, loff_t size, + int mask, enum ima_hooks func, int opened) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; @@ -163,9 +162,10 @@ static int process_measurement(struct file *file, int mask, int function, char *pathbuf = NULL; const char *pathname = NULL; int rc = -ENOMEM, action, must_appraise; - struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; + struct evm_ima_xattr_data *xattr_value = NULL; int xattr_len = 0; bool violation_check; + enum hash_algo hash_algo; if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; @@ -174,8 +174,8 @@ static int process_measurement(struct file *file, int mask, int function, * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ - action = ima_get_action(inode, mask, function); - violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) && + action = ima_get_action(inode, mask, func); + violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && (ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) return 0; @@ -184,7 +184,7 @@ static int process_measurement(struct file *file, int mask, int function, /* Is the appraise rule hook specific? */ if (action & IMA_FILE_APPRAISE) - function = FILE_CHECK; + func = FILE_CHECK; inode_lock(inode); @@ -214,16 +214,19 @@ static int process_measurement(struct file *file, int mask, int function, /* Nothing to do, just return existing appraised status */ if (!action) { if (must_appraise) - rc = ima_get_cache_status(iint, function); + rc = ima_get_cache_status(iint, func); goto out_digsig; } template_desc = ima_template_desc_current(); if ((action & IMA_APPRAISE_SUBMASK) || strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) - xattr_ptr = &xattr_value; + /* read 'security.ima' */ + xattr_len = ima_read_xattr(file->f_path.dentry, &xattr_value); - rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len); + hash_algo = ima_get_hash_algo(xattr_value, xattr_len); + + rc = ima_collect_measurement(iint, file, buf, size, hash_algo); if (rc != 0) { if (file->f_flags & O_DIRECT) rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES; @@ -237,7 +240,7 @@ static int process_measurement(struct file *file, int mask, int function, ima_store_measurement(iint, file, pathname, xattr_value, xattr_len); if (action & IMA_APPRAISE_SUBMASK) - rc = ima_appraise_measurement(function, iint, file, pathname, + rc = ima_appraise_measurement(func, iint, file, pathname, xattr_value, xattr_len, opened); if (action & IMA_AUDIT) ima_audit_measurement(iint, pathname); @@ -270,7 +273,8 @@ out: int ima_file_mmap(struct file *file, unsigned long prot) { if (file && (prot & PROT_EXEC)) - return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0); + return process_measurement(file, NULL, 0, MAY_EXEC, + MMAP_CHECK, 0); return 0; } @@ -289,7 +293,8 @@ int ima_file_mmap(struct file *file, unsigned long prot) */ int ima_bprm_check(struct linux_binprm *bprm) { - return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0); + return process_measurement(bprm->file, NULL, 0, MAY_EXEC, + BPRM_CHECK, 0); } /** @@ -304,24 +309,26 @@ int ima_bprm_check(struct linux_binprm *bprm) */ int ima_file_check(struct file *file, int mask, int opened) { - return process_measurement(file, + return process_measurement(file, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC), FILE_CHECK, opened); } EXPORT_SYMBOL_GPL(ima_file_check); /** - * ima_module_check - based on policy, collect/store/appraise measurement. - * @file: pointer to the file to be measured/appraised + * 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 * - * Measure/appraise kernel modules based on policy. + * Permit reading a file based on policy. The policy rules are written + * in terms of the policy identifier. Appraising the integrity of + * a file requires a file descriptor. * - * On success return 0. On integrity appraisal error, assuming the file - * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. + * For permission return 0, otherwise return -EACCES. */ -int ima_module_check(struct file *file) +int ima_read_file(struct file *file, enum kernel_read_file_id read_id) { - if (!file) { + if (!file && read_id == READING_MODULE) { #ifndef CONFIG_MODULE_SIG_FORCE if ((ima_appraise & IMA_APPRAISE_MODULES) && (ima_appraise & IMA_APPRAISE_ENFORCE)) @@ -329,18 +336,53 @@ int ima_module_check(struct file *file) #endif return 0; /* We rely on module signature checking */ } - return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0); + return 0; } -int ima_fw_from_file(struct file *file, char *buf, size_t size) +static int read_idmap[READING_MAX_ID] = { + [READING_FIRMWARE] = FIRMWARE_CHECK, + [READING_MODULE] = MODULE_CHECK, + [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, + [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, + [READING_POLICY] = POLICY_CHECK +}; + +/** + * ima_post_read_file - in memory collect/appraise/audit measurement + * @file: pointer to the file to be measured/appraised/audit + * @buf: pointer to in memory file contents + * @size: size of in memory file contents + * @read_id: caller identifier + * + * Measure/appraise/audit in memory file 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_read_file(struct file *file, void *buf, loff_t size, + enum kernel_read_file_id read_id) { - if (!file) { + enum ima_hooks func; + + if (!file && read_id == READING_FIRMWARE) { if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && (ima_appraise & IMA_APPRAISE_ENFORCE)) return -EACCES; /* INTEGRITY_UNKNOWN */ return 0; } - return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0); + + if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */ + return 0; + + if (!file || !buf || size == 0) { /* should never happen */ + if (ima_appraise & IMA_APPRAISE_ENFORCE) + return -EACCES; + return 0; + } + + func = read_idmap[read_id] ?: FILE_CHECK; + return process_measurement(file, buf, size, MAY_READ, func, 0); } static int __init init_ima(void) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 0a3b781f18e5..be09e2cacf82 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -12,6 +12,7 @@ */ #include <linux/module.h> #include <linux/list.h> +#include <linux/fs.h> #include <linux/security.h> #include <linux/magic.h> #include <linux/parser.h> @@ -113,6 +114,7 @@ static struct ima_rule_entry default_measurement_rules[] = { .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, + {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, }; static struct ima_rule_entry default_appraise_rules[] = { @@ -127,6 +129,10 @@ static struct ima_rule_entry default_appraise_rules[] = { {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, +#ifdef CONFIG_IMA_WRITE_POLICY + {.action = APPRAISE, .func = POLICY_CHECK, + .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, +#endif #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, #else @@ -207,8 +213,8 @@ static void ima_lsm_update_rules(void) * * Returns true on rule match, false on failure. */ -static bool ima_match_rules(struct ima_rule_entry *rule, - struct inode *inode, enum ima_hooks func, int mask) +static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, + enum ima_hooks func, int mask) { struct task_struct *tsk = current; const struct cred *cred = current_cred(); @@ -289,7 +295,7 @@ retry: * In addition to knowing that we need to appraise the file in general, * we need to differentiate between calling hooks, for hook specific rules. */ -static int get_subaction(struct ima_rule_entry *rule, int func) +static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) { if (!(rule->flags & IMA_FUNC)) return IMA_FILE_APPRAISE; @@ -299,13 +305,12 @@ static int get_subaction(struct ima_rule_entry *rule, int func) return IMA_MMAP_APPRAISE; case BPRM_CHECK: return IMA_BPRM_APPRAISE; - case MODULE_CHECK: - return IMA_MODULE_APPRAISE; - case FIRMWARE_CHECK: - return IMA_FIRMWARE_APPRAISE; case FILE_CHECK: - default: + case POST_SETATTR: return IMA_FILE_APPRAISE; + case MODULE_CHECK ... MAX_CHECK - 1: + default: + return IMA_READ_APPRAISE; } } @@ -411,13 +416,16 @@ void __init ima_init_policy(void) for (i = 0; i < appraise_entries; i++) { list_add_tail(&default_appraise_rules[i].list, &ima_default_rules); + if (default_appraise_rules[i].func == POLICY_CHECK) + temp_ima_appraise |= IMA_APPRAISE_POLICY; } ima_rules = &ima_default_rules; + ima_update_policy_flag(); } /* Make sure we have a valid policy, at least containing some rules. */ -int ima_check_policy() +int ima_check_policy(void) { if (list_empty(&ima_temp_rules)) return -EINVAL; @@ -612,6 +620,14 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->func = MMAP_CHECK; else if (strcmp(args[0].from, "BPRM_CHECK") == 0) entry->func = BPRM_CHECK; + else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") == + 0) + entry->func = KEXEC_KERNEL_CHECK; + else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK") + == 0) + entry->func = KEXEC_INITRAMFS_CHECK; + else if (strcmp(args[0].from, "POLICY_CHECK") == 0) + entry->func = POLICY_CHECK; else result = -EINVAL; if (!result) @@ -770,6 +786,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) 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; audit_log_format(ab, "res=%d", !result); audit_log_end(ab); return result; @@ -855,7 +873,9 @@ static char *mask_tokens[] = { enum { func_file = 0, func_mmap, func_bprm, - func_module, func_firmware, func_post + func_module, func_firmware, func_post, + func_kexec_kernel, func_kexec_initramfs, + func_policy }; static char *func_tokens[] = { @@ -864,6 +884,9 @@ static char *func_tokens[] = { "BPRM_CHECK", "MODULE_CHECK", "FIRMWARE_CHECK", + "KEXEC_KERNEL_CHECK", + "KEXEC_INITRAMFS_CHECK", + "POLICY_CHECK", "POST_SETATTR" }; @@ -903,6 +926,49 @@ void ima_policy_stop(struct seq_file *m, void *v) #define mt(token) mask_tokens[token] #define ft(token) func_tokens[token] +/* + * policy_func_show - display the ima_hooks policy rule + */ +static void policy_func_show(struct seq_file *m, enum ima_hooks func) +{ + char tbuf[64] = {0,}; + + switch (func) { + case FILE_CHECK: + seq_printf(m, pt(Opt_func), ft(func_file)); + break; + case MMAP_CHECK: + seq_printf(m, pt(Opt_func), ft(func_mmap)); + break; + case BPRM_CHECK: + seq_printf(m, pt(Opt_func), ft(func_bprm)); + break; + case MODULE_CHECK: + seq_printf(m, pt(Opt_func), ft(func_module)); + break; + case FIRMWARE_CHECK: + seq_printf(m, pt(Opt_func), ft(func_firmware)); + break; + case POST_SETATTR: + seq_printf(m, pt(Opt_func), ft(func_post)); + break; + case KEXEC_KERNEL_CHECK: + seq_printf(m, pt(Opt_func), ft(func_kexec_kernel)); + break; + case KEXEC_INITRAMFS_CHECK: + seq_printf(m, pt(Opt_func), ft(func_kexec_initramfs)); + break; + case POLICY_CHECK: + seq_printf(m, pt(Opt_func), ft(func_policy)); + break; + default: + snprintf(tbuf, sizeof(tbuf), "%d", func); + seq_printf(m, pt(Opt_func), tbuf); + break; + } + seq_puts(m, " "); +} + int ima_policy_show(struct seq_file *m, void *v) { struct ima_rule_entry *entry = v; @@ -924,33 +990,8 @@ int ima_policy_show(struct seq_file *m, void *v) seq_puts(m, " "); - if (entry->flags & IMA_FUNC) { - switch (entry->func) { - case FILE_CHECK: - seq_printf(m, pt(Opt_func), ft(func_file)); - break; - case MMAP_CHECK: - seq_printf(m, pt(Opt_func), ft(func_mmap)); - break; - case BPRM_CHECK: - seq_printf(m, pt(Opt_func), ft(func_bprm)); - break; - case MODULE_CHECK: - seq_printf(m, pt(Opt_func), ft(func_module)); - break; - case FIRMWARE_CHECK: - seq_printf(m, pt(Opt_func), ft(func_firmware)); - break; - case POST_SETATTR: - seq_printf(m, pt(Opt_func), ft(func_post)); - break; - default: - snprintf(tbuf, sizeof(tbuf), "%d", entry->func); - seq_printf(m, pt(Opt_func), tbuf); - break; - } - seq_puts(m, " "); - } + if (entry->flags & IMA_FUNC) + policy_func_show(m, entry->func); if (entry->flags & IMA_MASK) { if (entry->mask & MAY_EXEC) diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 0b7404ebfa80..febd12ed9b55 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -15,8 +15,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <crypto/hash_info.h> - #include "ima.h" #include "ima_template_lib.h" diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 2934e3d377f1..f9bae04ba176 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -12,7 +12,6 @@ * File: ima_template_lib.c * Library of supported template fields. */ -#include <crypto/hash_info.h> #include "ima_template_lib.h" diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 5efe2ecc538d..e08935cf343f 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -45,16 +45,12 @@ #define IMA_MMAP_APPRAISED 0x00000800 #define IMA_BPRM_APPRAISE 0x00001000 #define IMA_BPRM_APPRAISED 0x00002000 -#define IMA_MODULE_APPRAISE 0x00004000 -#define IMA_MODULE_APPRAISED 0x00008000 -#define IMA_FIRMWARE_APPRAISE 0x00010000 -#define IMA_FIRMWARE_APPRAISED 0x00020000 +#define IMA_READ_APPRAISE 0x00004000 +#define IMA_READ_APPRAISED 0x00008000 #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ - IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \ - IMA_FIRMWARE_APPRAISE) + IMA_BPRM_APPRAISE | IMA_READ_APPRAISE) #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ - IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \ - IMA_FIRMWARE_APPRAISED) + IMA_BPRM_APPRAISED | IMA_READ_APPRAISED) enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01, @@ -94,7 +90,7 @@ struct ima_digest_data { struct signature_v2_hdr { uint8_t type; /* xattr type */ uint8_t version; /* signature format version */ - uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */ + uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */ uint32_t keyid; /* IMA key identifier - not X509/PGP specific */ uint16_t sig_size; /* signature size */ uint8_t sig[0]; /* signature payload */ @@ -109,8 +105,7 @@ struct integrity_iint_cache { enum integrity_status ima_file_status:4; enum integrity_status ima_mmap_status:4; enum integrity_status ima_bprm_status:4; - enum integrity_status ima_module_status:4; - enum integrity_status ima_firmware_status:4; + enum integrity_status ima_read_status:4; enum integrity_status evm_status:4; struct ima_digest_data *ima_hash; }; diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 907c1522ee46..c721e398893a 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -9,7 +9,6 @@ * 2 of the Licence, or (at your option) any later version. */ -#include <linux/module.h> #include <linux/init.h> #include <linux/seq_file.h> #include <linux/file.h> @@ -18,8 +17,6 @@ #include <keys/user-type.h> #include <keys/big_key-type.h> -MODULE_LICENSE("GPL"); - /* * Layout of key payload words. */ @@ -212,18 +209,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) return ret; } -/* - * Module stuff - */ static int __init big_key_init(void) { return register_key_type(&key_type_big_key); } - -static void __exit big_key_cleanup(void) -{ - unregister_key_type(&key_type_big_key); -} - -module_init(big_key_init); -module_exit(big_key_cleanup); +device_initcall(big_key_init); diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 696ccfa08d10..5adbfc32242f 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -28,11 +28,10 @@ #include <linux/random.h> #include <linux/rcupdate.h> #include <linux/scatterlist.h> -#include <linux/crypto.h> #include <linux/ctype.h> #include <crypto/hash.h> #include <crypto/sha.h> -#include <crypto/aes.h> +#include <crypto/skcipher.h> #include "encrypted.h" #include "ecryptfs_format.h" @@ -85,17 +84,17 @@ static const match_table_t key_tokens = { static int aes_get_sizes(void) { - struct crypto_blkcipher *tfm; + struct crypto_skcipher *tfm; - tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); + tfm = crypto_alloc_skcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { pr_err("encrypted_key: failed to alloc_cipher (%ld)\n", PTR_ERR(tfm)); return PTR_ERR(tfm); } - ivsize = crypto_blkcipher_ivsize(tfm); - blksize = crypto_blkcipher_blocksize(tfm); - crypto_free_blkcipher(tfm); + ivsize = crypto_skcipher_ivsize(tfm); + blksize = crypto_skcipher_blocksize(tfm); + crypto_free_skcipher(tfm); return 0; } @@ -401,28 +400,37 @@ static int get_derived_key(u8 *derived_key, enum derived_key_type key_type, return ret; } -static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key, - unsigned int key_len, const u8 *iv, - unsigned int ivsize) +static struct skcipher_request *init_skcipher_req(const u8 *key, + unsigned int key_len) { + struct skcipher_request *req; + struct crypto_skcipher *tfm; int ret; - desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(desc->tfm)) { + tfm = crypto_alloc_skcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { pr_err("encrypted_key: failed to load %s transform (%ld)\n", - blkcipher_alg, PTR_ERR(desc->tfm)); - return PTR_ERR(desc->tfm); + blkcipher_alg, PTR_ERR(tfm)); + return ERR_CAST(tfm); } - desc->flags = 0; - ret = crypto_blkcipher_setkey(desc->tfm, key, key_len); + ret = crypto_skcipher_setkey(tfm, key, key_len); if (ret < 0) { pr_err("encrypted_key: failed to setkey (%d)\n", ret); - crypto_free_blkcipher(desc->tfm); - return ret; + crypto_free_skcipher(tfm); + return ERR_PTR(ret); } - crypto_blkcipher_set_iv(desc->tfm, iv, ivsize); - return 0; + + req = skcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + pr_err("encrypted_key: failed to allocate request for %s\n", + blkcipher_alg); + crypto_free_skcipher(tfm); + return ERR_PTR(-ENOMEM); + } + + skcipher_request_set_callback(req, 0, NULL, NULL); + return req; } static struct key *request_master_key(struct encrypted_key_payload *epayload, @@ -467,7 +475,8 @@ static int derived_key_encrypt(struct encrypted_key_payload *epayload, { struct scatterlist sg_in[2]; struct scatterlist sg_out[1]; - struct blkcipher_desc desc; + struct crypto_skcipher *tfm; + struct skcipher_request *req; unsigned int encrypted_datalen; unsigned int padlen; char pad[16]; @@ -476,9 +485,9 @@ static int derived_key_encrypt(struct encrypted_key_payload *epayload, encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); padlen = encrypted_datalen - epayload->decrypted_datalen; - ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, - epayload->iv, ivsize); - if (ret < 0) + req = init_skcipher_req(derived_key, derived_keylen); + ret = PTR_ERR(req); + if (IS_ERR(req)) goto out; dump_decrypted_data(epayload); @@ -491,8 +500,12 @@ static int derived_key_encrypt(struct encrypted_key_payload *epayload, sg_init_table(sg_out, 1); sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen); - ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen); - crypto_free_blkcipher(desc.tfm); + skcipher_request_set_crypt(req, sg_in, sg_out, encrypted_datalen, + epayload->iv); + ret = crypto_skcipher_encrypt(req); + tfm = crypto_skcipher_reqtfm(req); + skcipher_request_free(req); + crypto_free_skcipher(tfm); if (ret < 0) pr_err("encrypted_key: failed to encrypt (%d)\n", ret); else @@ -565,15 +578,16 @@ static int derived_key_decrypt(struct encrypted_key_payload *epayload, { struct scatterlist sg_in[1]; struct scatterlist sg_out[2]; - struct blkcipher_desc desc; + struct crypto_skcipher *tfm; + struct skcipher_request *req; unsigned int encrypted_datalen; char pad[16]; int ret; encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); - ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, - epayload->iv, ivsize); - if (ret < 0) + req = init_skcipher_req(derived_key, derived_keylen); + ret = PTR_ERR(req); + if (IS_ERR(req)) goto out; dump_encrypted_data(epayload, encrypted_datalen); @@ -585,8 +599,12 @@ static int derived_key_decrypt(struct encrypted_key_payload *epayload, epayload->decrypted_datalen); sg_set_buf(&sg_out[1], pad, sizeof pad); - ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen); - crypto_free_blkcipher(desc.tfm); + skcipher_request_set_crypt(req, sg_in, sg_out, encrypted_datalen, + epayload->iv); + ret = crypto_skcipher_decrypt(req); + tfm = crypto_skcipher_reqtfm(req); + skcipher_request_free(req); + crypto_free_skcipher(tfm); if (ret < 0) goto out; dump_decrypted_data(epayload); diff --git a/security/keys/key.c b/security/keys/key.c index 09ef276c4bdc..b28755131687 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -296,6 +296,8 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->flags |= 1 << KEY_FLAG_IN_QUOTA; if (flags & KEY_ALLOC_TRUSTED) key->flags |= 1 << KEY_FLAG_TRUSTED; + if (flags & KEY_ALLOC_BUILT_IN) + key->flags |= 1 << KEY_FLAG_BUILTIN; #ifdef KEY_DEBUGGING key->magic = KEY_DEBUG_MAGIC; diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 0dcab20cdacd..90d61751ff12 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -744,6 +744,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, unsigned long handle; unsigned long lock; unsigned long token_mask = 0; + unsigned int digest_len; int i; int tpm2; @@ -752,7 +753,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return tpm2; opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1; - opt->digest_len = hash_digest_size[opt->hash]; while ((p = strsep(&c, " \t"))) { if (*p == '\0' || *p == ' ' || *p == '\t') @@ -812,8 +812,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay, for (i = 0; i < HASH_ALGO__LAST; i++) { if (!strcmp(args[0].from, hash_algo_name[i])) { opt->hash = i; - opt->digest_len = - hash_digest_size[opt->hash]; break; } } @@ -825,13 +823,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay, } break; case Opt_policydigest: - if (!tpm2 || - strlen(args[0].from) != (2 * opt->digest_len)) + digest_len = hash_digest_size[opt->hash]; + if (!tpm2 || strlen(args[0].from) != (2 * digest_len)) return -EINVAL; res = hex2bin(opt->policydigest, args[0].from, - opt->digest_len); + digest_len); if (res < 0) return -EINVAL; + opt->policydigest_len = digest_len; break; case Opt_policyhandle: if (!tpm2) diff --git a/security/security.c b/security/security.c index e8ffd92ae2eb..3644b0344d29 100644 --- a/security/security.c +++ b/security/security.c @@ -884,31 +884,33 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) return call_int_hook(kernel_create_files_as, 0, new, inode); } -int security_kernel_fw_from_file(struct file *file, char *buf, size_t size) +int security_kernel_module_request(char *kmod_name) +{ + return call_int_hook(kernel_module_request, 0, kmod_name); +} + +int security_kernel_read_file(struct file *file, enum kernel_read_file_id id) { int ret; - ret = call_int_hook(kernel_fw_from_file, 0, file, buf, size); + ret = call_int_hook(kernel_read_file, 0, file, id); if (ret) return ret; - return ima_fw_from_file(file, buf, size); -} -EXPORT_SYMBOL_GPL(security_kernel_fw_from_file); - -int security_kernel_module_request(char *kmod_name) -{ - return call_int_hook(kernel_module_request, 0, kmod_name); + return ima_read_file(file, id); } +EXPORT_SYMBOL_GPL(security_kernel_read_file); -int security_kernel_module_from_file(struct file *file) +int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, + enum kernel_read_file_id id) { int ret; - ret = call_int_hook(kernel_module_from_file, 0, file); + ret = call_int_hook(kernel_post_read_file, 0, file, buf, size, id); if (ret) return ret; - return ima_module_check(file); + return ima_post_read_file(file, buf, size, id); } +EXPORT_SYMBOL_GPL(security_kernel_post_read_file); int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) @@ -1691,12 +1693,12 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.kernel_act_as), .kernel_create_files_as = LIST_HEAD_INIT(security_hook_heads.kernel_create_files_as), - .kernel_fw_from_file = - LIST_HEAD_INIT(security_hook_heads.kernel_fw_from_file), .kernel_module_request = LIST_HEAD_INIT(security_hook_heads.kernel_module_request), - .kernel_module_from_file = - LIST_HEAD_INIT(security_hook_heads.kernel_module_from_file), + .kernel_read_file = + LIST_HEAD_INIT(security_hook_heads.kernel_read_file), + .kernel_post_read_file = + LIST_HEAD_INIT(security_hook_heads.kernel_post_read_file), .task_fix_setuid = LIST_HEAD_INIT(security_hook_heads.task_fix_setuid), .task_setpgid = LIST_HEAD_INIT(security_hook_heads.task_setpgid), diff --git a/security/selinux/Makefile b/security/selinux/Makefile index ad5cd76ec231..3411c33e2a44 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -13,7 +13,7 @@ selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o selinux-$(CONFIG_NETLABEL) += netlabel.o -ccflags-y := -Isecurity/selinux -Isecurity/selinux/include +ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f8110cfd80ff..912deee3f01e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2415,7 +2415,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, tty = get_current_tty(); if (tty) { - spin_lock(&tty_files_lock); + spin_lock(&tty->files_lock); if (!list_empty(&tty->tty_files)) { struct tty_file_private *file_priv; @@ -2430,7 +2430,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE)) drop_tty = 1; } - spin_unlock(&tty_files_lock); + spin_unlock(&tty->files_lock); tty_kref_put(tty); } /* Reset controlling tty. */ @@ -3249,7 +3249,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t static void selinux_inode_getsecid(struct inode *inode, u32 *secid) { - struct inode_security_struct *isec = inode_security(inode); + struct inode_security_struct *isec = inode_security_novalidate(inode); *secid = isec->sid; } diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 2bbb41822d8e..8495b9368190 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -83,6 +83,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] = { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, }; static struct nlmsg_perm nlmsg_xfrm_perms[] = diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 2d6e9bdea398..11f79013ae1f 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1442,9 +1442,13 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) * Don't do anything special for these. * XATTR_NAME_SMACKIPIN * XATTR_NAME_SMACKIPOUT - * XATTR_NAME_SMACKEXEC */ - if (strcmp(name, XATTR_NAME_SMACK) == 0) + if (strcmp(name, XATTR_NAME_SMACK) == 0) { + struct super_block *sbp = d_backing_inode(dentry)->i_sb; + struct superblock_smack *sbsp = sbp->s_security; + + isp->smk_inode = sbsp->smk_default; + } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) isp->smk_task = NULL; else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) isp->smk_mmap = NULL; @@ -1545,12 +1549,8 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid) * File Hooks */ -/** - * smack_file_permission - Smack check on file operations - * @file: unused - * @mask: unused - * - * Returns 0 +/* + * There is no smack_file_permission hook * * Should access checks be done on each read or write? * UNICOS and SELinux say yes. @@ -1559,10 +1559,6 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid) * I'll say no for now. Smack does not do the frequent * label changing that SELinux does. */ -static int smack_file_permission(struct file *file, int mask) -{ - return 0; -} /** * smack_file_alloc_security - assign a file security blob @@ -4503,16 +4499,10 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, return 0; } -/** - * smack_audit_rule_free - free smack rule representation - * @vrule: rule to be freed. - * +/* + * There is no need for a smack_audit_rule_free hook. * No memory was allocated. */ -static void smack_audit_rule_free(void *vrule) -{ - /* No-op */ -} #endif /* CONFIG_AUDIT */ @@ -4563,16 +4553,11 @@ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) return 0; } -/** - * smack_release_secctx - don't do anything. - * @secdata: unused - * @seclen: unused - * - * Exists to make sure nothing gets done, and properly +/* + * There used to be a smack_release_secctx hook + * that did nothing back when hooks were in a vector. + * Now that there's a list such a hook adds cost. */ -static void smack_release_secctx(char *secdata, u32 seclen) -{ -} static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) { @@ -4631,7 +4616,6 @@ static struct security_hook_list smack_hooks[] = { LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity), LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid), - LSM_HOOK_INIT(file_permission, smack_file_permission), LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security), LSM_HOOK_INIT(file_free_security, smack_file_free_security), LSM_HOOK_INIT(file_ioctl, smack_file_ioctl), @@ -4726,13 +4710,11 @@ static struct security_hook_list smack_hooks[] = { LSM_HOOK_INIT(audit_rule_init, smack_audit_rule_init), LSM_HOOK_INIT(audit_rule_known, smack_audit_rule_known), LSM_HOOK_INIT(audit_rule_match, smack_audit_rule_match), - LSM_HOOK_INIT(audit_rule_free, smack_audit_rule_free), #endif /* CONFIG_AUDIT */ LSM_HOOK_INIT(ismaclabel, smack_ismaclabel), LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx), LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid), - LSM_HOOK_INIT(release_secctx, smack_release_secctx), LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx), LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx), LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx), |