Commit 7f9f852c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'modules-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux

Pull modules updates from Jessica Yu:

 - Some modules-related kallsyms cleanups and a kallsyms fix for ARM.

 - Include keys from the secondary keyring in module signature
   verification.

* tag 'modules-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux:
  ARM: module: Fix function kallsyms on Thumb-2
  module: Overwrite st_size instead of st_info
  module: make it clearer when we're handling kallsyms symbols vs exported symbols
  modsign: use all trusted keys to verify module signature
parents 3f03bf93 93d77e7f
...@@ -61,4 +61,15 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val); ...@@ -61,4 +61,15 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val);
MODULE_ARCH_VERMAGIC_ARMTHUMB \ MODULE_ARCH_VERMAGIC_ARMTHUMB \
MODULE_ARCH_VERMAGIC_P2V MODULE_ARCH_VERMAGIC_P2V
#ifdef CONFIG_THUMB2_KERNEL
#define HAVE_ARCH_KALLSYMS_SYMBOL_VALUE
static inline unsigned long kallsyms_symbol_value(const Elf_Sym *sym)
{
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
return sym->st_value & ~1;
return sym->st_value;
}
#endif
#endif /* _ASM_ARM_MODULE_H */ #endif /* _ASM_ARM_MODULE_H */
...@@ -486,6 +486,13 @@ struct module { ...@@ -486,6 +486,13 @@ struct module {
#define MODULE_ARCH_INIT {} #define MODULE_ARCH_INIT {}
#endif #endif
#ifndef HAVE_ARCH_KALLSYMS_SYMBOL_VALUE
static inline unsigned long kallsyms_symbol_value(const Elf_Sym *sym)
{
return sym->st_value;
}
#endif
extern struct mutex module_mutex; extern struct mutex module_mutex;
/* FIXME: It'd be nice to isolate modules during init, too, so they /* FIXME: It'd be nice to isolate modules during init, too, so they
......
...@@ -495,9 +495,9 @@ struct find_symbol_arg { ...@@ -495,9 +495,9 @@ struct find_symbol_arg {
const struct kernel_symbol *sym; const struct kernel_symbol *sym;
}; };
static bool check_symbol(const struct symsearch *syms, static bool check_exported_symbol(const struct symsearch *syms,
struct module *owner, struct module *owner,
unsigned int symnum, void *data) unsigned int symnum, void *data)
{ {
struct find_symbol_arg *fsa = data; struct find_symbol_arg *fsa = data;
...@@ -555,9 +555,9 @@ static int cmp_name(const void *va, const void *vb) ...@@ -555,9 +555,9 @@ static int cmp_name(const void *va, const void *vb)
return strcmp(a, kernel_symbol_name(b)); return strcmp(a, kernel_symbol_name(b));
} }
static bool find_symbol_in_section(const struct symsearch *syms, static bool find_exported_symbol_in_section(const struct symsearch *syms,
struct module *owner, struct module *owner,
void *data) void *data)
{ {
struct find_symbol_arg *fsa = data; struct find_symbol_arg *fsa = data;
struct kernel_symbol *sym; struct kernel_symbol *sym;
...@@ -565,13 +565,14 @@ static bool find_symbol_in_section(const struct symsearch *syms, ...@@ -565,13 +565,14 @@ static bool find_symbol_in_section(const struct symsearch *syms,
sym = bsearch(fsa->name, syms->start, syms->stop - syms->start, sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
sizeof(struct kernel_symbol), cmp_name); sizeof(struct kernel_symbol), cmp_name);
if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data)) if (sym != NULL && check_exported_symbol(syms, owner,
sym - syms->start, data))
return true; return true;
return false; return false;
} }
/* Find a symbol and return it, along with, (optional) crc and /* Find an exported symbol and return it, along with, (optional) crc and
* (optional) module which owns it. Needs preempt disabled or module_mutex. */ * (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name, const struct kernel_symbol *find_symbol(const char *name,
struct module **owner, struct module **owner,
...@@ -585,7 +586,7 @@ const struct kernel_symbol *find_symbol(const char *name, ...@@ -585,7 +586,7 @@ const struct kernel_symbol *find_symbol(const char *name,
fsa.gplok = gplok; fsa.gplok = gplok;
fsa.warn = warn; fsa.warn = warn;
if (each_symbol_section(find_symbol_in_section, &fsa)) { if (each_symbol_section(find_exported_symbol_in_section, &fsa)) {
if (owner) if (owner)
*owner = fsa.owner; *owner = fsa.owner;
if (crc) if (crc)
...@@ -2198,7 +2199,7 @@ EXPORT_SYMBOL_GPL(__symbol_get); ...@@ -2198,7 +2199,7 @@ EXPORT_SYMBOL_GPL(__symbol_get);
* *
* You must hold the module_mutex. * You must hold the module_mutex.
*/ */
static int verify_export_symbols(struct module *mod) static int verify_exported_symbols(struct module *mod)
{ {
unsigned int i; unsigned int i;
struct module *owner; struct module *owner;
...@@ -2519,10 +2520,10 @@ static void free_modinfo(struct module *mod) ...@@ -2519,10 +2520,10 @@ static void free_modinfo(struct module *mod)
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
/* lookup symbol in given range of kernel_symbols */ /* Lookup exported symbol in given range of kernel_symbols */
static const struct kernel_symbol *lookup_symbol(const char *name, static const struct kernel_symbol *lookup_exported_symbol(const char *name,
const struct kernel_symbol *start, const struct kernel_symbol *start,
const struct kernel_symbol *stop) const struct kernel_symbol *stop)
{ {
return bsearch(name, start, stop - start, return bsearch(name, start, stop - start,
sizeof(struct kernel_symbol), cmp_name); sizeof(struct kernel_symbol), cmp_name);
...@@ -2533,9 +2534,10 @@ static int is_exported(const char *name, unsigned long value, ...@@ -2533,9 +2534,10 @@ static int is_exported(const char *name, unsigned long value,
{ {
const struct kernel_symbol *ks; const struct kernel_symbol *ks;
if (!mod) if (!mod)
ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
else else
ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
return ks != NULL && kernel_symbol_value(ks) == value; return ks != NULL && kernel_symbol_value(ks) == value;
} }
...@@ -2682,7 +2684,7 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) ...@@ -2682,7 +2684,7 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
/* Set types up while we still have access to sections. */ /* Set types up while we still have access to sections. */
for (i = 0; i < mod->kallsyms->num_symtab; i++) for (i = 0; i < mod->kallsyms->num_symtab; i++)
mod->kallsyms->symtab[i].st_info mod->kallsyms->symtab[i].st_size
= elf_type(&mod->kallsyms->symtab[i], info); = elf_type(&mod->kallsyms->symtab[i], info);
/* Now populate the cut down core kallsyms for after init. */ /* Now populate the cut down core kallsyms for after init. */
...@@ -3592,7 +3594,7 @@ static int complete_formation(struct module *mod, struct load_info *info) ...@@ -3592,7 +3594,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
/* Find duplicate symbols (must be called under lock). */ /* Find duplicate symbols (must be called under lock). */
err = verify_export_symbols(mod); err = verify_exported_symbols(mod);
if (err < 0) if (err < 0)
goto out; goto out;
...@@ -3911,18 +3913,22 @@ static inline int is_arm_mapping_symbol(const char *str) ...@@ -3911,18 +3913,22 @@ static inline int is_arm_mapping_symbol(const char *str)
&& (str[2] == '\0' || str[2] == '.'); && (str[2] == '\0' || str[2] == '.');
} }
static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum) static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
{ {
return kallsyms->strtab + kallsyms->symtab[symnum].st_name; return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
} }
static const char *get_ksymbol(struct module *mod, /*
unsigned long addr, * Given a module and address, find the corresponding symbol and return its name
unsigned long *size, * while providing its size and offset if needed.
unsigned long *offset) */
static const char *find_kallsyms_symbol(struct module *mod,
unsigned long addr,
unsigned long *size,
unsigned long *offset)
{ {
unsigned int i, best = 0; unsigned int i, best = 0;
unsigned long nextval; unsigned long nextval, bestval;
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
/* At worse, next value is at end of module */ /* At worse, next value is at end of module */
...@@ -3931,34 +3937,40 @@ static const char *get_ksymbol(struct module *mod, ...@@ -3931,34 +3937,40 @@ static const char *get_ksymbol(struct module *mod,
else else
nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size; nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
/* Scan for closest preceding symbol, and next symbol. (ELF /* Scan for closest preceding symbol, and next symbol. (ELF
starts real symbols at 1). */ starts real symbols at 1). */
for (i = 1; i < kallsyms->num_symtab; i++) { for (i = 1; i < kallsyms->num_symtab; i++) {
if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) const Elf_Sym *sym = &kallsyms->symtab[i];
unsigned long thisval = kallsyms_symbol_value(sym);
if (sym->st_shndx == SHN_UNDEF)
continue; continue;
/* We ignore unnamed symbols: they're uninformative /* We ignore unnamed symbols: they're uninformative
* and inserted at a whim. */ * and inserted at a whim. */
if (*symname(kallsyms, i) == '\0' if (*kallsyms_symbol_name(kallsyms, i) == '\0'
|| is_arm_mapping_symbol(symname(kallsyms, i))) || is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
continue; continue;
if (kallsyms->symtab[i].st_value <= addr if (thisval <= addr && thisval > bestval) {
&& kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
best = i; best = i;
if (kallsyms->symtab[i].st_value > addr bestval = thisval;
&& kallsyms->symtab[i].st_value < nextval) }
nextval = kallsyms->symtab[i].st_value; if (thisval > addr && thisval < nextval)
nextval = thisval;
} }
if (!best) if (!best)
return NULL; return NULL;
if (size) if (size)
*size = nextval - kallsyms->symtab[best].st_value; *size = nextval - bestval;
if (offset) if (offset)
*offset = addr - kallsyms->symtab[best].st_value; *offset = addr - bestval;
return symname(kallsyms, best);
return kallsyms_symbol_name(kallsyms, best);
} }
void * __weak dereference_module_function_descriptor(struct module *mod, void * __weak dereference_module_function_descriptor(struct module *mod,
...@@ -3983,7 +3995,8 @@ const char *module_address_lookup(unsigned long addr, ...@@ -3983,7 +3995,8 @@ const char *module_address_lookup(unsigned long addr,
if (mod) { if (mod) {
if (modname) if (modname)
*modname = mod->name; *modname = mod->name;
ret = get_ksymbol(mod, addr, size, offset);
ret = find_kallsyms_symbol(mod, addr, size, offset);
} }
/* Make a copy in here where it's safe */ /* Make a copy in here where it's safe */
if (ret) { if (ret) {
...@@ -4006,9 +4019,10 @@ int lookup_module_symbol_name(unsigned long addr, char *symname) ...@@ -4006,9 +4019,10 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
if (within_module(addr, mod)) { if (within_module(addr, mod)) {
const char *sym; const char *sym;
sym = get_ksymbol(mod, addr, NULL, NULL); sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
if (!sym) if (!sym)
goto out; goto out;
strlcpy(symname, sym, KSYM_NAME_LEN); strlcpy(symname, sym, KSYM_NAME_LEN);
preempt_enable(); preempt_enable();
return 0; return 0;
...@@ -4031,7 +4045,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, ...@@ -4031,7 +4045,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
if (within_module(addr, mod)) { if (within_module(addr, mod)) {
const char *sym; const char *sym;
sym = get_ksymbol(mod, addr, size, offset); sym = find_kallsyms_symbol(mod, addr, size, offset);
if (!sym) if (!sym)
goto out; goto out;
if (modname) if (modname)
...@@ -4060,9 +4074,11 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, ...@@ -4060,9 +4074,11 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
continue; continue;
kallsyms = rcu_dereference_sched(mod->kallsyms); kallsyms = rcu_dereference_sched(mod->kallsyms);
if (symnum < kallsyms->num_symtab) { if (symnum < kallsyms->num_symtab) {
*value = kallsyms->symtab[symnum].st_value; const Elf_Sym *sym = &kallsyms->symtab[symnum];
*type = kallsyms->symtab[symnum].st_info;
strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN); *value = kallsyms_symbol_value(sym);
*type = sym->st_size;
strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
strlcpy(module_name, mod->name, MODULE_NAME_LEN); strlcpy(module_name, mod->name, MODULE_NAME_LEN);
*exported = is_exported(name, *value, mod); *exported = is_exported(name, *value, mod);
preempt_enable(); preempt_enable();
...@@ -4074,15 +4090,19 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, ...@@ -4074,15 +4090,19 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
return -ERANGE; return -ERANGE;
} }
static unsigned long mod_find_symname(struct module *mod, const char *name) /* Given a module and name of symbol, find and return the symbol's value */
static unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
{ {
unsigned int i; unsigned int i;
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
for (i = 0; i < kallsyms->num_symtab; i++) for (i = 0; i < kallsyms->num_symtab; i++) {
if (strcmp(name, symname(kallsyms, i)) == 0 && const Elf_Sym *sym = &kallsyms->symtab[i];
kallsyms->symtab[i].st_shndx != SHN_UNDEF)
return kallsyms->symtab[i].st_value; if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
sym->st_shndx != SHN_UNDEF)
return kallsyms_symbol_value(sym);
}
return 0; return 0;
} }
...@@ -4097,12 +4117,12 @@ unsigned long module_kallsyms_lookup_name(const char *name) ...@@ -4097,12 +4117,12 @@ unsigned long module_kallsyms_lookup_name(const char *name)
preempt_disable(); preempt_disable();
if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) { if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
if ((mod = find_module_all(name, colon - name, false)) != NULL) if ((mod = find_module_all(name, colon - name, false)) != NULL)
ret = mod_find_symname(mod, colon+1); ret = find_kallsyms_symbol_value(mod, colon+1);
} else { } else {
list_for_each_entry_rcu(mod, &modules, list) { list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED) if (mod->state == MODULE_STATE_UNFORMED)
continue; continue;
if ((ret = mod_find_symname(mod, name)) != 0) if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
break; break;
} }
} }
...@@ -4127,12 +4147,13 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, ...@@ -4127,12 +4147,13 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
if (mod->state == MODULE_STATE_UNFORMED) if (mod->state == MODULE_STATE_UNFORMED)
continue; continue;
for (i = 0; i < kallsyms->num_symtab; i++) { for (i = 0; i < kallsyms->num_symtab; i++) {
const Elf_Sym *sym = &kallsyms->symtab[i];
if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) if (sym->st_shndx == SHN_UNDEF)
continue; continue;
ret = fn(data, symname(kallsyms, i), ret = fn(data, kallsyms_symbol_name(kallsyms, i),
mod, kallsyms->symtab[i].st_value); mod, kallsyms_symbol_value(sym));
if (ret != 0) if (ret != 0)
return ret; return ret;
} }
......
...@@ -83,6 +83,7 @@ int mod_verify_sig(const void *mod, struct load_info *info) ...@@ -83,6 +83,7 @@ int mod_verify_sig(const void *mod, struct load_info *info)
} }
return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len, return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
NULL, VERIFYING_MODULE_SIGNATURE, VERIFY_USE_SECONDARY_KEYRING,
VERIFYING_MODULE_SIGNATURE,
NULL, NULL); NULL, NULL);
} }
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