From nobody Tue Dec 30 07:41:30 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 387EEC47071 for ; Sat, 18 Nov 2023 02:58:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232915AbjKRC6N (ORCPT ); Fri, 17 Nov 2023 21:58:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51722 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232854AbjKRC6L (ORCPT ); Fri, 17 Nov 2023 21:58:11 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4B72120 for ; Fri, 17 Nov 2023 18:58:08 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-5bc3be6a91bso29617217b3.1 for ; Fri, 17 Nov 2023 18:58:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1700276288; x=1700881088; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Ua0IE78OI3V4iuwp2QSoKWUWADgF+ZXc9DJoA62znV8=; b=F3jRmmh2EUK+OfbPUNe20oapoSvEhNicFeHmxJ/ixVlLf1ZBkP22OAHd1hmZUCvZsu 1VaOG1HutflZuwff1N+aB+ElGpfYHHU4huPgCGLS5IZyL4BRRPQ8VynifDc2AdQB3/AZ LQr8z+SzK+8PjJn21ItvbT/PJLJ3KSP9engLbXThkfCdz9Z12vPovpZ/s8mLqf9A+mXq wEG/0DJy8KVjt0wODrqkkmyxJO2w+loCUzYFLF6rD6dw6h9bxF5mjwovRIMujp1TbwC4 WYN/glhBqY5rX8A4edfLXeIaR7hNqbYMSTGlnh669YFyHe0NwOxbEmVhM3L7YXwH/IKe ou1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700276288; x=1700881088; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Ua0IE78OI3V4iuwp2QSoKWUWADgF+ZXc9DJoA62znV8=; b=aCPZQa2DRY4KobAkV78LsXJpuFRkivk3xb0WLBMgVYzbVYr7O85p5byZcR9RaqpxqZ 5BM4/FMfXUOer7zPEfgWYECZve9Lmz0fGJhJOugHVPOuGHFgnmgEYqw5fjiCT+Eaz0Sz P7UdCSWZLhjc+DKT43tn7ZMsIPS+vy52F9jrGC/SZmCsGcKvLafg014/U6TcuXu3mIvU xuJtJOi1N8sbJ6LLBkemtNqT1Ii/q8oEbllR+fViyF4HHDTsOfFnD3JJmWWw77cE0AYX ixUrbnR/+qJR9XMQy08Sb+soqkBABRdlNUV6x7yy+fJtBm1TxWvQRxLKVzTFRKlQHFrh uiMA== X-Gm-Message-State: AOJu0Yx5dH2zQdrtC8YDO7oq0xL7zXcift3nZhTmK0H4VyQnVvgx5A/g 4FgCrVk+HkjyGz0v6MmauZ6fJ1kDaFry X-Google-Smtp-Source: AGHT+IERm4l8aRNMXSza7sGbPFbUkdTe33rpYyqpHWn57Z3BfKIw6SvQM+EZkHQPY3+Yu4peV7KukI7LkV3P X-Received: from anyblade.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:1791]) (user=mmaurer job=sendgmr) by 2002:a25:e6c1:0:b0:daf:3e84:d016 with SMTP id d184-20020a25e6c1000000b00daf3e84d016mr29963ybh.2.1700276288083; Fri, 17 Nov 2023 18:58:08 -0800 (PST) Date: Sat, 18 Nov 2023 02:54:42 +0000 In-Reply-To: <20231118025748.2778044-1-mmaurer@google.com> Mime-Version: 1.0 References: <20231118025748.2778044-1-mmaurer@google.com> X-Mailer: git-send-email 2.43.0.rc0.421.g78406f8d94-goog Message-ID: <20231118025748.2778044-2-mmaurer@google.com> Subject: [PATCH v2 1/5] export_report: Rehabilitate script From: Matthew Maurer To: Masahiro Yamada , Nick Desaulniers , Miguel Ojeda , Gary Guo , Luis Chamberlain Cc: Nathan Chancellor , Nicolas Schier , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, linux-kbuild@vger.kernel.org, rust-for-linux@vger.kernel.org, Laura Abbott , Matthew Maurer Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" * modules.order has .o files when in a build dir, support this * .mod.c source layout has changed, update regexes to match * Add a stage 3, to be more robust against additional .mod.c content Signed-off-by: Matthew Maurer --- scripts/export_report.pl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/export_report.pl b/scripts/export_report.pl index feb3d5542a62..dcef915405f3 100755 --- a/scripts/export_report.pl +++ b/scripts/export_report.pl @@ -55,6 +55,7 @@ sub collectcfiles { open my $fh, '< modules.order' or die "cannot open modules.order: $!\n= "; while (<$fh>) { s/\.ko$/.mod.c/; + s/\.o$/.mod.c/; push (@file, $_) } close($fh); @@ -120,10 +121,14 @@ foreach my $thismod (@allcfiles) { next; } if ($state =3D=3D 1) { - $state =3D 2 if ($_ =3D~ /__attribute__\(\(section\("__versions"\)\)\)/= ); + $state =3D 2 if ($_ =3D~ /__used __section\("__versions"\)/); next; } if ($state =3D=3D 2) { + if ( $_ =3D~ /};/ ) { + $state =3D 3; + next; + } if ( $_ !~ /0x[0-9a-f]+,/ ) { next; } @@ -133,7 +138,7 @@ foreach my $thismod (@allcfiles) { push(@{$MODULE{$thismod}} , $sym); } } - if ($state !=3D 2) { + if ($state !=3D 3) { warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n"; $modversion_warnings++; } --=20 2.43.0.rc0.421.g78406f8d94-goog From nobody Tue Dec 30 07:41:30 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A4A5AC072A2 for ; Sat, 18 Nov 2023 02:58:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346434AbjKRC6Y (ORCPT ); Fri, 17 Nov 2023 21:58:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51806 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232985AbjKRC6S (ORCPT ); Fri, 17 Nov 2023 21:58:18 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C24DF10EC for ; Fri, 17 Nov 2023 18:58:10 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-5c5c760fc98so25994517b3.3 for ; Fri, 17 Nov 2023 18:58:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1700276290; x=1700881090; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=0CSTyxlHVYn/ezKsio8aqvsiIxg7WzrWt9V3HTJto8U=; b=eIzuuwsPiEMfVxBZqOFzAybH6lWeHSZntgre+oOF9e/MAHaK7cTyQ5XNy8th+52/6m iKeLzOWVEkVqd0jH5X5uGM34X1itelqC44YhFo6vtyvjA2+Pm7shHtG2UWXgz56ivuKN ySkwqMdFFYv887JB+Y5lH7/UJC0R5psrz2jvReqsFHd8uovty1RVsw9LA+zeTNhb7UjT LyPmrQv0twBsa81DBN6pkonAExBEMMWIogWuKMgyX+AgL0UZ6kSw/1R69oTGtadUIJm6 1QFSMkXVzVc8lnIMSumfNkjKk7vQuAuLex4s9vPtYm9JeWDYB0RbqmBiZ6vd0RvAF7KJ Vi/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700276290; x=1700881090; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0CSTyxlHVYn/ezKsio8aqvsiIxg7WzrWt9V3HTJto8U=; b=EFNP96WqKDuQbNwuStlRmkGvgu3zsouA5lNMLyIuLcti1f0Hb4ZrwuC8/w6d06evpQ a+ZWhhpE7nqn0UsuHv2N1G2ipAPSLnj7N8NcjHc3M6NGK2JMQyQ7M7aXfNsnyadg2OQh drlWnwJB2JjU17WUvJZ1dvybwkGcbICIKRo829TDcz+iLcGpw4wkWxOfgtOnWWT0H0qD riuK9Jtc8dW+kXCN19WZ3zBtgvAsj9BvDHv4GogXvWNT86Pi9bmRxn0w87MdU3j0KV6C LQnEg1xrI0RVpuqDe7MfLMplpYMaKtwc8dc7PUYzOkrPmlRv8cJDGlG82BErdzFwE0Ne zDVA== X-Gm-Message-State: AOJu0YyZlayH1hSaVmyEXuKZLGejvTp9N/F+d96+6Y3W/KPTEsK0PJVA P9OVSskRY7tLtIzZuG4AmJZnQ8Q/4NAt X-Google-Smtp-Source: AGHT+IFpKeTENBwI0ASlwBKxE16vOwrL2b0cwNdYaTwSpUxnAe/isEmFPMOfFv0fKsPZ7HsumU6uXU5f3ukQ X-Received: from anyblade.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:1791]) (user=mmaurer job=sendgmr) by 2002:a25:38f:0:b0:d9a:6007:223a with SMTP id 137-20020a25038f000000b00d9a6007223amr24384ybd.8.1700276289931; Fri, 17 Nov 2023 18:58:09 -0800 (PST) Date: Sat, 18 Nov 2023 02:54:43 +0000 In-Reply-To: <20231118025748.2778044-1-mmaurer@google.com> Mime-Version: 1.0 References: <20231118025748.2778044-1-mmaurer@google.com> X-Mailer: git-send-email 2.43.0.rc0.421.g78406f8d94-goog Message-ID: <20231118025748.2778044-3-mmaurer@google.com> Subject: [PATCH v2 2/5] modules: Refactor + kdoc elf_validity_cached_copy From: Matthew Maurer To: Masahiro Yamada , Nick Desaulniers , Miguel Ojeda , Gary Guo , Luis Chamberlain Cc: Nathan Chancellor , Nicolas Schier , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, linux-kbuild@vger.kernel.org, rust-for-linux@vger.kernel.org, Laura Abbott , Matthew Maurer Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Functionality is almost identical, just structured for better documentation and readability. Changes: * Section names are checked for *all* non-SHT_NULL sections, not just SHF_ALLOC sections. We have code that accesses section names of non-SHF_ALLOC sections (see find_any_sec for example) * The section name check occurs *before* strcmping on section names. Previously, it was possible to use an out-of-bounds offset to strcmp against ".modinfo" or ".gnu.linkonce.this_module" * strtab is checked for NUL lead+termination and nonzero size * The symbol table is swept to ensure offsets are inbounds of strtab While some of these oversights would normally be worrying, all of the potentially unverified accesses occur after signature check, and only in response to a user who can load a kernel module. Signed-off-by: Matthew Maurer --- kernel/module/internal.h | 7 +- kernel/module/main.c | 585 +++++++++++++++++++++++++++++---------- 2 files changed, 444 insertions(+), 148 deletions(-) diff --git a/kernel/module/internal.h b/kernel/module/internal.h index c8b7b4dcf782..d8dc52eb9c82 100644 --- a/kernel/module/internal.h +++ b/kernel/module/internal.h @@ -80,7 +80,12 @@ struct load_info { unsigned int used_pages; #endif struct { - unsigned int sym, str, mod, vers, info, pcpu; + unsigned int sym; + unsigned int str; + unsigned int mod; + unsigned int vers; + unsigned int info; + unsigned int pcpu; } index; }; =20 diff --git a/kernel/module/main.c b/kernel/module/main.c index 98fedfdb8db5..8b2848b3183a 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -193,6 +193,38 @@ static unsigned int find_sec(const struct load_info *i= nfo, const char *name) return 0; } =20 +/** + * find_any_unique_sec() - Find a unique section index by name + * @info: Load info for the module to scan + * @name: Name of the section we're looking for + * + * Locates a unique section by name. Ignores SHF_ALLOC. + * + * Return: Section index if found uniquely, zero if absent, negative count + * of total instances if multiple were found. + */ +static int find_any_unique_sec(const struct load_info *info, const char *n= ame) +{ + unsigned int idx; + unsigned int count =3D 0; + int i; + + for (i =3D 1; i < info->hdr->e_shnum; i++) { + if (strcmp(info->secstrings + info->sechdrs[i].sh_name, + name) =3D=3D 0) { + count++; + idx =3D i; + } + } + if (count =3D=3D 1) { + return idx; + } else if (count =3D=3D 0) { + return 0; + } else { + return -count; + } +} + /* Find a module section, or NULL. */ static void *section_addr(const struct load_info *info, const char *name) { @@ -1627,7 +1659,7 @@ bool __weak module_exit_section(const char *name) return strstarts(name, ".exit"); } =20 -static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr) +static int validate_section_offset(const struct load_info *info, Elf_Shdr = *shdr) { #if defined(CONFIG_64BIT) unsigned long long secend; @@ -1646,62 +1678,80 @@ static int validate_section_offset(struct load_info= *info, Elf_Shdr *shdr) return 0; } =20 -/* - * Check userspace passed ELF module against our expectations, and cache - * useful variables for further processing as we go. - * - * This does basic validity checks against section offsets and sizes, the - * section name string table, and the indices used for it (sh_name). +/** + * elf_validity_ehdr() - Checks an ELF header for module validity + * @info: Load info containing the ELF header to check * - * As a last step, since we're already checking the ELF sections we cache - * useful variables which will be used later for our convenience: + * Checks whether an ELF header could belong to a valid module. Checks: * - * o pointers to section headers - * o cache the modinfo symbol section - * o cache the string symbol section - * o cache the module section + * * ELF header is within the data the user provided + * * ELF magic is present + * * It is relocatable (not final linked, not core file, etc.) + * * The header's machine type matches what the architecture expects. + * * Optional arch-specific hook for other properties + * - module_elf_check_arch() is currently only used by PPC to check + * ELF ABI version, but may be used by others in the future. * - * As a last step we set info->mod to the temporary copy of the module in - * info->hdr. The final one will be allocated in move_module(). Any - * modifications we make to our copy of the module will be carried over - * to the final minted module. + * Return: %0 if valid, %-ENOEXEC on failure. */ -static int elf_validity_cache_copy(struct load_info *info, int flags) +static int elf_validity_ehdr(const struct load_info *info) { - unsigned int i; - Elf_Shdr *shdr, *strhdr; - int err; - unsigned int num_mod_secs =3D 0, mod_idx; - unsigned int num_info_secs =3D 0, info_idx; - unsigned int num_sym_secs =3D 0, sym_idx; - if (info->len < sizeof(*(info->hdr))) { pr_err("Invalid ELF header len %lu\n", info->len); - goto no_exec; + return -ENOEXEC; } - if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) !=3D 0) { pr_err("Invalid ELF header magic: !=3D %s\n", ELFMAG); - goto no_exec; + return -ENOEXEC; } if (info->hdr->e_type !=3D ET_REL) { pr_err("Invalid ELF header type: %u !=3D %u\n", info->hdr->e_type, ET_REL); - goto no_exec; + return -ENOEXEC; } if (!elf_check_arch(info->hdr)) { pr_err("Invalid architecture in ELF header: %u\n", info->hdr->e_machine); - goto no_exec; + return -ENOEXEC; } if (!module_elf_check_arch(info->hdr)) { pr_err("Invalid module architecture in ELF header: %u\n", info->hdr->e_machine); - goto no_exec; + return -ENOEXEC; } + return 0; +} + +/** + * elf_validity_cache_sechdrs() - Cache section headers if valid + * @info: Load info to compute section headers from + * + * Checks: + * + * * ELF header is valid (see elf_validity_ehdr()) + * * Section headers are the size we expect + * * Section array fits in the user provided data + * * Section index 0 is NULL + * * Section contents are inbounds + * + * Then updates @info with a &load_info->sechdrs pointer if valid. + * + * Return: %0 if valid, negative error code if validation failed. + */ +static int elf_validity_cache_sechdrs(struct load_info *info) +{ + Elf_Shdr *sechdrs; + Elf_Shdr *shdr; + int i; + int err; + + err =3D elf_validity_ehdr(info); + if (err < 0) + return err; + if (info->hdr->e_shentsize !=3D sizeof(Elf_Shdr)) { pr_err("Invalid ELF section header size\n"); - goto no_exec; + return -ENOEXEC; } =20 /* @@ -1713,10 +1763,66 @@ static int elf_validity_cache_copy(struct load_info= *info, int flags) || (info->hdr->e_shnum * sizeof(Elf_Shdr) > info->len - info->hdr->e_shoff)) { pr_err("Invalid ELF section header overflow\n"); - goto no_exec; + return -ENOEXEC; } =20 - info->sechdrs =3D (void *)info->hdr + info->hdr->e_shoff; + sechdrs =3D (void *)info->hdr + info->hdr->e_shoff; + + /* + * The code assumes that section 0 has a length of zero and + * an addr of zero, so check for it. + */ + if (sechdrs[0].sh_type !=3D SHT_NULL + || sechdrs[0].sh_size !=3D 0 + || sechdrs[0].sh_addr !=3D 0) { + pr_err("ELF Spec violation: section 0 type(%d)!=3DSH_NULL or non-zero le= n or addr\n", + sechdrs[0].sh_type); + return -ENOEXEC; + } + + /* Validate contents are inbounds */ + for (i =3D 1; i < info->hdr->e_shnum; i++) { + shdr =3D &sechdrs[i]; + switch (shdr->sh_type) { + case SHT_NULL: + case SHT_NOBITS: + /* No contents, offset/size don't mean anything */ + continue; + default: + err =3D validate_section_offset(info, shdr); + if (err < 0) { + pr_err("Invalid ELF section in module (section %u type %u)\n", + i, shdr->sh_type); + return err; + } + } + } + + info->sechdrs =3D sechdrs; + + return 0; +} + +/** + * elf_validity_cache_secstrings() - Caches section names if valid + * @info: Load info to cache section names from. Must have valid sechdrs. + * + * Specifically checks: + * + * * Section name table index is inbounds of section headers + * * Section name table is not empty + * * Section name table is NUL terminated + * * All section name offsets are inbounds of the section + * + * Then updates @info with a &load_info->secstrings pointer if valid. + * + * Return: %0 if valid, negative error code if validation failed. + */ +static int elf_validity_cache_secstrings(struct load_info *info) +{ + Elf_Shdr *strhdr, *shdr; + char *secstrings; + int i; =20 /* * Verify if the section name table index is valid. @@ -1726,165 +1832,234 @@ static int elf_validity_cache_copy(struct load_in= fo *info, int flags) pr_err("Invalid ELF section name index: %d || e_shstrndx (%d) >=3D e_shn= um (%d)\n", info->hdr->e_shstrndx, info->hdr->e_shstrndx, info->hdr->e_shnum); - goto no_exec; + return -ENOEXEC; } =20 strhdr =3D &info->sechdrs[info->hdr->e_shstrndx]; - err =3D validate_section_offset(info, strhdr); - if (err < 0) { - pr_err("Invalid ELF section hdr(type %u)\n", strhdr->sh_type); - return err; - } =20 /* * The section name table must be NUL-terminated, as required * by the spec. This makes strcmp and pr_* calls that access * strings in the section safe. */ - info->secstrings =3D (void *)info->hdr + strhdr->sh_offset; + secstrings =3D (void *)info->hdr + strhdr->sh_offset; if (strhdr->sh_size =3D=3D 0) { pr_err("empty section name table\n"); - goto no_exec; + return -ENOEXEC; } - if (info->secstrings[strhdr->sh_size - 1] !=3D '\0') { + if (secstrings[strhdr->sh_size - 1] !=3D '\0') { pr_err("ELF Spec violation: section name table isn't null terminated\n"); - goto no_exec; - } - - /* - * The code assumes that section 0 has a length of zero and - * an addr of zero, so check for it. - */ - if (info->sechdrs[0].sh_type !=3D SHT_NULL - || info->sechdrs[0].sh_size !=3D 0 - || info->sechdrs[0].sh_addr !=3D 0) { - pr_err("ELF Spec violation: section 0 type(%d)!=3DSH_NULL or non-zero le= n or addr\n", - info->sechdrs[0].sh_type); - goto no_exec; + return -ENOEXEC; } =20 - for (i =3D 1; i < info->hdr->e_shnum; i++) { + for (i =3D 0; i < info->hdr->e_shnum; i++) { shdr =3D &info->sechdrs[i]; - switch (shdr->sh_type) { - case SHT_NULL: - case SHT_NOBITS: + /* SHT_NULL means sh_name has an undefined value */ + if (shdr->sh_type =3D=3D SHT_NULL) continue; - case SHT_SYMTAB: - if (shdr->sh_link =3D=3D SHN_UNDEF - || shdr->sh_link >=3D info->hdr->e_shnum) { - pr_err("Invalid ELF sh_link!=3DSHN_UNDEF(%d) or (sh_link(%d) >=3D hdr-= >e_shnum(%d)\n", - shdr->sh_link, shdr->sh_link, - info->hdr->e_shnum); - goto no_exec; - } - num_sym_secs++; - sym_idx =3D i; - fallthrough; - default: - err =3D validate_section_offset(info, shdr); - if (err < 0) { - pr_err("Invalid ELF section in module (section %u type %u)\n", - i, shdr->sh_type); - return err; - } - if (strcmp(info->secstrings + shdr->sh_name, - ".gnu.linkonce.this_module") =3D=3D 0) { - num_mod_secs++; - mod_idx =3D i; - } else if (strcmp(info->secstrings + shdr->sh_name, - ".modinfo") =3D=3D 0) { - num_info_secs++; - info_idx =3D i; - } - - if (shdr->sh_flags & SHF_ALLOC) { - if (shdr->sh_name >=3D strhdr->sh_size) { - pr_err("Invalid ELF section name in module (section %u type %u)\n", - i, shdr->sh_type); - return -ENOEXEC; - } - } - break; + if (shdr->sh_name >=3D strhdr->sh_size) { + pr_err("Invalid ELF section name in module (section %u type %u)\n", + i, shdr->sh_type); + return -ENOEXEC; } } =20 - if (num_info_secs > 1) { + info->secstrings =3D secstrings; + return 0; +} + +/** + * elf_validity_cache_index_info() - Validate and cache modinfo section + * @info: Load info to populate the modinfo index on. + * Must have &load_info->sechdrs and &load_info->secstrings populat= ed + * + * Checks that if there is a .modinfo section, it is unique. + * Then, it caches its index in &load_info->index.info. + * Finally, it tries to populate the name to improve error messages. + * + * Return: %0 if valid, %-ENOEXEC if multiple modinfo sections were found. + */ +static int elf_validity_cache_index_info(struct load_info *info) +{ + int info_idx; + + info_idx =3D find_any_unique_sec(info, ".modinfo"); + + if (info_idx =3D=3D 0) + /* Early return, no .modinfo */ + return 0; + + if (info_idx < 0) { pr_err("Only one .modinfo section must exist.\n"); - goto no_exec; - } else if (num_info_secs =3D=3D 1) { - /* Try to find a name early so we can log errors with a module name */ - info->index.info =3D info_idx; - info->name =3D get_modinfo(info, "name"); + return -ENOEXEC; } =20 - if (num_sym_secs !=3D 1) { - pr_warn("%s: module has no symbols (stripped?)\n", - info->name ?: "(missing .modinfo section or name field)"); - goto no_exec; - } + info->index.info =3D info_idx; + /* Try to find a name early so we can log errors with a module name */ + info->name =3D get_modinfo(info, "name"); =20 - /* Sets internal symbols and strings. */ - info->index.sym =3D sym_idx; - shdr =3D &info->sechdrs[sym_idx]; - info->index.str =3D shdr->sh_link; - info->strtab =3D (char *)info->hdr + info->sechdrs[info->index.str].sh_of= fset; + return 0; +} =20 - /* - * The ".gnu.linkonce.this_module" ELF section is special. It is - * what modpost uses to refer to __this_module and let's use rely - * on THIS_MODULE to point to &__this_module properly. The kernel's - * modpost declares it on each modules's *.mod.c file. If the struct - * module of the kernel changes a full kernel rebuild is required. - * - * We have a few expectaions for this special section, the following - * code validates all this for us: - * - * o Only one section must exist - * o We expect the kernel to always have to allocate it: SHF_ALLOC - * o The section size must match the kernel's run time's struct module - * size - */ - if (num_mod_secs !=3D 1) { - pr_err("module %s: Only one .gnu.linkonce.this_module section must exist= .\n", +/** + * elf_validity_cache_index_mod() - Validates and caches this_module secti= on + * @info: Load info to cache this_module on. + * Must have &load_info->sechdrs and &load_info->secstrings populat= ed + * + * The ".gnu.linkonce.this_module" ELF section is special. It is what modp= ost + * uses to refer to __this_module and let's use rely on THIS_MODULE to poi= nt + * to &__this_module properly. The kernel's modpost declares it on each + * modules's *.mod.c file. If the struct module of the kernel changes a fu= ll + * kernel rebuild is required. + * + * We have a few expectations for this special section, this function + * validates all this for us: + * + * * The section has contents + * * The section is unique + * * We expect the kernel to always have to allocate it: SHF_ALLOC + * * The section size must match the kernel's run time's struct module + * size + * + * If all checks pass, the index will be cached in &load_info->index.mod + * + * Return: %0 on validation success, %-ENOEXEC on failure + */ +static int elf_validity_cache_index_mod(struct load_info *info) +{ + Elf_Shdr *shdr; + int mod_idx; + + mod_idx =3D find_any_unique_sec(info, ".gnu.linkonce.this_module"); + if (mod_idx <=3D 0) { + pr_err("module %s: Exactly one .gnu.linkonce.this_module section must ex= ist.\n", info->name ?: "(missing .modinfo section or name field)"); - goto no_exec; + return -ENOEXEC; } =20 shdr =3D &info->sechdrs[mod_idx]; =20 - /* - * This is already implied on the switch above, however let's be - * pedantic about it. - */ if (shdr->sh_type =3D=3D SHT_NOBITS) { pr_err("module %s: .gnu.linkonce.this_module section must have a size se= t\n", info->name ?: "(missing .modinfo section or name field)"); - goto no_exec; + return -ENOEXEC; } =20 if (!(shdr->sh_flags & SHF_ALLOC)) { pr_err("module %s: .gnu.linkonce.this_module must occupy memory during p= rocess execution\n", info->name ?: "(missing .modinfo section or name field)"); - goto no_exec; + return -ENOEXEC; } =20 if (shdr->sh_size !=3D sizeof(struct module)) { pr_err("module %s: .gnu.linkonce.this_module section size must match the= kernel's built struct module size at run time\n", info->name ?: "(missing .modinfo section or name field)"); - goto no_exec; + return -ENOEXEC; } =20 info->index.mod =3D mod_idx; =20 - /* This is temporary: point mod into copy of data. */ - info->mod =3D (void *)info->hdr + shdr->sh_offset; + return 0; +} =20 - /* - * If we didn't load the .modinfo 'name' field earlier, fall back to - * on-disk struct mod 'name' field. - */ - if (!info->name) - info->name =3D info->mod->name; +/** + * elf_validity_cache_index_sym() - Validate and cache symtab index + * @info: Load info to cache symtab index in. + * Must have &load_info->sechdrs and &load_info->secstrings populat= ed. + * + * Checks that there is exactly one symbol table, then caches its index in + * &load_info->index.sym. + * + * Return: %0 if valid, %-ENOEXEC on failure. + */ +static int elf_validity_cache_index_sym(struct load_info *info) +{ + unsigned int sym_idx; + unsigned int num_sym_secs =3D 0; + int i; + + for (i =3D 1; i < info->hdr->e_shnum; i++) { + if (info->sechdrs[i].sh_type =3D=3D SHT_SYMTAB) { + num_sym_secs++; + sym_idx =3D i; + } + } + + if (num_sym_secs !=3D 1) { + pr_warn("%s: module has no symbols (stripped?)\n", + info->name ?: "(missing .modinfo section or name field)"); + return -ENOEXEC; + } + + info->index.sym =3D sym_idx; + + return 0; +} + +/** + * elf_validity_cache_index_str() - Validate and cache strtab index + * @info: Load info to cache strtab index in. + * Must have &load_info->sechdrs and &load_info->secstrings populat= ed. + * Must have &load_info->index.sym populated. + * + * Looks at the symbol table's associated string table, makes sure it is + * in-bounds, and caches it. + * + * Return: %0 if valid, %-ENOEXEC on failure. + */ +static int elf_validity_cache_index_str(struct load_info *info) +{ + unsigned int str_idx =3D info->sechdrs[info->index.sym].sh_link; + + if (str_idx =3D=3D SHN_UNDEF || str_idx > info->hdr->e_shnum) { + pr_err("Invalid ELF sh_link!=3DSHN_UNDEF(%d) or (sh_link(%d) >=3D hdr->e= _shnum(%d)\n", + str_idx, str_idx, info->hdr->e_shnum); + return -ENOEXEC; + } + + info->index.str =3D str_idx; + return 0; +} + +/** + * elf_validity_cache_index() - Resolve, validate, cache section indices + * @info: Load info to read from and update. + * &load_info->sechdrs and &load_info->secstrings must be populate= d. + * @flags: Load flags, relevant to suppress version loading, see + * uapi/linux/module.h + * + * Populates &load_info->index, validating as it goes. + * See child functions for per-field validation: + * + * * elf_validity_cache_index_info() + * * elf_validity_cache_index_mod() + * * elf_validity_cache_index_sym() + * * elf_validity_cache_index_str() + * + * If versioning is not suppressed via flags, load the version index from + * a section called "__versions" with no validation. + * + * If CONFIG_SMP is enabled, load the percpu section by name with no + * validation. + * + * Return: 0 on success, negative error code if an index failed validation. + */ +static int elf_validity_cache_index(struct load_info *info, int flags) +{ + int err; + + err =3D elf_validity_cache_index_info(info); + if (err < 0) + return err; + err =3D elf_validity_cache_index_mod(info); + if (err < 0) + return err; + err =3D elf_validity_cache_index_sym(info); + if (err < 0) + return err; + err =3D elf_validity_cache_index_str(info); + if (err < 0) + return err; =20 if (flags & MODULE_INIT_IGNORE_MODVERSIONS) info->index.vers =3D 0; /* Pretend no __versions section! */ @@ -1894,9 +2069,125 @@ static int elf_validity_cache_copy(struct load_info= *info, int flags) info->index.pcpu =3D find_pcpusec(info); =20 return 0; +} =20 -no_exec: - return -ENOEXEC; +/** + * elf_validity_cache_strtab() - Validate and cache symbol string table + * @info: Load info to read from and update. + * Must have &load_info->sechdrs and &load_info->secstrings populat= ed. + * Must have &load_info->index populated. + * + * Checks: + * + * * The string table is not empty. + * * The string table starts and ends with NUL (required by ELF spec). + * * Every &Elf_Sym->st_name offset in the symbol table is inbounds of the + * string table. + * + * And caches the pointer as &load_info->strtab in @info. + * + * Return: 0 on success, negative error code if a check failed. + */ +static int elf_validity_cache_strtab(struct load_info *info) +{ + Elf_Shdr *str_shdr =3D &info->sechdrs[info->index.str]; + Elf_Shdr *sym_shdr =3D &info->sechdrs[info->index.sym]; + char *strtab =3D (char *)info->hdr + str_shdr->sh_offset; + Elf_Sym *syms =3D (void *)info->hdr + sym_shdr->sh_offset; + int i; + + if (str_shdr->sh_size =3D=3D 0) { + pr_err("empty symbol string table\n"); + return -ENOEXEC; + } + if (strtab[0] !=3D '\0') { + pr_err("symbol string table missing leading NUL\n"); + return -ENOEXEC; + } + if (strtab[str_shdr->sh_size - 1] !=3D '\0') { + pr_err("symbol string table isn't NUL terminated\n"); + return -ENOEXEC; + } + + /* + * Now that we know strtab is correctly structured, check symbol + * starts are inbounds before they're used later. + */ + for (i =3D 0; i < sym_shdr->sh_size / sizeof(*syms); i++) { + if (syms[i].st_name >=3D str_shdr->sh_size) { + pr_err("symbol name out of bounds in string table"); + return -ENOEXEC; + } + } + + info->strtab =3D strtab; + return 0; +} + +/** + * elf_validity_cache_copy() - Validate kernel module and cache section in= fo + * + * @info: Contains the ELF info, and is where we fill out the computed se= ction + * indexes and pointers. + * @flags: Module load flags, see uapi/linux/module.h + * + * This validates a userspace ELF module matches our expectations so that = it + * will be safe to assume it is well formed later in the load. + * + * Notable checks include: + * + * * ELF header is within range and valid + * * Section headers are inbounds and the expected size + * * Section contents are inbounds + * * The section name string section is inbounds, NUL terminated, and + * section name offsets are inbounds. + * * Symbol table, symbol string table, and this_module are present + * * Symbol table, this_module, and modinfo are unique + * * The symbol table string table is inbounds, NUL leading and terminated, + * and the symbol name offsets into the table are inbounds. + * + * Computed and cached values include: + * + * * &load_info->sechdrs (section header table) + * * &load_info->secstrings (section name strings) + * * &load_info->index (distinguished section indices) + * * &load_info->strtab (string table for decoding section symbols) + * + * As a last step we set info->mod to the temporary copy of the module in + * info->hdr. The final one will be allocated in move_module(). Any + * modifications we make to our copy of the module will be carried over + * to the final minted module. + * + * Return: 0 on success, negative error code if the ELF failed validation. + */ +static int elf_validity_cache_copy(struct load_info *info, int flags) +{ + int err; + + err =3D elf_validity_cache_sechdrs(info); + if (err < 0) + return err; + err =3D elf_validity_cache_secstrings(info); + if (err < 0) + return err; + err =3D elf_validity_cache_index(info, flags); + if (err < 0) + return err; + err =3D elf_validity_cache_strtab(info); + if (err < 0) + return err; + + /* This is temporary: point mod into copy of data. */ + info->mod =3D (void *)info->hdr + info->sechdrs[info->index.mod].sh_offse= t; + + /* + * If we didn't load the .modinfo 'name' field earlier, fall back to + * on-disk struct mod 'name' field. + */ + if (!info->name) + info->name =3D info->mod->name; + + return 0; } =20 #define COPY_CHUNK_SIZE (16*PAGE_SIZE) --=20 2.43.0.rc0.421.g78406f8d94-goog From nobody Tue Dec 30 07:41:30 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BA62EC47071 for ; Sat, 18 Nov 2023 02:58:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233071AbjKRC6U (ORCPT ); Fri, 17 Nov 2023 21:58:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51752 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232854AbjKRC6R (ORCPT ); Fri, 17 Nov 2023 21:58:17 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 748C41702 for ; Fri, 17 Nov 2023 18:58:12 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-5af9b0850fdso41525597b3.1 for ; Fri, 17 Nov 2023 18:58:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1700276291; x=1700881091; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=YNSJ/gYYBG8A4ykrZfDNuKpVx6Mci9cgUfNx2nrc6vM=; b=yTZMmN9dxaz/CCsYMxZi23R36CRoJ/aFea1WHji/hOb89D3bbpqid5+TloxCTFdHpK r3urdVBBxL82JAX6Cu4SyOzw7L9n+KKfC6UhMgMoO2/T65nKAc3TjWYpbD8SMGqyp+gI JyqMhM/kA11hfJ+BThp+zEtSe28XQzmx/l9hcU1F6UCBcdSBMlW0J6U1TU2HYzs+26jv 4sRYMBs2/tPTpy9KWbV5dsx746izODZds9y53LDd/CQvQGIhbSQdHamI53DE9iuezxBr 6CFZtvWcZnlD227SwJ6N1nPriuvySMgAYgnGFHQXD5dfgZejxjI9xftBdBD6VnByRfs/ axpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700276291; x=1700881091; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=YNSJ/gYYBG8A4ykrZfDNuKpVx6Mci9cgUfNx2nrc6vM=; b=sKK1Xky2Fr9xmGf23nm5quZlttcxAfdL7YRD13oH+cMB+OyKrCOVNJ9m3A2BqInDBe vjpz2lzTOeASK19OO3E/P5uTFa8sMEAxASr7zkglokSEsuMK+gVWPLodTUt8D4d70TcU FSIw0l26FO8wvwM6NIBHpylNSq5gsCQUniLUuqBhv7olf3Xaj6yGraWVFP0AsfTDBe6O MOyAElOijWIb5sbFS93kVfxQDmTRBY57ziS/CryfPOYfq9c5FKCW1Sb9bAEwfub6UfWi KHDS64r7mch1e2LPxBHzc/H7YF5F5uGK9/GVnfefDvs+ggln5DA4ZkzApCpoa54Wkjow ZeVg== X-Gm-Message-State: AOJu0YwlLR55M5p3DSb2eDekUYkK2E5SeHsBc464M/19ujAmYS6wQ82b hke/reSNNuFlIAAO9nkoZuy8NLAPcZqM X-Google-Smtp-Source: AGHT+IFk464zSCK9cH2m12jAZWO3sor71fpHnoQbR6kwJbvMrxeJpAu2BKJjrULfqlHF7H5VjGSHm/Dnz/j4 X-Received: from anyblade.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:1791]) (user=mmaurer job=sendgmr) by 2002:a81:a1cb:0:b0:5be:9a1e:5867 with SMTP id y194-20020a81a1cb000000b005be9a1e5867mr38515ywg.6.1700276291732; Fri, 17 Nov 2023 18:58:11 -0800 (PST) Date: Sat, 18 Nov 2023 02:54:44 +0000 In-Reply-To: <20231118025748.2778044-1-mmaurer@google.com> Mime-Version: 1.0 References: <20231118025748.2778044-1-mmaurer@google.com> X-Mailer: git-send-email 2.43.0.rc0.421.g78406f8d94-goog Message-ID: <20231118025748.2778044-4-mmaurer@google.com> Subject: [PATCH v2 3/5] modpost: Extended modversion support From: Matthew Maurer To: Masahiro Yamada , Nick Desaulniers , Miguel Ojeda , Gary Guo , Luis Chamberlain Cc: Nathan Chancellor , Nicolas Schier , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, linux-kbuild@vger.kernel.org, rust-for-linux@vger.kernel.org, Laura Abbott , Matthew Maurer Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Adds a new format for modversions which stores each field in a separate ELF section. This initially adds support for variable length names, but could later be used to add additional fields to modversions in a backwards compatible way if needed. Since PPC munges its version records to strip leading dots, we reproduce the munging for the new format. Other architectures do not appear to have architecture-specific usage of this information. Signed-off-by: Matthew Maurer --- arch/powerpc/kernel/module_64.c | 25 ++++++++- kernel/module/internal.h | 11 ++++ kernel/module/main.c | 92 ++++++++++++++++++++++++++++++--- kernel/module/version.c | 43 +++++++++++++++ scripts/mod/modpost.c | 37 +++++++++++-- 5 files changed, 195 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_6= 4.c index 7112adc597a8..bff03627014c 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -22,6 +22,7 @@ #include #include #include +#include =20 /* FIXME: We don't do .init separately. To do this, we'd need to have a separate r2 value in the init and core section, and stub between @@ -355,6 +356,24 @@ static void dedotify_versions(struct modversion_info *= vers, } } =20 +static void dedotify_ext_version_names(char *str_seq, unsigned long size) +{ + unsigned long out =3D 0; + unsigned long in; + char last =3D '\0'; + + for (in =3D 0; in < size; in++) { + if (last =3D=3D '\0') + /* Skip all leading dots */ + if (str_seq[in] =3D=3D '.') + continue; + last =3D str_seq[in]; + str_seq[out++] =3D last; + } + /* Zero the trailing portion of the names table for robustness */ + bzero(&str_seq[out], size - out); +} + /* * Undefined symbols which refer to .funcname, hack to funcname. Make .TOC. * seem to be defined (value set later). @@ -424,10 +443,12 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, me->arch.toc_section =3D i; if (sechdrs[i].sh_addralign < 8) sechdrs[i].sh_addralign =3D 8; - } - else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")=3D=3D0) + } else if (strcmp(secstrings + sechdrs[i].sh_name, "__versions") =3D=3D = 0) dedotify_versions((void *)hdr + sechdrs[i].sh_offset, sechdrs[i].sh_size); + else if (strcmp(secstrings + sechdrs[i].sh_name, "__version_ext_names") = =3D=3D 0) + dedotify_ext_version_names((void *)hdr + sechdrs[i].sh_offset, + sechdrs[i].sh_size); =20 if (sechdrs[i].sh_type =3D=3D SHT_SYMTAB) dedotify((void *)hdr + sechdrs[i].sh_offset, diff --git a/kernel/module/internal.h b/kernel/module/internal.h index d8dc52eb9c82..35d89c3f657c 100644 --- a/kernel/module/internal.h +++ b/kernel/module/internal.h @@ -86,6 +86,8 @@ struct load_info { unsigned int vers; unsigned int info; unsigned int pcpu; + unsigned int vers_ext_crc; + unsigned int vers_ext_name; } index; }; =20 @@ -389,6 +391,15 @@ void module_layout(struct module *mod, struct modversi= on_info *ver, struct kerne struct kernel_symbol *ks, struct tracepoint * const *tp); int check_modstruct_version(const struct load_info *info, struct module *m= od); int same_magic(const char *amagic, const char *bmagic, bool has_crcs); +struct modversion_info_ext { + size_t remaining; + const s32 *crc; + const char *name; +}; +void modversion_ext_start(const struct load_info *info, struct modversion_= info_ext *ver); +void modversion_ext_advance(struct modversion_info_ext *ver); +#define for_each_modversion_info_ext(ver, info) \ + for (modversion_ext_start(info, &ver); ver.remaining > 0; modversion_ext_= advance(&ver)) #else /* !CONFIG_MODVERSIONS */ static inline int check_version(const struct load_info *info, const char *symname, diff --git a/kernel/module/main.c b/kernel/module/main.c index 8b2848b3183a..2b175b7953e7 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -2021,6 +2021,82 @@ static int elf_validity_cache_index_str(struct load_= info *info) return 0; } =20 +/** + * elf_validity_cache_index_versions() - Validate and cache version indices + * @info: Load info to cache version indices in. + * Must have &load_info->sechdrs and &load_info->secstrings popula= ted. + * @flags: Load flags, relevant to suppress version loading, see + * uapi/linux/module.h + * + * If we're ignoring modversions based on @flags, zero all version indices + * and return validity. Othewrise check: + * + * * If "__version_ext_crcs" is present, "__version_ext_names" is present + * * There is a name present for every crc + * + * Then populate: + * + * * &load_info->index.vers + * * &load_info->index.vers_ext_crc + * * &load_info->index.vers_ext_names + * + * if present. + * + * Return: %0 if valid, %-ENOEXEC on failure. + */ +static int elf_validity_cache_index_versions(struct load_info *info, int f= lags) +{ + unsigned int vers_ext_crc; + unsigned int vers_ext_name; + size_t crc_count; + size_t remaining_len; + size_t name_size; + char *name; + + /* If modversions were suppressed, pretend we didn't find any */ + if (flags & MODULE_INIT_IGNORE_MODVERSIONS) { + info->index.vers =3D 0; + info->index.vers_ext_crc =3D 0; + info->index.vers_ext_name =3D 0; + return 0; + } + + vers_ext_crc =3D find_sec(info, "__version_ext_crcs"); + vers_ext_name =3D find_sec(info, "__version_ext_names"); + + /* If we have one field, we must have the other */ + if (!!vers_ext_crc !=3D !!vers_ext_name) { + pr_err("extended version crc+name presence does not match"); + return -ENOEXEC; + } + + /* + * If we have extended version information, we should have the same + * number of entries in every section. + */ + if (vers_ext_crc) { + crc_count =3D info->sechdrs[vers_ext_crc].sh_size / sizeof(s32); + name =3D (void *)info->hdr + + info->sechdrs[vers_ext_name].sh_offset; + remaining_len =3D info->sechdrs[vers_ext_name].sh_size; + + while (crc_count--) { + name_size =3D strnlen(name, remaining_len) + 1; + if (name_size > remaining_len) { + pr_err("more extended version crcs than names"); + return -ENOEXEC; + } + remaining_len -=3D name_size; + name +=3D name_size; + } + } + + info->index.vers =3D find_sec(info, "__versions"); + info->index.vers_ext_crc =3D vers_ext_crc; + info->index.vers_ext_name =3D vers_ext_name; + return 0; +} + /** * elf_validity_cache_index() - Resolve, validate, cache section indices * @info: Load info to read from and update. @@ -2035,9 +2111,7 @@ static int elf_validity_cache_index_str(struct load_i= nfo *info) * * elf_validity_cache_index_mod() * * elf_validity_cache_index_sym() * * elf_validity_cache_index_str() - * - * If versioning is not suppressed via flags, load the version index from - * a section called "__versions" with no validation. + * * elf_validity_cache_index_versions() * * If CONFIG_SMP is enabled, load the percpu section by name with no * validation. @@ -2060,11 +2134,9 @@ static int elf_validity_cache_index(struct load_info= *info, int flags) err =3D elf_validity_cache_index_str(info); if (err < 0) return err; - - if (flags & MODULE_INIT_IGNORE_MODVERSIONS) - info->index.vers =3D 0; /* Pretend no __versions section! */ - else - info->index.vers =3D find_sec(info, "__versions"); + err =3D elf_validity_cache_index_versions(info, flags); + if (err < 0) + return err; =20 info->index.pcpu =3D find_pcpusec(info); =20 @@ -2291,6 +2363,10 @@ static int rewrite_section_headers(struct load_info = *info, int flags) =20 /* Track but don't keep modinfo and version sections. */ info->sechdrs[info->index.vers].sh_flags &=3D ~(unsigned long)SHF_ALLOC; + info->sechdrs[info->index.vers_ext_crc].sh_flags &=3D + ~(unsigned long)SHF_ALLOC; + info->sechdrs[info->index.vers_ext_name].sh_flags &=3D + ~(unsigned long)SHF_ALLOC; info->sechdrs[info->index.info].sh_flags &=3D ~(unsigned long)SHF_ALLOC; =20 return 0; diff --git a/kernel/module/version.c b/kernel/module/version.c index 53f43ac5a73e..02d8340bdb57 100644 --- a/kernel/module/version.c +++ b/kernel/module/version.c @@ -19,11 +19,28 @@ int check_version(const struct load_info *info, unsigned int versindex =3D info->index.vers; unsigned int i, num_versions; struct modversion_info *versions; + struct modversion_info_ext version_ext; =20 /* Exporting module didn't supply crcs? OK, we're already tainted. */ if (!crc) return 1; =20 + /* If we have extended version info, rely on it */ + if (info->index.vers_ext_crc) { + for_each_modversion_info_ext(version_ext, info) { + if (strcmp(version_ext.name, symname) !=3D 0) + continue; + if (*version_ext.crc =3D=3D *crc) + return 1; + pr_debug("Found checksum %X vs module %X\n", + *crc, *version_ext.crc); + goto bad_version; + } + pr_warn_once("%s: no extended symbol version for %s\n", + info->name, symname); + return 1; + } + /* No versions at all? modprobe --force does this. */ if (versindex =3D=3D 0) return try_to_force_load(mod, symname) =3D=3D 0; @@ -87,6 +104,32 @@ int same_magic(const char *amagic, const char *bmagic, return strcmp(amagic, bmagic) =3D=3D 0; } =20 +void modversion_ext_start(const struct load_info *info, + struct modversion_info_ext *start) +{ + unsigned int crc_idx =3D info->index.vers_ext_crc; + unsigned int name_idx =3D info->index.vers_ext_name; + Elf_Shdr *sechdrs =3D info->sechdrs; + + /* + * Both of these fields are needed for this to be useful + * Any future fields should be initialized to NULL if absent. + */ + if ((crc_idx =3D=3D 0) || (name_idx =3D=3D 0)) + start->remaining =3D 0; + + start->crc =3D (const s32 *)sechdrs[crc_idx].sh_addr; + start->name =3D (const char *)sechdrs[name_idx].sh_addr; + start->remaining =3D sechdrs[crc_idx].sh_size / sizeof(*start->crc); +} + +void modversion_ext_advance(struct modversion_info_ext *vers) +{ + vers->remaining--; + vers->crc++; + vers->name +=3D strlen(vers->name) + 1; +} + /* * Generate the signature for all relevant module structures here. * If these change, we don't want to try to parse the module. diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 973b5e5ae2dd..530890bf5733 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1910,15 +1910,46 @@ static void add_versions(struct buffer *b, struct m= odule *mod) continue; } if (strlen(s->name) >=3D MODULE_NAME_LEN) { - error("too long symbol \"%s\" [%s.ko]\n", - s->name, mod->name); - break; + /* this symbol will only be in the extended info */ + continue; } buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name); } =20 buf_printf(b, "};\n"); + + buf_printf(b, "static const s32 ____version_ext_crcs[]\n"); + buf_printf(b, "__used __section(\"__version_ext_crcs\") =3D {\n"); + list_for_each_entry(s, &mod->unresolved_symbols, list) { + if (!s->module) + continue; + if (!s->crc_valid) { + /* + * We already warned on this when producing the legacy + * modversions table. + */ + continue; + } + buf_printf(b, "\t%#8x,\n", s->crc); + } + buf_printf(b, "};\n"); + + buf_printf(b, "static const char ____version_ext_names[]\n"); + buf_printf(b, "__used __section(\"__version_ext_names\") =3D\n"); + list_for_each_entry(s, &mod->unresolved_symbols, list) { + if (!s->module) + continue; + if (!s->crc_valid) { + /* + * We already warned on this when producing the legacy + * modversions table. + */ + continue; + } + buf_printf(b, "\t\"%s\\0\"\n", s->name); + } + buf_printf(b, ";\n"); } =20 static void add_depends(struct buffer *b, struct module *mod) --=20 2.43.0.rc0.421.g78406f8d94-goog From nobody Tue Dec 30 07:41:30 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA7F3C5AD4C for ; Sat, 18 Nov 2023 02:58:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346422AbjKRC6V (ORCPT ); Fri, 17 Nov 2023 21:58:21 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51784 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232967AbjKRC6S (ORCPT ); Fri, 17 Nov 2023 21:58:18 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5EE4E1723 for ; Fri, 17 Nov 2023 18:58:14 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-5b02ed0f886so36381797b3.0 for ; Fri, 17 Nov 2023 18:58:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1700276293; x=1700881093; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Nvk9Q6fDi4VYvpZBd2dg6YVoVQRX3tnrrY9vqXNqK/Y=; b=cFpJc1uGrK0L9IEqMQ1f7XN8NnqWZD/2zkqP2j9JqCDvFOlV5c90qC0MoFUkNlBATj /hMF2V4bt/rf45dVNejfFaVYgvo38gE882Zv6Pyqg0IMerwFg6bFBkh6aKJUNpSHgKMP qCSolDJ4azR4YU3wUTANt0khbIdLSMJgmhVUCVDGcGWWj5JCBCulIDcj+dYI5YeKz42U Ex2mse2bptK9oWhVPS+XF2g49ipbKQfqSezHOwdNa4ooDxNWq+68hTgAtPAT3apZE33g a1871CLMq7R9B1w+ApX3yO1BTw6xHUWTkOZNgsUuMRMGcw11fKFuAQpoDAFIbYjiYEb/ fXEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700276293; x=1700881093; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Nvk9Q6fDi4VYvpZBd2dg6YVoVQRX3tnrrY9vqXNqK/Y=; b=QVPSWDl1Q0tMeL0dVyLSwtgk5yvz1T7StUaXkafGp9sa0mmCaZIFgCxML45Wm4j1hv VPsxDzUO+BQTWvleYbhwG4AtzGDsBMFdu1gbMVMtuMdfrYnFC6EzocFoOGPtg8qkLeQL 6l385ntqFMhF3ZAihDiURFQ1VpAa4AKeK6XkgDS53xIFw+c3vk/zTh37KzyUaNCs0MXN p+d7n8A34hDWhykK8mAenv0/EZNEUnHuaM8fnH6uAhuTaN/63lna+TBpsMTpIUE5Hl4G ghyuHjxM2i552Lmm2p3FtUfkwK3QULGseKVP6favMlTybnvwkbNhjEO/6I2niIwjD+JK ZIcQ== X-Gm-Message-State: AOJu0YzVFXuLJIovuZwJ49dlHhepjXN64XhBvBd+0ioIs1EaxhYPlW+/ 4EOg6+/lop95BXzDlG39NloiHO5fdBT8 X-Google-Smtp-Source: AGHT+IGP3XlXj/5Dcw3hp9Px56ng9u8ZBGdlOpNsgMCWjyW3JuNS4KY9Ymdo28sfT5+B96al0+/x10TRijqM X-Received: from anyblade.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:1791]) (user=mmaurer job=sendgmr) by 2002:a81:d512:0:b0:5a8:d81f:f5e7 with SMTP id i18-20020a81d512000000b005a8d81ff5e7mr38384ywj.8.1700276293608; Fri, 17 Nov 2023 18:58:13 -0800 (PST) Date: Sat, 18 Nov 2023 02:54:45 +0000 In-Reply-To: <20231118025748.2778044-1-mmaurer@google.com> Mime-Version: 1.0 References: <20231118025748.2778044-1-mmaurer@google.com> X-Mailer: git-send-email 2.43.0.rc0.421.g78406f8d94-goog Message-ID: <20231118025748.2778044-5-mmaurer@google.com> Subject: [PATCH v2 4/5] rust: Allow MODVERSIONS From: Matthew Maurer To: Masahiro Yamada , Nick Desaulniers , Miguel Ojeda , Gary Guo , Luis Chamberlain Cc: Nathan Chancellor , Nicolas Schier , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, linux-kbuild@vger.kernel.org, rust-for-linux@vger.kernel.org, Laura Abbott , Matthew Maurer Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" With variable length symbol names from extended modversions, we can enable MODVERSIONS alongside RUST due to support for its longer symbol names. Signed-off-by: Matthew Maurer --- init/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/init/Kconfig b/init/Kconfig index 9ffb103fc927..6cac5b4db8f6 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1885,7 +1885,6 @@ config RUST bool "Rust support" depends on HAVE_RUST depends on RUST_IS_AVAILABLE - depends on !MODVERSIONS depends on !GCC_PLUGINS depends on !RANDSTRUCT depends on !DEBUG_INFO_BTF || PAHOLE_HAS_LANG_EXCLUDE --=20 2.43.0.rc0.421.g78406f8d94-goog From nobody Tue Dec 30 07:41:30 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83AD8C5AE4A for ; Sat, 18 Nov 2023 02:58:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233019AbjKRC62 (ORCPT ); Fri, 17 Nov 2023 21:58:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51854 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233020AbjKRC6T (ORCPT ); Fri, 17 Nov 2023 21:58:19 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2EFAE171A for ; Fri, 17 Nov 2023 18:58:16 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-da07b5e6f75so3291476276.0 for ; Fri, 17 Nov 2023 18:58:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1700276295; x=1700881095; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=6470cZa62MbyzT9ybBeTXZeWGQJ3Ep0Ies1ZAhH/GQQ=; b=A+K7W2goGY3rCRjchC7VMQq7Xg5AZwcYYzysdc+2u8ff3LvNEE0oRpHfJT18UQp+Tj Vxw/Lz5R2tV0BLDhuOImU1MSL3Eg9uhp71m6ky1ddK6jEsjTzkD5gCBFRfOYPPXMi8tD Vd66AYhHa+2IAEhxWB6Gp5C7k+eWK6MqJYDmh840RN97lJz+JqpDREwsU3HbnR2k/nez EikZnDIXaXE3L4gBVpvI3eGFXzYY/imHZ0LocduIXhhiYQLeOl6cz68zvws80d2rreEo P2lkWaIIOGoQCq8prnhBAGj67Bn4bNAxq4u8hvkakG8K4fXsd5SbazKYGcAstfApcoJe 6JEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700276295; x=1700881095; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=6470cZa62MbyzT9ybBeTXZeWGQJ3Ep0Ies1ZAhH/GQQ=; b=Iv2fdifOKW1t6OgePmyWFMtV/ImdL+rGzmcPD3Wk4pP7ESMqGCmJen7IG2oQSWQQR1 /mMyjM2YApjkMP7d99NwD5vt6njyxOUS+PYNZzi5leZL6JerAngmrjycVc5IV/qk5wiF dlR12ETGq4UG6u5CLN1EIWw1vesVD2tjLPzvubZn21eoB+e0iN4Dfkflg/J1KTuY4fwi GFEaHIbPcCCjNgMEy3XSRVA8t9whre7b+dm6UuuiQ42fDCt3qeM5OPUnKUdERHdQqy5L 9FZbdInua99sJm5FSt4Cj1fdG3bVQeZ5iqKSzQkvti2LgOZfjwtUcSHV61R3IuqE9Xkx dw2g== X-Gm-Message-State: AOJu0YzycjMbEBz4f4eEL0I/xyR1u5wMwI5rb49bPV3WJq5uW6ilMD3x uS3F031sgquLfa/Azb9NgiEQ2XUomsvq X-Google-Smtp-Source: AGHT+IE0p+YtnUfNXyViuu9ji/lc0sYzrwa5eOwzdtBv1fKlqv6arjeB7wtV3bdeWily94YGEBFtqUBG97qg X-Received: from anyblade.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:1791]) (user=mmaurer job=sendgmr) by 2002:a5b:cc9:0:b0:da0:37e1:558e with SMTP id e9-20020a5b0cc9000000b00da037e1558emr26098ybr.6.1700276295405; Fri, 17 Nov 2023 18:58:15 -0800 (PST) Date: Sat, 18 Nov 2023 02:54:46 +0000 In-Reply-To: <20231118025748.2778044-1-mmaurer@google.com> Mime-Version: 1.0 References: <20231118025748.2778044-1-mmaurer@google.com> X-Mailer: git-send-email 2.43.0.rc0.421.g78406f8d94-goog Message-ID: <20231118025748.2778044-6-mmaurer@google.com> Subject: [PATCH v2 5/5] export_report: Use new version info format From: Matthew Maurer To: Masahiro Yamada , Nick Desaulniers , Miguel Ojeda , Gary Guo , Luis Chamberlain Cc: Nathan Chancellor , Nicolas Schier , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, linux-kbuild@vger.kernel.org, rust-for-linux@vger.kernel.org, Laura Abbott , Matthew Maurer Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The new version info format has a superset of symbols in the old format. Since this is a tool for in-tree modules, we don't need to parse the old one with this tool any longer. Signed-off-by: Matthew Maurer --- scripts/export_report.pl | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/scripts/export_report.pl b/scripts/export_report.pl index dcef915405f3..6a37df6f947f 100755 --- a/scripts/export_report.pl +++ b/scripts/export_report.pl @@ -114,31 +114,29 @@ foreach my $thismod (@allcfiles) { } =20 my $state=3D0; + # State map: + # 0 - Looking for names + # 1 - Scanning names + # 2 - Done while ( <$module> ) { chomp; if ($state =3D=3D 0) { - $state =3D 1 if ($_ =3D~ /static const struct modversion_info/); + $state =3D 1 if ($_ =3D~ /__used __section\("__version_ext_names"\)/); next; } if ($state =3D=3D 1) { - $state =3D 2 if ($_ =3D~ /__used __section\("__versions"\)/); - next; - } - if ($state =3D=3D 2) { - if ( $_ =3D~ /};/ ) { - $state =3D 3; - next; - } - if ( $_ !~ /0x[0-9a-f]+,/ ) { + if ( $_ =3D~ /;/ ) { + $state =3D 2; next; } - my $sym =3D (split /([,"])/,)[4]; + $_ =3D~ /"(.*)\\0"/; + my $sym =3D $1; my ($module, $value, $symbol, $gpl) =3D @{$SYMBOL{$sym}}; $SYMBOL{ $sym } =3D [ $module, $value+1, $symbol, $gpl]; push(@{$MODULE{$thismod}} , $sym); } } - if ($state !=3D 3) { + if ($state !=3D 2) { warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n"; $modversion_warnings++; } --=20 2.43.0.rc0.421.g78406f8d94-goog