diff options
author | Jason Gunthorpe | 2018-08-16 22:13:03 +0200 |
---|---|---|
committer | Jason Gunthorpe | 2018-08-16 22:21:29 +0200 |
commit | 0a3173a5f09bc58a3638ecfd0a80bdbae55e123c (patch) | |
tree | d6c0bc84863cca54dfbde3b7463e5d49c82af9f1 /security/integrity | |
parent | Revert "net/smc: Replace ib_query_gid with rdma_get_gid_attr" (diff) | |
parent | Merge tag 'for-linus-4.19-ofs1' of git://git.kernel.org/pub/scm/linux/kernel/... (diff) | |
download | kernel-qcow2-linux-0a3173a5f09bc58a3638ecfd0a80bdbae55e123c.tar.gz kernel-qcow2-linux-0a3173a5f09bc58a3638ecfd0a80bdbae55e123c.tar.xz kernel-qcow2-linux-0a3173a5f09bc58a3638ecfd0a80bdbae55e123c.zip |
Merge branch 'linus/master' into rdma.git for-next
rdma.git merge resolution for the 4.19 merge window
Conflicts:
drivers/infiniband/core/rdma_core.c
- Use the rdma code and revise with the new spelling for
atomic_fetch_add_unless
drivers/nvme/host/rdma.c
- Replace max_sge with max_send_sge in new blk code
drivers/nvme/target/rdma.c
- Use the blk code and revise to use NULL for ib_post_recv when
appropriate
- Replace max_sge with max_recv_sge in new blk code
net/rds/ib_send.c
- Use the net code and revise to use NULL for ib_post_recv when
appropriate
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/digsig_asymmetric.c | 23 | ||||
-rw-r--r-- | security/integrity/evm/Kconfig | 1 | ||||
-rw-r--r-- | security/integrity/evm/evm.h | 10 | ||||
-rw-r--r-- | security/integrity/evm/evm_crypto.c | 50 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 19 | ||||
-rw-r--r-- | security/integrity/evm/evm_secfs.c | 4 | ||||
-rw-r--r-- | security/integrity/iint.c | 9 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 59 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 7 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 4 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 4 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 16 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 84 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 57 | ||||
-rw-r--r-- | security/integrity/ima/ima_queue.c | 4 | ||||
-rw-r--r-- | security/integrity/integrity.h | 15 | ||||
-rw-r--r-- | security/integrity/integrity_audit.c | 6 |
17 files changed, 282 insertions, 90 deletions
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index ab6a029062a1..6dc075144508 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -115,3 +115,26 @@ int asymmetric_verify(struct key *keyring, const char *sig, pr_debug("%s() = %d\n", __func__, ret); return ret; } + +/** + * integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests + * @kmod_name: kernel module name + * + * We have situation, when public_key_verify_signature() in case of RSA + * algorithm use alg_name to store internal information in order to + * construct an algorithm on the fly, but crypto_larval_lookup() will try + * to use alg_name in order to load kernel module with same name. + * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules, + * we are safe to fail such module request from crypto_larval_lookup(). + * + * In this way we prevent modprobe execution during digsig verification + * and avoid possible deadlock if modprobe and/or it's dependencies + * also signed with digsig. + */ +int integrity_kernel_module_request(char *kmod_name) +{ + if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0) + return -EINVAL; + + return 0; +} diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index d593346d0bba..60221852b26a 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -4,6 +4,7 @@ config EVM select ENCRYPTED_KEYS select CRYPTO_HMAC select CRYPTO_SHA1 + select CRYPTO_HASH_INFO default n help EVM protects a file's security extended attributes against diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 1257c3c24723..c3f437f5db10 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -47,6 +47,11 @@ extern struct crypto_shash *hash_tfm; /* List of EVM protected security xattrs */ extern struct list_head evm_config_xattrnames; +struct evm_digest { + struct ima_digest_data hdr; + char digest[IMA_MAX_DIGEST_SIZE]; +} __packed; + int evm_init_key(void); int evm_update_evmxattr(struct dentry *dentry, const char *req_xattr_name, @@ -54,10 +59,11 @@ int evm_update_evmxattr(struct dentry *dentry, size_t req_xattr_value_len); int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, - size_t req_xattr_value_len, char *digest); + size_t req_xattr_value_len, struct evm_digest *data); int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, - size_t req_xattr_value_len, char type, char *digest); + size_t req_xattr_value_len, char type, + struct evm_digest *data); int evm_init_hmac(struct inode *inode, const struct xattr *xattr, char *hmac_val); int evm_init_secfs(void); diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index b60524310855..8a3905bb02c7 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -21,6 +21,7 @@ #include <linux/evm.h> #include <keys/encrypted-type.h> #include <crypto/hash.h> +#include <crypto/hash_info.h> #include "evm.h" #define EVMKEY "evm-key" @@ -29,7 +30,7 @@ static unsigned char evmkey[MAX_KEY_SIZE]; static int evmkey_len = MAX_KEY_SIZE; struct crypto_shash *hmac_tfm; -struct crypto_shash *hash_tfm; +static struct crypto_shash *evm_tfm[HASH_ALGO__LAST]; static DEFINE_MUTEX(mutex); @@ -38,7 +39,6 @@ static DEFINE_MUTEX(mutex); static unsigned long evm_set_key_flags; static char * const evm_hmac = "hmac(sha1)"; -static char * const evm_hash = "sha1"; /** * evm_set_key() - set EVM HMAC key from the kernel @@ -74,10 +74,10 @@ busy: } EXPORT_SYMBOL_GPL(evm_set_key); -static struct shash_desc *init_desc(char type) +static struct shash_desc *init_desc(char type, uint8_t hash_algo) { long rc; - char *algo; + const char *algo; struct crypto_shash **tfm; struct shash_desc *desc; @@ -89,15 +89,16 @@ static struct shash_desc *init_desc(char type) tfm = &hmac_tfm; algo = evm_hmac; } else { - tfm = &hash_tfm; - algo = evm_hash; + tfm = &evm_tfm[hash_algo]; + algo = hash_algo_name[hash_algo]; } if (*tfm == NULL) { mutex_lock(&mutex); if (*tfm) goto out; - *tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC); + *tfm = crypto_alloc_shash(algo, 0, + CRYPTO_ALG_ASYNC | CRYPTO_NOLOAD); if (IS_ERR(*tfm)) { rc = PTR_ERR(*tfm); pr_err("Can not allocate %s (reason: %ld)\n", algo, rc); @@ -186,10 +187,10 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, * each xattr, but attempt to re-use the previously allocated memory. */ static int evm_calc_hmac_or_hash(struct dentry *dentry, - const char *req_xattr_name, - const char *req_xattr_value, - size_t req_xattr_value_len, - char type, char *digest) + const char *req_xattr_name, + const char *req_xattr_value, + size_t req_xattr_value_len, + uint8_t type, struct evm_digest *data) { struct inode *inode = d_backing_inode(dentry); struct xattr_list *xattr; @@ -204,10 +205,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, inode->i_sb->s_user_ns != &init_user_ns) return -EOPNOTSUPP; - desc = init_desc(type); + desc = init_desc(type, data->hdr.algo); if (IS_ERR(desc)) return PTR_ERR(desc); + data->hdr.length = crypto_shash_digestsize(desc->tfm); + error = -ENODATA; list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) { bool is_ima = false; @@ -239,7 +242,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry, if (is_ima) ima_present = true; } - hmac_add_misc(desc, inode, type, digest); + hmac_add_misc(desc, inode, type, data->digest); /* Portable EVM signatures must include an IMA hash */ if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present) @@ -252,18 +255,18 @@ out: int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, size_t req_xattr_value_len, - char *digest) + struct evm_digest *data) { return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, - req_xattr_value_len, EVM_XATTR_HMAC, digest); + req_xattr_value_len, EVM_XATTR_HMAC, data); } int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name, const char *req_xattr_value, size_t req_xattr_value_len, - char type, char *digest) + char type, struct evm_digest *data) { return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, - req_xattr_value_len, type, digest); + req_xattr_value_len, type, data); } static int evm_is_immutable(struct dentry *dentry, struct inode *inode) @@ -303,7 +306,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, const char *xattr_value, size_t xattr_value_len) { struct inode *inode = d_backing_inode(dentry); - struct evm_ima_xattr_data xattr_data; + struct evm_digest data; int rc = 0; /* @@ -316,13 +319,14 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, if (rc) return -EPERM; + data.hdr.algo = HASH_ALGO_SHA1; rc = evm_calc_hmac(dentry, xattr_name, xattr_value, - xattr_value_len, xattr_data.digest); + xattr_value_len, &data); if (rc == 0) { - xattr_data.type = EVM_XATTR_HMAC; + data.hdr.xattr.sha1.type = EVM_XATTR_HMAC; rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM, - &xattr_data, - sizeof(xattr_data), 0); + &data.hdr.xattr.data[1], + SHA1_DIGEST_SIZE + 1, 0); } else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) { rc = __vfs_removexattr(dentry, XATTR_NAME_EVM); } @@ -334,7 +338,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, { struct shash_desc *desc; - desc = init_desc(EVM_XATTR_HMAC); + desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); if (IS_ERR(desc)) { pr_info("init_desc failed\n"); return PTR_ERR(desc); diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index f9eff5041e4c..7f3f54d89a6e 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -25,6 +25,7 @@ #include <linux/magic.h> #include <crypto/hash.h> +#include <crypto/hash_info.h> #include <crypto/algapi.h> #include "evm.h" @@ -134,8 +135,9 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, struct integrity_iint_cache *iint) { struct evm_ima_xattr_data *xattr_data = NULL; - struct evm_ima_xattr_data calc; + struct signature_v2_hdr *hdr; enum integrity_status evm_status = INTEGRITY_PASS; + struct evm_digest digest; struct inode *inode; int rc, xattr_len; @@ -171,25 +173,28 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, evm_status = INTEGRITY_FAIL; goto out; } + + digest.hdr.algo = HASH_ALGO_SHA1; rc = evm_calc_hmac(dentry, xattr_name, xattr_value, - xattr_value_len, calc.digest); + xattr_value_len, &digest); if (rc) break; - rc = crypto_memneq(xattr_data->digest, calc.digest, - sizeof(calc.digest)); + rc = crypto_memneq(xattr_data->digest, digest.digest, + SHA1_DIGEST_SIZE); if (rc) rc = -EINVAL; break; case EVM_IMA_XATTR_DIGSIG: case EVM_XATTR_PORTABLE_DIGSIG: + hdr = (struct signature_v2_hdr *)xattr_data; + digest.hdr.algo = hdr->hash_algo; rc = evm_calc_hash(dentry, xattr_name, xattr_value, - xattr_value_len, xattr_data->type, - calc.digest); + xattr_value_len, xattr_data->type, &digest); if (rc) break; rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, (const char *)xattr_data, xattr_len, - calc.digest, sizeof(calc.digest)); + digest.digest, digest.hdr.length); if (!rc) { inode = d_backing_inode(dentry); diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 637eb999e340..77de71b7794c 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -193,8 +193,8 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf, return -E2BIG; ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_EVM_XATTR); - if (IS_ERR(ab)) - return PTR_ERR(ab); + if (!ab) + return -ENOMEM; xattr = kmalloc(sizeof(struct xattr_list), GFP_KERNEL); if (!xattr) { diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 149faa81f6f0..5a6810041e5c 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -219,10 +219,13 @@ static int __init integrity_fs_init(void) { integrity_dir = securityfs_create_dir("integrity", NULL); if (IS_ERR(integrity_dir)) { - pr_err("Unable to create integrity sysfs dir: %ld\n", - PTR_ERR(integrity_dir)); + int ret = PTR_ERR(integrity_dir); + + if (ret != -ENODEV) + pr_err("Unable to create integrity sysfs dir: %d\n", + ret); integrity_dir = NULL; - return PTR_ERR(integrity_dir); + return ret; } return 0; diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 6a8f67714c83..13b446328dda 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -12,6 +12,7 @@ config IMA select TCG_TIS if TCG_TPM && X86 select TCG_CRB if TCG_TPM && ACPI select TCG_IBMVTPM if TCG_TPM && PPC_PSERIES + select INTEGRITY_AUDIT if AUDIT help The Trusted Computing Group(TCG) runtime Integrity Measurement Architecture(IMA) maintains a list of hash @@ -156,6 +157,64 @@ config IMA_APPRAISE <http://linux-ima.sourceforge.net> If unsure, say N. +config IMA_APPRAISE_BUILD_POLICY + bool "IMA build time configured policy rules" + depends on IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS + default n + help + This option defines an IMA appraisal policy at build time, which + is enforced at run time without having to specify a builtin + policy name on the boot command line. The build time appraisal + policy rules persist after loading a custom policy. + + Depending on the rules configured, this policy may require kernel + modules, firmware, the kexec kernel image, and/or the IMA policy + to be signed. Unsigned files might prevent the system from + booting or applications from working properly. + +config IMA_APPRAISE_REQUIRE_FIRMWARE_SIGS + bool "Appraise firmware signatures" + depends on IMA_APPRAISE_BUILD_POLICY + default n + help + This option defines a policy requiring all firmware to be signed, + including the regulatory.db. If both this option and + CFG80211_REQUIRE_SIGNED_REGDB are enabled, then both signature + verification methods are necessary. + +config IMA_APPRAISE_REQUIRE_KEXEC_SIGS + bool "Appraise kexec kernel image signatures" + depends on IMA_APPRAISE_BUILD_POLICY + default n + help + Enabling this rule will require all kexec'ed kernel images to + be signed and verified by a public key on the trusted IMA + keyring. + + Kernel image signatures can not be verified by the original + kexec_load syscall. Enabling this rule will prevent its + usage. + +config IMA_APPRAISE_REQUIRE_MODULE_SIGS + bool "Appraise kernel modules signatures" + depends on IMA_APPRAISE_BUILD_POLICY + default n + help + Enabling this rule will require all kernel modules to be signed + and verified by a public key on the trusted IMA keyring. + + Kernel module signatures can only be verified by IMA-appraisal, + via the finit_module syscall. Enabling this rule will prevent + the usage of the init_module syscall. + +config IMA_APPRAISE_REQUIRE_POLICY_SIGS + bool "Appraise IMA policy signature" + depends on IMA_APPRAISE_BUILD_POLICY + default n + help + Enabling this rule will require the IMA policy to be signed and + and verified by a key on the trusted IMA keyring. + config IMA_APPRAISE_BOOTPARAM bool "ima_appraise boot parameter" depends on IMA_APPRAISE diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 354bb5716ce3..67db9d9454ca 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -53,9 +53,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; extern int ima_policy_flag; /* set during initialization */ -extern int ima_used_chip; extern int ima_hash_algo; extern int ima_appraise; +extern struct tpm_chip *ima_tpm_chip; /* IMA event related data */ struct ima_event_data { @@ -232,13 +232,14 @@ int ima_policy_show(struct seq_file *m, void *v); #define IMA_APPRAISE_MODULES 0x08 #define IMA_APPRAISE_FIRMWARE 0x10 #define IMA_APPRAISE_POLICY 0x20 +#define IMA_APPRAISE_KEXEC 0x40 #ifdef CONFIG_IMA_APPRAISE 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 xattr_len); 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, @@ -254,7 +255,7 @@ static inline int ima_appraise_measurement(enum ima_hooks func, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, - int xattr_len, int opened) + int xattr_len) { return INTEGRITY_UNKNOWN; } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 8bd7a0733e51..deec1804a00a 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -212,7 +212,7 @@ 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 xattr_len) { static const char op[] = "appraise_data"; const char *cause = "unknown"; @@ -231,7 +231,7 @@ int ima_appraise_measurement(enum ima_hooks func, cause = iint->flags & IMA_DIGSIG_REQUIRED ? "IMA-signature-required" : "missing-hash"; status = INTEGRITY_NOLABEL; - if (opened & FILE_CREATED) + if (file->f_mode & FMODE_CREATED) iint->flags |= IMA_NEW_FILE; if ((iint->flags & IMA_NEW_FILE) && (!(iint->flags & IMA_DIGSIG_REQUIRED) || diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 4e085a17124f..7e7e7e7c250a 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -631,10 +631,10 @@ int ima_calc_buffer_hash(const void *buf, loff_t len, static void __init ima_pcrread(int idx, u8 *pcr) { - if (!ima_used_chip) + if (!ima_tpm_chip) return; - if (tpm_pcr_read(NULL, idx, pcr) != 0) + if (tpm_pcr_read(ima_tpm_chip, idx, pcr) != 0) pr_err("Error Communicating to TPM chip\n"); } diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 29b72cd2502e..faac9ecaa0ae 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -26,7 +26,7 @@ /* name for boot aggregate entry */ static const char *boot_aggregate_name = "boot_aggregate"; -int ima_used_chip; +struct tpm_chip *ima_tpm_chip; /* Add the boot aggregate to the IMA measurement list and extend * the PCR register. @@ -64,7 +64,7 @@ static int __init ima_add_boot_aggregate(void) iint->ima_hash->algo = HASH_ALGO_SHA1; iint->ima_hash->length = SHA1_DIGEST_SIZE; - if (ima_used_chip) { + if (ima_tpm_chip) { result = ima_calc_boot_aggregate(&hash.hdr); if (result < 0) { audit_cause = "hashing_error"; @@ -106,17 +106,11 @@ void __init ima_load_x509(void) int __init ima_init(void) { - u8 pcr_i[TPM_DIGEST_SIZE]; int rc; - ima_used_chip = 0; - rc = tpm_pcr_read(NULL, 0, pcr_i); - if (rc == 0) - ima_used_chip = 1; - - if (!ima_used_chip) - pr_info("No TPM chip found, activating TPM-bypass! (rc=%d)\n", - rc); + ima_tpm_chip = tpm_default_chip(); + if (!ima_tpm_chip) + pr_info("No TPM chip found, activating TPM-bypass!\n"); rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA); if (rc) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index dca44cf7838e..2d31921fbda4 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -168,7 +168,7 @@ void ima_file_free(struct file *file) static int process_measurement(struct file *file, const struct cred *cred, u32 secid, char *buf, loff_t size, int mask, - enum ima_hooks func, int opened) + enum ima_hooks func) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; @@ -294,7 +294,7 @@ static int process_measurement(struct file *file, const struct cred *cred, if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { inode_lock(inode); rc = ima_appraise_measurement(func, iint, file, pathname, - xattr_value, xattr_len, opened); + xattr_value, xattr_len); inode_unlock(inode); } if (action & IMA_AUDIT) @@ -338,7 +338,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) if (file && (prot & PROT_EXEC)) { security_task_getsecid(current, &secid); return process_measurement(file, current_cred(), secid, NULL, - 0, MAY_EXEC, MMAP_CHECK, 0); + 0, MAY_EXEC, MMAP_CHECK); } return 0; @@ -364,13 +364,13 @@ int ima_bprm_check(struct linux_binprm *bprm) security_task_getsecid(current, &secid); ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0, - MAY_EXEC, BPRM_CHECK, 0); + MAY_EXEC, BPRM_CHECK); if (ret) return ret; security_cred_getsecid(bprm->cred, &secid); return process_measurement(bprm->file, bprm->cred, secid, NULL, 0, - MAY_EXEC, CREDS_CHECK, 0); + MAY_EXEC, CREDS_CHECK); } /** @@ -383,14 +383,14 @@ 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 opened) +int ima_file_check(struct file *file, int mask) { u32 secid; security_task_getsecid(current, &secid); return process_measurement(file, current_cred(), secid, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | - MAY_APPEND), FILE_CHECK, opened); + MAY_APPEND), FILE_CHECK); } EXPORT_SYMBOL_GPL(ima_file_check); @@ -429,16 +429,14 @@ void ima_post_path_mknod(struct dentry *dentry) */ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) { - bool sig_enforce = is_module_sig_enforced(); - - if (!file && read_id == READING_MODULE) { - if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES) && - (ima_appraise & IMA_APPRAISE_ENFORCE)) { - pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n"); - return -EACCES; /* INTEGRITY_UNKNOWN */ - } - return 0; /* We rely on module signature checking */ - } + /* + * READING_FIRMWARE_PREALLOC_BUFFER + * + * Do devices using pre-allocated memory run the risk of the + * firmware being accessible to the device prior to the completion + * of IMA's signature verification any more than when using two + * buffers? + */ return 0; } @@ -472,14 +470,13 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, if (!file && read_id == READING_FIRMWARE) { if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && - (ima_appraise & IMA_APPRAISE_ENFORCE)) + (ima_appraise & IMA_APPRAISE_ENFORCE)) { + pr_err("Prevent firmware loading_store.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */ + } return 0; } - if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */ - return 0; - /* permit signed certs */ if (!file && read_id == READING_X509_CERTIFICATE) return 0; @@ -493,7 +490,50 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, func = read_idmap[read_id] ?: FILE_CHECK; security_task_getsecid(current, &secid); return process_measurement(file, current_cred(), secid, buf, size, - MAY_READ, func, 0); + MAY_READ, func); +} + +/** + * ima_load_data - appraise decision based on policy + * @id: kernel load data caller identifier + * + * Callers of this LSM hook can not measure, appraise, or audit the + * data provided by userspace. Enforce policy rules requring a file + * signature (eg. kexec'ed kernel image). + * + * For permission return 0, otherwise return -EACCES. + */ +int ima_load_data(enum kernel_load_data_id id) +{ + bool sig_enforce; + + if ((ima_appraise & IMA_APPRAISE_ENFORCE) != IMA_APPRAISE_ENFORCE) + return 0; + + switch (id) { + case LOADING_KEXEC_IMAGE: + if (ima_appraise & IMA_APPRAISE_KEXEC) { + pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); + return -EACCES; /* INTEGRITY_UNKNOWN */ + } + break; + case LOADING_FIRMWARE: + if (ima_appraise & IMA_APPRAISE_FIRMWARE) { + pr_err("Prevent firmware sysfs fallback loading.\n"); + return -EACCES; /* INTEGRITY_UNKNOWN */ + } + break; + case LOADING_MODULE: + sig_enforce = is_module_sig_enforced(); + + if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES)) { + pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n"); + return -EACCES; /* INTEGRITY_UNKNOWN */ + } + default: + break; + } + return 0; } static int __init init_ima(void) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index cdcc9a7b4e24..8c9499867c91 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -49,6 +49,7 @@ int ima_policy_flag; static int temp_ima_appraise; +static int build_ima_appraise __ro_after_init; #define MAX_LSM_RULES 6 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, @@ -162,6 +163,25 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { #endif }; +static struct ima_rule_entry build_appraise_rules[] __ro_after_init = { +#ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS + {.action = APPRAISE, .func = MODULE_CHECK, + .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, +#endif +#ifdef CONFIG_IMA_APPRAISE_REQUIRE_FIRMWARE_SIGS + {.action = APPRAISE, .func = FIRMWARE_CHECK, + .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, +#endif +#ifdef CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS + {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, + .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, +#endif +#ifdef CONFIG_IMA_APPRAISE_REQUIRE_POLICY_SIGS + {.action = APPRAISE, .func = POLICY_CHECK, + .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, +#endif +}; + static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { {.action = APPRAISE, .func = MODULE_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, @@ -435,7 +455,7 @@ void ima_update_policy_flag(void) ima_policy_flag |= entry->action; } - ima_appraise |= temp_ima_appraise; + ima_appraise |= (build_ima_appraise | temp_ima_appraise); if (!ima_appraise) ima_policy_flag &= ~IMA_APPRAISE; } @@ -448,6 +468,8 @@ static int ima_appraise_flag(enum ima_hooks func) return IMA_APPRAISE_FIRMWARE; else if (func == POLICY_CHECK) return IMA_APPRAISE_POLICY; + else if (func == KEXEC_KERNEL_CHECK) + return IMA_APPRAISE_KEXEC; return 0; } @@ -486,8 +508,8 @@ void __init ima_init_policy(void) } /* - * Insert the appraise rules requiring file signatures, prior to - * any other appraise rules. + * Insert the builtin "secure_boot" policy 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); @@ -495,6 +517,26 @@ void __init ima_init_policy(void) ima_appraise_flag(secure_boot_rules[i].func); } + /* + * Insert the build time appraise rules requiring file signatures + * for both the initial and custom policies, prior to other appraise + * rules. + */ + for (i = 0; i < ARRAY_SIZE(build_appraise_rules); i++) { + struct ima_rule_entry *entry; + + if (!secure_boot_entries) + list_add_tail(&build_appraise_rules[i].list, + &ima_default_rules); + + entry = kmemdup(&build_appraise_rules[i], sizeof(*entry), + GFP_KERNEL); + if (entry) + list_add_tail(&entry->list, &ima_policy_rules); + build_ima_appraise |= + ima_appraise_flag(build_appraise_rules[i].func); + } + for (i = 0; i < appraise_entries; i++) { list_add_tail(&default_appraise_rules[i].list, &ima_default_rules); @@ -615,14 +657,16 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value, bool (*rule_operator)(kuid_t, kuid_t)) { + if (!ab) + return; + if (rule_operator == &uid_gt) audit_log_format(ab, "%s>", key); else if (rule_operator == &uid_lt) audit_log_format(ab, "%s<", key); else audit_log_format(ab, "%s=", key); - audit_log_untrustedstring(ab, value); - audit_log_format(ab, " "); + audit_log_format(ab, "%s ", value); } static void ima_log_string(struct audit_buffer *ab, char *key, char *value) { @@ -637,7 +681,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) bool uid_token; int result = 0; - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); + ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, + AUDIT_INTEGRITY_POLICY_RULE); entry->uid = INVALID_UID; entry->fowner = INVALID_UID; diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 418f35e38015..b186819bd5aa 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -142,10 +142,10 @@ static int ima_pcr_extend(const u8 *hash, int pcr) { int result = 0; - if (!ima_used_chip) + if (!ima_tpm_chip) return result; - result = tpm_pcr_extend(NULL, pcr, hash); + result = tpm_pcr_extend(ima_tpm_chip, pcr, hash); if (result != 0) pr_err("Error Communicating to TPM chip, result: %d\n", result); return result; diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 0bb372eed62a..e60473b13a8d 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -15,6 +15,7 @@ #include <linux/integrity.h> #include <crypto/sha.h> #include <linux/key.h> +#include <linux/audit.h> /* iint action cache flags */ #define IMA_MEASURE 0x00000001 @@ -199,6 +200,13 @@ static inline void evm_load_x509(void) void integrity_audit_msg(int audit_msgno, struct inode *inode, const unsigned char *fname, const char *op, const char *cause, int result, int info); + +static inline struct audit_buffer * +integrity_audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type) +{ + return audit_log_start(ctx, gfp_mask, type); +} + #else static inline void integrity_audit_msg(int audit_msgno, struct inode *inode, const unsigned char *fname, @@ -206,4 +214,11 @@ static inline void integrity_audit_msg(int audit_msgno, struct inode *inode, int result, int info) { } + +static inline struct audit_buffer * +integrity_audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type) +{ + return NULL; +} + #endif diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c index ab10a25310a1..82c98f7d217e 100644 --- a/security/integrity/integrity_audit.c +++ b/security/integrity/integrity_audit.c @@ -45,11 +45,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); audit_log_task_context(ab); - audit_log_format(ab, " op="); - audit_log_string(ab, op); - audit_log_format(ab, " cause="); - audit_log_string(ab, cause); - audit_log_format(ab, " comm="); + audit_log_format(ab, " op=%s cause=%s comm=", op, cause); audit_log_untrustedstring(ab, get_task_comm(name, current)); if (fname) { audit_log_format(ab, " name="); |