Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorri...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Aug 2018 05:54:12 +0000 (22:54 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Aug 2018 05:54:12 +0000 (22:54 -0700)
Pull integrity updates from James Morris:
 "This adds support for EVM signatures based on larger digests, contains
  a new audit record AUDIT_INTEGRITY_POLICY_RULE to differentiate the
  IMA policy rules from the IMA-audit messages, addresses two deadlocks
  due to either loading or searching for crypto algorithms, and cleans
  up the audit messages"

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  EVM: fix return value check in evm_write_xattrs()
  integrity: prevent deadlock during digsig verification.
  evm: Allow non-SHA1 digital signatures
  evm: Don't deadlock if a crypto algorithm is unavailable
  integrity: silence warning when CONFIG_SECURITYFS is not enabled
  ima: Differentiate auditing policy rules from "audit" actions
  ima: Do not audit if CONFIG_INTEGRITY_AUDIT is not set
  ima: Use audit_log_format() rather than audit_log_string()
  ima: Call audit_log_string() rather than logging it untrusted

16 files changed:
crypto/api.c
include/linux/crypto.h
include/linux/integrity.h
include/uapi/linux/audit.h
security/integrity/digsig_asymmetric.c
security/integrity/evm/Kconfig
security/integrity/evm/evm.h
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/evm/evm_secfs.c
security/integrity/iint.c
security/integrity/ima/Kconfig
security/integrity/ima/ima_policy.c
security/integrity/integrity.h
security/integrity/integrity_audit.c
security/security.c

index 0ee632b..7aca9f8 100644 (file)
@@ -229,7 +229,7 @@ static struct crypto_alg *crypto_larval_lookup(const char *name, u32 type,
        mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
 
        alg = crypto_alg_lookup(name, type, mask);
-       if (!alg) {
+       if (!alg && !(mask & CRYPTO_NOLOAD)) {
                request_module("crypto-%s", name);
 
                if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask &
index 6eb0610..e8839d3 100644 (file)
 #define CRYPTO_ALG_OPTIONAL_KEY                0x00004000
 
 /*
+ * Don't trigger module loading
+ */
+#define CRYPTO_NOLOAD                  0x00008000
+
+/*
  * Transform masks and values (for crt_flags).
  */
 #define CRYPTO_TFM_NEED_KEY            0x00000001
index 858d3f4..54c853e 100644 (file)
@@ -44,4 +44,17 @@ static inline void integrity_load_keys(void)
 }
 #endif /* CONFIG_INTEGRITY */
 
+#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
+
+extern int integrity_kernel_module_request(char *kmod_name);
+
+#else
+
+static inline int integrity_kernel_module_request(char *kmod_name)
+{
+       return 0;
+}
+
+#endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
+
 #endif /* _LINUX_INTEGRITY_H */
index 4e3eaba..818ae69 100644 (file)
 #define AUDIT_INTEGRITY_PCR        1804 /* PCR invalidation msgs */
 #define AUDIT_INTEGRITY_RULE       1805 /* policy rule */
 #define AUDIT_INTEGRITY_EVM_XATTR   1806 /* New EVM-covered xattr */
+#define AUDIT_INTEGRITY_POLICY_RULE 1807 /* IMA policy rules */
 
 #define AUDIT_KERNEL           2000    /* Asynchronous audit record. NOT A REQUEST. */
 
index ab6a029..6dc0751 100644 (file)
@@ -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;
+}
index d593346..6022185 100644 (file)
@@ -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
index 1257c3c..c3f437f 100644 (file)
@@ -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);
index b605243..8a3905b 100644 (file)
@@ -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);
index f9eff50..7f3f54d 100644 (file)
@@ -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);
 
index 637eb99..77de71b 100644 (file)
@@ -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) {
index 149faa8..5a68100 100644 (file)
@@ -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;
index 004919d..13b4463 100644 (file)
@@ -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
index 1659abb..8c94998 100644 (file)
@@ -657,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)
 {
@@ -679,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;
index 0bb372e..e60473b 100644 (file)
@@ -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
index ab10a25..82c98f7 100644 (file)
@@ -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=");
index ab4f963..47cfff0 100644 (file)
@@ -1032,7 +1032,12 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
 
 int security_kernel_module_request(char *kmod_name)
 {
-       return call_int_hook(kernel_module_request, 0, kmod_name);
+       int ret;
+
+       ret = call_int_hook(kernel_module_request, 0, kmod_name);
+       if (ret)
+               return ret;
+       return integrity_kernel_module_request(kmod_name);
 }
 
 int security_kernel_read_file(struct file *file, enum kernel_read_file_id id)