Commit d2fdc759 authored by Kai Germaschewski's avatar Kai Germaschewski

kbuild/modules: Check module symbol versions on insmod

Yeah, the final step!
  
Now that we've got the checksums for the exported symbols and the
checksums of the unresolved symbols for the module we're loading,
let's compare and see.
  
Again, we allow to load a module which has the version info stripped,
but taint the kernel in that case.
parent 82455d2e
...@@ -725,11 +725,66 @@ static int obsolete_params(const char *name, ...@@ -725,11 +725,66 @@ static int obsolete_params(const char *name,
} }
#endif /* CONFIG_OBSOLETE_MODPARM */ #endif /* CONFIG_OBSOLETE_MODPARM */
#ifdef CONFIG_MODVERSIONING
static int check_version(Elf_Shdr *sechdrs,
unsigned int versindex,
const char *symname,
struct module *mod,
struct kernel_symbol_group *ksg,
unsigned int symidx)
{
unsigned long crc;
unsigned int i, num_versions;
struct modversion_info *versions;
if (!ksg->crcs) {
printk("%s: no CRC for \"%s\" [%s] found: kernel tainted.\n",
mod->name, symname,
ksg->owner ? ksg->owner->name : "kernel");
goto taint;
}
crc = ksg->crcs[symidx];
versions = (void *) sechdrs[versindex].sh_addr;
num_versions = sechdrs[versindex].sh_size
/ sizeof(struct modversion_info);
for (i = 0; i < num_versions; i++) {
if (strcmp(versions[i].name, symname) != 0)
continue;
if (versions[i].crc == crc)
return 1;
printk("%s: disagrees about version of symbol %s\n",
mod->name, symname);
DEBUGP("Found checksum %lX vs module %lX\n",
crc, versions[i].crc);
return 0;
}
/* Not in module's version table. OK, but that taints the kernel. */
printk("%s: no version for \"%s\" found: kernel tainted.\n",
mod->name, symname);
taint:
tainted |= TAINT_FORCED_MODULE;
return 1;
}
#else
static inline int check_version(Elf_Shdr *sechdrs,
unsigned int versindex,
const char *symname,
struct module *mod,
struct kernel_symbol_group *ksg,
unsigned int symidx)
{
return 1;
}
#endif /* CONFIG_MODVERSIONING */
/* Resolve a symbol for this module. I.e. if we find one, record usage. /* Resolve a symbol for this module. I.e. if we find one, record usage.
Must be holding module_mutex. */ Must be holding module_mutex. */
static unsigned long resolve_symbol(Elf_Shdr *sechdrs, static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
unsigned int symindex, unsigned int versindex,
const char *strtab,
const char *name, const char *name,
struct module *mod) struct module *mod)
{ {
...@@ -740,8 +795,10 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, ...@@ -740,8 +795,10 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
spin_lock_irq(&modlist_lock); spin_lock_irq(&modlist_lock);
ret = __find_symbol(name, &ksg, &symidx, mod->license_gplok); ret = __find_symbol(name, &ksg, &symidx, mod->license_gplok);
if (ret) { if (ret) {
/* This can fail due to OOM, or module unloading */ /* use_module can fail due to OOM, or module unloading */
if (!use_module(mod, ksg->owner)) if (!check_version(sechdrs, versindex, name, mod,
ksg, symidx) ||
!use_module(mod, ksg->owner))
ret = 0; ret = 0;
} }
spin_unlock_irq(&modlist_lock); spin_unlock_irq(&modlist_lock);
...@@ -828,6 +885,7 @@ static int handle_section(const char *name, ...@@ -828,6 +885,7 @@ static int handle_section(const char *name,
static int simplify_symbols(Elf_Shdr *sechdrs, static int simplify_symbols(Elf_Shdr *sechdrs,
unsigned int symindex, unsigned int symindex,
unsigned int strindex, unsigned int strindex,
unsigned int versindex,
struct module *mod) struct module *mod)
{ {
Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
...@@ -852,7 +910,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs, ...@@ -852,7 +910,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
case SHN_UNDEF: case SHN_UNDEF:
sym[i].st_value sym[i].st_value
= resolve_symbol(sechdrs, symindex, strtab, = resolve_symbol(sechdrs, versindex,
strtab + sym[i].st_name, mod); strtab + sym[i].st_name, mod);
/* Ok if resolved. */ /* Ok if resolved. */
...@@ -981,7 +1039,7 @@ static struct module *load_module(void *umod, ...@@ -981,7 +1039,7 @@ static struct module *load_module(void *umod,
char *secstrings, *args; char *secstrings, *args;
unsigned int i, symindex, exportindex, strindex, setupindex, exindex, unsigned int i, symindex, exportindex, strindex, setupindex, exindex,
modindex, obsparmindex, licenseindex, gplindex, vmagindex, modindex, obsparmindex, licenseindex, gplindex, vmagindex,
crcindex, gplcrcindex; crcindex, gplcrcindex, versindex;
long arglen; long arglen;
struct module *mod; struct module *mod;
long err = 0; long err = 0;
...@@ -1018,7 +1076,7 @@ static struct module *load_module(void *umod, ...@@ -1018,7 +1076,7 @@ static struct module *load_module(void *umod,
/* May not export symbols, or have setup params, so these may /* May not export symbols, or have setup params, so these may
not exist */ not exist */
exportindex = setupindex = obsparmindex = gplindex = licenseindex exportindex = setupindex = obsparmindex = gplindex = licenseindex
= crcindex = gplcrcindex = 0; = crcindex = gplcrcindex = versindex = 0;
/* And these should exist, but gcc whinges if we don't init them */ /* And these should exist, but gcc whinges if we don't init them */
symindex = strindex = exindex = modindex = vmagindex = 0; symindex = strindex = exindex = modindex = vmagindex = 0;
...@@ -1089,6 +1147,13 @@ static struct module *load_module(void *umod, ...@@ -1089,6 +1147,13 @@ static struct module *load_module(void *umod,
DEBUGP("Version magic found in section %u\n", i); DEBUGP("Version magic found in section %u\n", i);
vmagindex = i; vmagindex = i;
sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC; sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
} else if (strcmp(secstrings+sechdrs[i].sh_name,
"__versions") == 0 &&
(sechdrs[i].sh_flags & SHF_ALLOC)) {
/* Module version info (both exported and needed) */
DEBUGP("Versions found in section %u\n", i);
versindex = i;
sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
} }
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
/* symbol and string tables for decoding later. */ /* symbol and string tables for decoding later. */
...@@ -1200,7 +1265,7 @@ static struct module *load_module(void *umod, ...@@ -1200,7 +1265,7 @@ static struct module *load_module(void *umod,
set_license(mod, sechdrs, licenseindex); set_license(mod, sechdrs, licenseindex);
/* Fix up syms, so that st_value is a pointer to location. */ /* Fix up syms, so that st_value is a pointer to location. */
err = simplify_symbols(sechdrs, symindex, strindex, mod); err = simplify_symbols(sechdrs, symindex, strindex, versindex, mod);
if (err < 0) if (err < 0)
goto cleanup; goto cleanup;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment