summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMatthew Maurer <mmaurer@google.com>2024-10-16 01:16:45 +0200
committerLuis Chamberlain <mcgrof@kernel.org>2024-10-19 23:35:07 +0200
commitd979e3dffa93c9284f244ef64f7a68042c2f8b80 (patch)
treee264d3c6e50bd1d7dfca1495594ebd40947605e6 /kernel
parentmodule: Factor out elf_validity_cache_strtab (diff)
downloadlinux-d979e3dffa93c9284f244ef64f7a68042c2f8b80.tar.xz
linux-d979e3dffa93c9284f244ef64f7a68042c2f8b80.zip
module: Additional validation in elf_validity_cache_strtab
Validate properties of the strtab that are depended on elsewhere, but were previously unchecked: * String table nonempty (offset 0 is valid) * String table has a leading NUL (offset 0 corresponds to "") * String table is NUL terminated (strfoo functions won't run out of the table while reading). * All symbols names are inbounds of the string table. Signed-off-by: Matthew Maurer <mmaurer@google.com> Reviewed-by: Sami Tolvanen <samitolvanen@google.com> Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/module/main.c38
1 files changed, 37 insertions, 1 deletions
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c082d5d41a8d..b40b632f00a6 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2090,17 +2090,53 @@ static int elf_validity_cache_index(struct load_info *info, int flags)
}
/**
- * elf_validity_cache_strtab() - Cache symbol string table
+ * 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 populated.
* 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 = &info->sechdrs[info->index.str];
+ Elf_Shdr *sym_shdr = &info->sechdrs[info->index.sym];
char *strtab = (char *)info->hdr + str_shdr->sh_offset;
+ Elf_Sym *syms = (void *)info->hdr + sym_shdr->sh_offset;
+ int i;
+
+ if (str_shdr->sh_size == 0) {
+ pr_err("empty symbol string table\n");
+ return -ENOEXEC;
+ }
+ if (strtab[0] != '\0') {
+ pr_err("symbol string table missing leading NUL\n");
+ return -ENOEXEC;
+ }
+ if (strtab[str_shdr->sh_size - 1] != '\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 = 0; i < sym_shdr->sh_size / sizeof(*syms); i++) {
+ if (syms[i].st_name >= str_shdr->sh_size) {
+ pr_err("symbol name out of bounds in string table");
+ return -ENOEXEC;
+ }
+ }
info->strtab = strtab;
return 0;