The module authentication functionality will also be used by the hash-based module authentication. To make it usable even if CONFIG_MODULE_SIG is disabled, move it to a new file.
Signed-off-by: Thomas Weißschuh <[email protected]> --- kernel/module/auth.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ kernel/module/internal.h | 14 ++++++-- kernel/module/main.c | 6 ++-- kernel/module/signing.c | 90 ++---------------------------------------------- 4 files changed, 103 insertions(+), 92 deletions(-) diff --git a/kernel/module/auth.c b/kernel/module/auth.c index 956ac63d9d33..831a13eb0c9b 100644 --- a/kernel/module/auth.c +++ b/kernel/module/auth.c @@ -5,10 +5,16 @@ * Written by David Howells ([email protected]) */ +#include <linux/errno.h> #include <linux/export.h> #include <linux/module.h> +#include <linux/module_signature.h> #include <linux/moduleparam.h> +#include <linux/security.h> +#include <linux/string.h> #include <linux/types.h> +#include <uapi/linux/module.h> +#include "internal.h" #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "module." @@ -30,3 +36,82 @@ void set_module_sig_enforced(void) { sig_enforce = true; } + +static int mod_verify_sig(const void *mod, struct load_info *info) +{ + struct module_signature ms; + size_t sig_len, modlen = info->len; + int ret; + + if (modlen <= sizeof(ms)) + return -EBADMSG; + + memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); + + ret = mod_check_sig(&ms, modlen, "module"); + if (ret) + return ret; + + sig_len = be32_to_cpu(ms.sig_len); + modlen -= sig_len + sizeof(ms); + info->len = modlen; + + return module_sig_check(mod, modlen, mod + modlen, sig_len); +} + +int module_auth_check(struct load_info *info, int flags) +{ + int err = -ENODATA; + const unsigned long markerlen = sizeof(MODULE_SIGNATURE_MARKER) - 1; + const char *reason; + const void *mod = info->hdr; + bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS | + MODULE_INIT_IGNORE_VERMAGIC); + /* + * Do not allow mangled modules as a module with version information + * removed is no longer the module that was signed. + */ + if (!mangled_module && + info->len > markerlen && + memcmp(mod + info->len - markerlen, MODULE_SIGNATURE_MARKER, markerlen) == 0) { + /* We truncate the module to discard the signature */ + info->len -= markerlen; + err = mod_verify_sig(mod, info); + if (!err) { + info->auth_ok = true; + return 0; + } + } + + /* + * We don't permit modules to be loaded into the trusted kernels + * without a valid signature on them, but if we're not enforcing, + * certain errors are non-fatal. + */ + switch (err) { + case -ENODATA: + reason = "unsigned module"; + break; + case -ENOPKG: + reason = "module with unsupported crypto"; + break; + case -ENOKEY: + reason = "module with unavailable key"; + break; + + default: + /* + * All other errors are fatal, including lack of memory, + * unparseable signatures, and signature check failures -- + * even if signatures aren't required. + */ + return err; + } + + if (is_module_sig_enforced()) { + pr_notice("Loading of %s is rejected\n", reason); + return -EKEYREJECTED; + } + + return security_locked_down(LOCKDOWN_MODULE_SIGNATURE); +} diff --git a/kernel/module/internal.h b/kernel/module/internal.h index f8f425b167f1..d923e31a5d8e 100644 --- a/kernel/module/internal.h +++ b/kernel/module/internal.h @@ -336,14 +336,24 @@ void module_mark_ro_after_init(const Elf_Ehdr *hdr, Elf_Shdr *sechdrs, const char *secstrings); #ifdef CONFIG_MODULE_SIG -int module_sig_check(struct load_info *info, int flags); +int module_sig_check(const void *mod, size_t mod_len, const void *sig, size_t sig_len); #else /* !CONFIG_MODULE_SIG */ -static inline int module_sig_check(struct load_info *info, int flags) +static inline int module_sig_check(const void *mod, size_t mod_len, + const void *sig, size_t sig_len) { return 0; } #endif /* !CONFIG_MODULE_SIG */ +#ifdef CONFIG_MODULE_AUTH +int module_auth_check(struct load_info *info, int flags); +#else /* !CONFIG_MODULE_AUTH */ +static inline int module_auth_check(struct load_info *info, int flags) +{ + return 0; +} +#endif /* !CONFIG_MODULE_AUTH */ + #ifdef CONFIG_DEBUG_KMEMLEAK void kmemleak_load_module(const struct module *mod, const struct load_info *info); #else /* !CONFIG_DEBUG_KMEMLEAK */ diff --git a/kernel/module/main.c b/kernel/module/main.c index cd8a74df117e..55a010383a8d 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -3428,8 +3428,8 @@ static int load_module(struct load_info *info, const char __user *uargs, char *after_dashes; /* - * Do the signature check (if any) first. All that - * the signature check needs is info->len, it does + * Do the authentication checks (if any) first. All that + * the authentication checks need is info->len, it does * not need any of the section info. That can be * set up later. This will minimize the chances * of a corrupt module causing problems before @@ -3439,7 +3439,7 @@ static int load_module(struct load_info *info, const char __user *uargs, * off the sig length at the end of the module, making * checks against info->len more correct. */ - err = module_sig_check(info, flags); + err = module_auth_check(info, flags); if (err) goto free_copy; diff --git a/kernel/module/signing.c b/kernel/module/signing.c index 07a786723221..a49317e3c66f 100644 --- a/kernel/module/signing.c +++ b/kernel/module/signing.c @@ -5,98 +5,14 @@ * Written by David Howells ([email protected]) */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/module_signature.h> -#include <linux/string.h> +#include <linux/types.h> #include <linux/verification.h> -#include <linux/security.h> -#include <crypto/public_key.h> -#include <uapi/linux/module.h> #include "internal.h" -/* - * Verify the signature on a module. - */ -static int mod_verify_sig(const void *mod, struct load_info *info) +int module_sig_check(const void *mod, size_t mod_len, const void *sig, size_t sig_len) { - struct module_signature ms; - size_t sig_len, modlen = info->len; - int ret; - - if (modlen <= sizeof(ms)) - return -EBADMSG; - - memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); - - ret = mod_check_sig(&ms, modlen, "module"); - if (ret) - return ret; - - sig_len = be32_to_cpu(ms.sig_len); - modlen -= sig_len + sizeof(ms); - info->len = modlen; - - return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len, + return verify_pkcs7_signature(mod, mod_len, sig, sig_len, VERIFY_USE_SECONDARY_KEYRING, VERIFYING_MODULE_SIGNATURE, NULL, NULL); } - -int module_sig_check(struct load_info *info, int flags) -{ - int err = -ENODATA; - const unsigned long markerlen = sizeof(MODULE_SIGNATURE_MARKER) - 1; - const char *reason; - const void *mod = info->hdr; - bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS | - MODULE_INIT_IGNORE_VERMAGIC); - /* - * Do not allow mangled modules as a module with version information - * removed is no longer the module that was signed. - */ - if (!mangled_module && - info->len > markerlen && - memcmp(mod + info->len - markerlen, MODULE_SIGNATURE_MARKER, markerlen) == 0) { - /* We truncate the module to discard the signature */ - info->len -= markerlen; - err = mod_verify_sig(mod, info); - if (!err) { - info->auth_ok = true; - return 0; - } - } - - /* - * We don't permit modules to be loaded into the trusted kernels - * without a valid signature on them, but if we're not enforcing, - * certain errors are non-fatal. - */ - switch (err) { - case -ENODATA: - reason = "unsigned module"; - break; - case -ENOPKG: - reason = "module with unsupported crypto"; - break; - case -ENOKEY: - reason = "module with unavailable key"; - break; - - default: - /* - * All other errors are fatal, including lack of memory, - * unparseable signatures, and signature check failures -- - * even if signatures aren't required. - */ - return err; - } - - if (is_module_sig_enforced()) { - pr_notice("Loading of %s is rejected\n", reason); - return -EKEYREJECTED; - } - - return security_locked_down(LOCKDOWN_MODULE_SIGNATURE); -} -- 2.54.0
