Once keys pin to the kernel module of their key type, having the DNS key type in the same modules as the resolver will introduce a circular dependency preventing module_exit() from ever running. Introduce dns_resolver_key.ko containing key_type_dns_resolver. On a module exit, drop the credentials and call key_gc_flush() in order the drain the remaining RCU callbacks. Signed-off-by: Jarkko Sakkinen --- net/Makefile | 2 +- net/dns_resolver/Kconfig | 15 +++++++++ net/dns_resolver/Makefile | 4 ++- net/dns_resolver/dns_key.c | 65 +++++------------------------------- net/dns_resolver/dns_query.c | 64 +++++++++++++++++++++++++++++++++++ net/dns_resolver/internal.h | 5 --- 6 files changed, 92 insertions(+), 63 deletions(-) diff --git a/net/Makefile b/net/Makefile index 5b2dd7f07a85..69c16a7851b4 100644 --- a/net/Makefile +++ b/net/Makefile @@ -55,7 +55,7 @@ obj-$(CONFIG_IEEE802154) += ieee802154/ obj-$(CONFIG_MAC802154) += mac802154/ obj-$(CONFIG_SYSCTL) += sysctl_net.o -obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ +obj-$(CONFIG_DNS_KEY) += dns_resolver/ obj-$(CONFIG_CEPH_LIB) += ceph/ obj-$(CONFIG_BATMAN_ADV) += batman-adv/ obj-$(CONFIG_NFC) += nfc/ diff --git a/net/dns_resolver/Kconfig b/net/dns_resolver/Kconfig index 7c2dba273e35..2618bad2e771 100644 --- a/net/dns_resolver/Kconfig +++ b/net/dns_resolver/Kconfig @@ -1,10 +1,25 @@ # SPDX-License-Identifier: GPL-2.0-only + +# +# Configuration for DNS Resolver key type +# +config DNS_KEY + tristate "DNS Resolver key type" + depends on KEYS + help + Support the key type used to cache DNS lookups independently of + the in-kernel DNS query service. + + To compile this as a module, choose M here: the module is called + dns_resolver_key. + # # Configuration for DNS Resolver # config DNS_RESOLVER tristate "DNS Resolver support" depends on KEYS + select DNS_KEY help Saying Y here will include support for the DNS Resolver key type which can be used to make upcalls to perform DNS lookups in diff --git a/net/dns_resolver/Makefile b/net/dns_resolver/Makefile index 877532d662d0..586e4c6514de 100644 --- a/net/dns_resolver/Makefile +++ b/net/dns_resolver/Makefile @@ -3,6 +3,8 @@ # Makefile for the Linux DNS Resolver. # +obj-$(CONFIG_DNS_KEY) += dns_resolver_key.o obj-$(CONFIG_DNS_RESOLVER) += dns_resolver.o -dns_resolver-y := dns_key.o dns_query.o +dns_resolver-y := dns_query.o +dns_resolver_key-y := dns_key.o diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index 451247864a63..fecbdc1d6beb 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -9,8 +9,8 @@ * Wang Lei (wang840925@gmail.com) * David Howells (dhowells@redhat.com) */ + #include -#include #include #include #include @@ -22,15 +22,12 @@ #include #include "internal.h" -MODULE_DESCRIPTION("DNS Resolver"); +MODULE_DESCRIPTION("DNS Resolver key type"); MODULE_AUTHOR("Wang Lei"); MODULE_LICENSE("GPL"); unsigned int dns_resolver_debug; -module_param_named(debug, dns_resolver_debug, uint, 0644); -MODULE_PARM_DESC(debug, "DNS Resolver debugging mask"); - -const struct cred *dns_resolver_cache; +EXPORT_SYMBOL_GPL(dns_resolver_debug); #define DNS_ERRORNO_OPTION "dnserror" @@ -318,61 +315,17 @@ struct key_type key_type_dns_resolver = { .describe = dns_resolver_describe, .read = dns_resolver_read, }; +EXPORT_SYMBOL_GPL(key_type_dns_resolver); -static int __init init_dns_resolver(void) +static int __init init_dns_key(void) { - struct cred *cred; - struct key *keyring; - int ret; - - /* create an override credential set with a special thread keyring in - * which DNS requests are cached - * - * this is used to prevent malicious redirections from being installed - * with add_key(). - */ - cred = prepare_kernel_cred(&init_task); - if (!cred) - return -ENOMEM; - - keyring = keyring_alloc(".dns_resolver", - GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, - (KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ, - KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); - goto failed_put_cred; - } - - ret = register_key_type(&key_type_dns_resolver); - if (ret < 0) - goto failed_put_key; - - /* instruct request_key() to use this special keyring as a cache for - * the results it looks up */ - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); - cred->thread_keyring = keyring; - cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; - dns_resolver_cache = cred; - - kdebug("DNS resolver keyring: %d\n", key_serial(keyring)); - return 0; - -failed_put_key: - key_put(keyring); -failed_put_cred: - put_cred(cred); - return ret; + return register_key_type(&key_type_dns_resolver); } -static void __exit exit_dns_resolver(void) +static void __exit exit_dns_key(void) { - key_revoke(dns_resolver_cache->thread_keyring); unregister_key_type(&key_type_dns_resolver); - put_cred(dns_resolver_cache); } -module_init(init_dns_resolver) -module_exit(exit_dns_resolver) -MODULE_LICENSE("GPL"); +module_init(init_dns_key); +module_exit(exit_dns_key); diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index b8fb9a1245bf..ae4dde190101 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c @@ -24,8 +24,10 @@ */ #include +#include #include #include +#include #include #include #include @@ -35,6 +37,8 @@ #include "internal.h" +static const struct cred *dns_resolver_cache; + /** * dns_query - Query the DNS * @net: The network namespace to operate in. @@ -137,3 +141,63 @@ int dns_query(struct net *net, return ret; } EXPORT_SYMBOL(dns_query); + +static int __init init_dns_resolver(void) +{ + struct cred *cred; + struct key *keyring; + int ret; + + /* + * Create an override credential set with a special thread keyring in + * which DNS requests are cached. This prevents malicious redirections + * from being installed with add_key(). + */ + cred = prepare_kernel_cred(&init_task); + if (!cred) + return -ENOMEM; + + keyring = keyring_alloc(".dns_resolver", + GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ, + KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); + if (IS_ERR(keyring)) { + ret = PTR_ERR(keyring); + goto failed_put_cred; + } + + /* + * Instruct request_key() to use this special keyring as a cache for + * the results it looks up. + */ + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); + cred->thread_keyring = keyring; + cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; + dns_resolver_cache = cred; + + kdebug("DNS resolver keyring: %d\n", key_serial(keyring)); + return 0; + +failed_put_cred: + put_cred(cred); + return ret; +} + +static void __exit exit_dns_resolver(void) +{ + key_revoke(dns_resolver_cache->thread_keyring); + put_cred(dns_resolver_cache); + /* Drain deferred credential and keyring destruction. */ + key_gc_flush(); +} + +module_init(init_dns_resolver); +module_exit(exit_dns_resolver); + +MODULE_DESCRIPTION("DNS Resolver"); +MODULE_AUTHOR("Wang Lei"); +MODULE_LICENSE("GPL"); + +module_param_named(debug, dns_resolver_debug, uint, 0644); +MODULE_PARM_DESC(debug, "DNS Resolver debugging mask"); diff --git a/net/dns_resolver/internal.h b/net/dns_resolver/internal.h index d0d8edcea092..3478bad78a9a 100644 --- a/net/dns_resolver/internal.h +++ b/net/dns_resolver/internal.h @@ -18,11 +18,6 @@ enum { dns_key_error, }; -/* - * dns_key.c - */ -extern const struct cred *dns_resolver_cache; - /* * debug tracing */ -- 2.47.3