From: Krzysztof Struczynski krzysztof.struczynski@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49KW1 CVE: NA
--------------------------------
Add key domain tag to the search criteria in digsig module. If the domain tag is not set for the keys from the given keyring, it is set to NULL and the behaviour is unchanged.
The key domain tag is added to the ima appraisal keys loaded to the system ima keyring.
Signed-off-by: Krzysztof Struczynski krzysztof.struczynski@huawei.com Reviewed-by: Zhang Tianxing zhangtianxing3@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- include/linux/digsig.h | 11 ++++--- lib/digsig.c | 11 +++---- security/integrity/digsig.c | 40 ++++++++++++++++++++++---- security/integrity/digsig_asymmetric.c | 20 ++++++++----- security/integrity/integrity.h | 11 ++++--- 5 files changed, 67 insertions(+), 26 deletions(-)
diff --git a/include/linux/digsig.h b/include/linux/digsig.h index 2ace69e41088..9e4121253899 100644 --- a/include/linux/digsig.h +++ b/include/linux/digsig.h @@ -44,13 +44,16 @@ struct signature_hdr {
#if defined(CONFIG_SIGNATURE) || defined(CONFIG_SIGNATURE_MODULE)
-int digsig_verify(struct key *keyring, const char *sig, int siglen, - const char *digest, int digestlen); +int digsig_verify(struct key *keyring, struct key_tag *domain_tag, + const char *sig, int siglen, const char *digest, + int digestlen);
#else
-static inline int digsig_verify(struct key *keyring, const char *sig, - int siglen, const char *digest, int digestlen) +static inline int digsig_verify(struct key *keyring, + struct key_tag *domain_tag, + const char *sig, int siglen, const char *digest, + int digestlen) { return -EOPNOTSUPP; } diff --git a/lib/digsig.c b/lib/digsig.c index 04b5e55ed95f..4cf5327327c8 100644 --- a/lib/digsig.c +++ b/lib/digsig.c @@ -196,8 +196,8 @@ static int digsig_verify_rsa(struct key *key, * Normally hash of the content is used as a data for this function. * */ -int digsig_verify(struct key *keyring, const char *sig, int siglen, - const char *data, int datalen) +int digsig_verify(struct key *keyring, struct key_tag *domain_tag, + const char *sig, int siglen, const char *data, int datalen) { int err = -ENOMEM; struct signature_hdr *sh = (struct signature_hdr *)sig; @@ -217,14 +217,15 @@ int digsig_verify(struct key *keyring, const char *sig, int siglen, if (keyring) { /* search in specific keyring */ key_ref_t kref; - kref = keyring_search(make_key_ref(keyring, 1UL), - &key_type_user, name, true); + kref = keyring_search_tag(make_key_ref(keyring, 1UL), + &key_type_user, name, + domain_tag, true); if (IS_ERR(kref)) key = ERR_CAST(kref); else key = key_ref_to_ptr(kref); } else { - key = request_key(&key_type_user, name, NULL); + key = request_key_tag(&key_type_user, name, domain_tag, NULL); } if (IS_ERR(key)) { pr_err("key not found, id: %s\n", name); diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 0f518dcfde05..4d2579a2c5ea 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -16,6 +16,7 @@ #include <linux/vmalloc.h> #include <crypto/public_key.h> #include <keys/system_keyring.h> +#include <linux/ima.h>
#include "integrity.h"
@@ -32,6 +33,16 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = { ".platform", };
+static unsigned long keyring_alloc_flags[INTEGRITY_KEYRING_MAX] = { + KEY_ALLOC_NOT_IN_QUOTA, +#ifdef CONFIG_IMA_NS + KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_DOMAIN_IMA, +#else + KEY_ALLOC_NOT_IN_QUOTA, +#endif + KEY_ALLOC_NOT_IN_QUOTA, +}; + #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY #define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted #else @@ -57,10 +68,22 @@ static struct key *integrity_keyring_from_id(const unsigned int id) return keyring[id]; }
+static struct key_tag *domain_tag_from_id(const unsigned int id) +{ + if (id >= INTEGRITY_KEYRING_MAX) + return ERR_PTR(-EINVAL); + + if (id == INTEGRITY_KEYRING_IMA) + return current->nsproxy->ima_ns->key_domain; + + return NULL; +} + int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, const char *digest, int digestlen) { struct key *keyring; + struct key_tag *domain_tag;
if (siglen < 2) return -EINVAL; @@ -69,14 +92,18 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, if (IS_ERR(keyring)) return PTR_ERR(keyring);
+ domain_tag = domain_tag_from_id(id); + if (IS_ERR(domain_tag)) + return PTR_ERR(domain_tag); + switch (sig[1]) { case 1: /* v1 API expect signature without xattr type */ - return digsig_verify(keyring, sig + 1, siglen - 1, digest, - digestlen); + return digsig_verify(keyring, domain_tag, + sig + 1, siglen - 1, digest, digestlen); case 2: - return asymmetric_verify(keyring, sig, siglen, digest, - digestlen); + return asymmetric_verify(keyring, domain_tag, sig, siglen, + digest, digestlen); }
return -EOPNOTSUPP; @@ -102,7 +129,8 @@ static int __init __integrity_init_keyring(const unsigned int id,
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), KGIDT_INIT(0), cred, perm, - KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL); + keyring_alloc_flags[id], + restriction, NULL); if (IS_ERR(keyring[id])) { err = PTR_ERR(keyring[id]); pr_info("Can't allocate %s keyring (%d)\n", @@ -154,7 +182,7 @@ int __init integrity_add_key(const unsigned int id, const void *data,
key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric", NULL, data, size, perm, - KEY_ALLOC_NOT_IN_QUOTA); + keyring_alloc_flags[id]); if (IS_ERR(key)) { rc = PTR_ERR(key); pr_err("Problem loading X.509 certificate %d\n", rc); diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 92dc64755e53..8f4cffd73602 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -20,7 +20,9 @@ /* * Request an asymmetric key. */ -static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) +static struct key *request_asymmetric_key(struct key *keyring, + struct key_tag *domain_tag, + uint32_t keyid) { struct key *key; char name[12]; @@ -45,14 +47,16 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) /* search in specific keyring */ key_ref_t kref;
- kref = keyring_search(make_key_ref(keyring, 1), - &key_type_asymmetric, name, true); + kref = keyring_search_tag(make_key_ref(keyring, 1), + &key_type_asymmetric, name, + domain_tag, true); if (IS_ERR(kref)) key = ERR_CAST(kref); else key = key_ref_to_ptr(kref); } else { - key = request_key(&key_type_asymmetric, name, NULL); + key = request_key_tag(&key_type_asymmetric, + name, domain_tag, NULL); }
if (IS_ERR(key)) { @@ -89,8 +93,9 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) return key; }
-int asymmetric_verify(struct key *keyring, const char *sig, - int siglen, const char *data, int datalen) +int asymmetric_verify(struct key *keyring, struct key_tag *domain_tag, + const char *sig, int siglen, + const char *data, int datalen) { struct public_key_signature pks; struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig; @@ -108,7 +113,8 @@ int asymmetric_verify(struct key *keyring, const char *sig, if (hdr->hash_algo >= HASH_ALGO__LAST) return -ENOPKG;
- key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid)); + key = request_asymmetric_key(keyring, domain_tag, + be32_to_cpu(hdr->keyid)); if (IS_ERR(key)) return PTR_ERR(key);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 78078d55fd33..423e61627716 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -256,11 +256,14 @@ static inline int __init integrity_load_cert(const unsigned int id, #endif /* CONFIG_INTEGRITY_SIGNATURE */
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS -int asymmetric_verify(struct key *keyring, const char *sig, - int siglen, const char *data, int datalen); +int asymmetric_verify(struct key *keyring, struct key_tag *domain_tag, + const char *sig, int siglen, + const char *data, int datalen); #else -static inline int asymmetric_verify(struct key *keyring, const char *sig, - int siglen, const char *data, int datalen) +static inline int asymmetric_verify(struct key *keyring, + struct key_tag *domain_tag, + const char *sig, int siglen, + const char *data, int datalen) { return -EOPNOTSUPP; }