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

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: default avatarMatthew Maurer <mmaurer@google.com>
Reviewed-by: default avatarSami Tolvanen <samitolvanen@google.com>
Signed-off-by: default avatarLuis Chamberlain <mcgrof@kernel.org>
parent 837031e0
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -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;