Commit fbc0e4e4 authored by Matthew Maurer's avatar Matthew Maurer Committed by Luis Chamberlain
Browse files

module: Factor out elf_validity_cache_index_info



Centralize .modinfo detection and property validation.

Signed-off-by: default avatarMatthew Maurer <mmaurer@google.com>
Reviewed-by: default avatarSami Tolvanen <samitolvanen@google.com>
Signed-off-by: default avatarLuis Chamberlain <mcgrof@kernel.org>
parent 3c5700ae
Loading
Loading
Loading
Loading
+68 −14
Original line number Diff line number Diff line
@@ -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)");