diff --git a/include/linux/digsig.h b/include/linux/digsig.h index 2ace69e4108850674030db3cf785f117d3391110..9e412125389934a944c00648898215ca16ae721f 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 04b5e55ed95f5b3419ad23b6f5ad4984b451303e..4cf5327327c8a238e5a82188380f079a85d574ac 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 0f518dcfde0528066ddbfd4e1a8f359d53c4dcef..4d2579a2c5ea40db34f3c6ee50b1bbcc4710df66 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -16,6 +16,7 @@ #include #include #include +#include #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 92dc64755e53374b7a32c3ec84116a4ffd19fa33..8f4cffd7360227da0f8c0597e08adfac0ca80863 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 78078d55fd331346b3ca626608935de837740d3c..423e616277165284ac95115a8437973fa4d4734c 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; }