From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from todd.t-8ch.de (todd.t-8ch.de [159.69.126.157]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 351BD3DC4C2; Tue, 5 May 2026 09:05:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.69.126.157 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777971939; cv=none; b=EdtA7t/Ti+FBBumvyDWne9L5EBxvQUFrhKO2NpQ/VnRbjRWYFi7hqPZ5+BSmKcMQ3rTTFhk68PULODP9L0I1lYxqAcwA58CMoHKcOUeRrD38el6u2LL3L942jekk4O7MxYgBedPdNOKFU/B25gSIDvvsJ47x0P1WVmJ3CVS4aEw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777971939; c=relaxed/simple; bh=z587DQf7ydM5gOPKNIBxSBWu9EUeBOTRuUfIH6UhiJM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eOHt9CyB/yR3txJMsmxyAHQ2e7xeITzBSNBNpTVPM7BSC6eyVkLP8NyqJRRKBwiexNg4cTYhu+b8hIPNmCXKbB7e6i1495+QXoet+aHMBeLK8Cri25Hh0agRVzC/64Z24y+hefh85t1+oIzzysGzVJK2fq1B+9uqcJWZK6/PumM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=weissschuh.net; spf=pass smtp.mailfrom=weissschuh.net; dkim=pass (1024-bit key) header.d=weissschuh.net header.i=@weissschuh.net header.b=aIgpWDKX; arc=none smtp.client-ip=159.69.126.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=weissschuh.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=weissschuh.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=weissschuh.net header.i=@weissschuh.net header.b="aIgpWDKX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=weissschuh.net; s=mail; t=1777971923; bh=z587DQf7ydM5gOPKNIBxSBWu9EUeBOTRuUfIH6UhiJM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=aIgpWDKXrg76P12O4zkGtJLBuZn8YCeI7ZzPJs6xm6dzdrhNjHvlCsyJmUEjNrCDX nnsToJ9+zngAbg5KnB2apzV2zul/tNtdLxtFkKFMh/CCZJG5ISZHQPcUMzBA/S/C/H yDIMRiiPrmSBoXKa210qmdtwe3j1bEA6l8n1iwS4= From: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= Date: Tue, 05 May 2026 11:05:12 +0200 Subject: [PATCH v5 08/14] module: Move authentication logic into dedicated new file Precedence: bulk X-Mailing-List: linux-arch@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Message-Id: <20260505-module-hashes-v5-8-e174a5a49fce@weissschuh.net> References: <20260505-module-hashes-v5-0-e174a5a49fce@weissschuh.net> In-Reply-To: <20260505-module-hashes-v5-0-e174a5a49fce@weissschuh.net> To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Eduard Zingerman , Kumar Kartikeya Dwivedi , Nathan Chancellor , Nicolas Schier , Arnd Bergmann , Luis Chamberlain , Petr Pavlu , Sami Tolvanen , Daniel Gomez , Paul Moore , James Morris , "Serge E. Hallyn" , Jonathan Corbet , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , Naveen N Rao , Mimi Zohar , Roberto Sassu , Dmitry Kasatkin , Eric Snowberg , Nicolas Schier , Daniel Gomez , Aaron Tomlin , "Christophe Leroy (CS GROUP)" , Nicolas Bouchinet , Xiu Jianfeng , Christophe Leroy Cc: Martin KaFai Lau , Song Liu , Yonghong Song , Jiri Olsa , bpf@vger.kernel.org, =?utf-8?q?Fabian_Gr=C3=BCnbichler?= , Arnout Engelen , Mattia Rizzolo , kpcyrd , Christian Heusel , =?utf-8?q?C=C3=A2ju_Mihai-Drosi?= , Eric Biggers , Sebastian Andrzej Siewior , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, linux-modules@vger.kernel.org, linux-security-module@vger.kernel.org, linux-doc@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, linux-integrity@vger.kernel.org, debian-kernel@lists.debian.org, =?utf-8?q?Thomas_Wei=C3=9Fschuh?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1777971921; l=8567; i=linux@weissschuh.net; s=20221212; h=from:subject:message-id; bh=z587DQf7ydM5gOPKNIBxSBWu9EUeBOTRuUfIH6UhiJM=; b=0QD9Bo5ArZ/toPAgrZ/Kwp8g1MN5vGvLlI3JacHftC7LXDAwqZfm7Tb5hscKQ74Tdp4pPzyNi hUJ9tsUkDfZBUtISxftgnKStnD51XKADZgJpNxcoo2sKOBdHsu9omPS X-Developer-Key: i=linux@weissschuh.net; a=ed25519; pk=KcycQgFPX2wGR5azS7RhpBqedglOZVgRPfdFSPB1LNw= 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 --- 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 (dhowells@redhat.com) */ +#include #include #include +#include #include +#include +#include #include +#include +#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 (dhowells@redhat.com) */ -#include -#include -#include -#include -#include +#include #include -#include -#include -#include #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