module: Factor out elf_validity_cache_index_info

Centralize .modinfo detection and property validation.

Signed-off-by: Matthew Maurer <mmaurer@google.com>
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
This commit is contained in:
Matthew Maurer 2024-10-15 23:16:39 +00:00 committed by Luis Chamberlain
parent 3c5700aeab
commit fbc0e4e482

View File

@ -195,6 +195,38 @@ static unsigned int find_sec(const struct load_info *info, const char *name)
return 0;
}
/**
* 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 *name)
{
unsigned int idx;
unsigned int count = 0;
int i;
for (i = 1; i < info->hdr->e_shnum; i++) {
if (strcmp(info->secstrings + info->sechdrs[i].sh_name,
name) == 0) {
count++;
idx = i;
}
}
if (count == 1) {
return idx;
} else if (count == 0) {
return 0;
} else {
return -count;
}
}
/* Find a module section, or NULL. */
static void *section_addr(const struct load_info *info, const char *name)
{
@ -1854,6 +1886,39 @@ static int elf_validity_cache_secstrings(struct load_info *info)
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 populated
*
* 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 = find_any_unique_sec(info, ".modinfo");
if (info_idx == 0)
/* Early return, no .modinfo */
return 0;
if (info_idx < 0) {
pr_err("Only one .modinfo section must exist.\n");
return -ENOEXEC;
}
info->index.info = info_idx;
/* Try to find a name early so we can log errors with a module name */
info->name = get_modinfo(info, "name");
return 0;
}
/*
* Check userspace passed ELF module against our expectations, and cache
* useful variables for further processing as we go.
@ -1880,13 +1945,15 @@ static int elf_validity_cache_copy(struct load_info *info, int flags)
Elf_Shdr *shdr;
int err;
unsigned int num_mod_secs = 0, mod_idx;
unsigned int num_info_secs = 0, info_idx;
unsigned int num_sym_secs = 0, sym_idx;
err = elf_validity_cache_sechdrs(info);
if (err < 0)
return err;
err = elf_validity_cache_secstrings(info);
if (err < 0)
return err;
err = elf_validity_cache_index_info(info);
if (err < 0)
return err;
@ -1912,24 +1979,11 @@ static int elf_validity_cache_copy(struct load_info *info, int flags)
".gnu.linkonce.this_module") == 0) {
num_mod_secs++;
mod_idx = i;
} else if (strcmp(info->secstrings + shdr->sh_name,
".modinfo") == 0) {
num_info_secs++;
info_idx = i;
}
break;
}
}
if (num_info_secs > 1) {
pr_err("Only one .modinfo section must exist.\n");
goto no_exec;
} else if (num_info_secs == 1) {
/* Try to find a name early so we can log errors with a module name */
info->index.info = info_idx;
info->name = get_modinfo(info, "name");
}
if (num_sym_secs != 1) {
pr_warn("%s: module has no symbols (stripped?)\n",
info->name ?: "(missing .modinfo section or name field)");