Commit 5e2f1b20 authored by Petr Vandrovec's avatar Petr Vandrovec Committed by Linus Torvalds

[PATCH] Weak symbols in modules and versioned symbols

Weak symbol may be unavailable in kernel, but if it is available, its
signature should be same as was at the build time.  If we do not attach
signatures to weak symbols, kernel is tainted when such module is loaded.

vmmon: no version for "sys_ioctl" found: kernel tainted.

I also believe that it is safer to add & check signatures here - module
wants either sys_ioctl with right signature, or no sys_ioctl at all, not
sys_ioctl with different signature (which signals that there is some
misbuild occuring).
Signed-off-by: default avatarPetr Vandrovec <vandrove@vc.cvut.cz>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (forwarded)
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e7ddba03
...@@ -104,6 +104,7 @@ struct symbol { ...@@ -104,6 +104,7 @@ struct symbol {
struct module *module; struct module *module;
unsigned int crc; unsigned int crc;
int crc_valid; int crc_valid;
unsigned int weak:1;
char name[0]; char name[0];
}; };
...@@ -126,12 +127,13 @@ static inline unsigned int tdb_hash(const char *name) ...@@ -126,12 +127,13 @@ static inline unsigned int tdb_hash(const char *name)
* the list of unresolved symbols per module */ * the list of unresolved symbols per module */
struct symbol * struct symbol *
alloc_symbol(const char *name, struct symbol *next) alloc_symbol(const char *name, unsigned int weak, struct symbol *next)
{ {
struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
strcpy(s->name, name); strcpy(s->name, name);
s->weak = weak;
s->next = next; s->next = next;
return s; return s;
} }
...@@ -145,7 +147,7 @@ new_symbol(const char *name, struct module *module, unsigned int *crc) ...@@ -145,7 +147,7 @@ new_symbol(const char *name, struct module *module, unsigned int *crc)
struct symbol *new; struct symbol *new;
hash = tdb_hash(name) % SYMBOL_HASH_SIZE; hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
new = symbolhash[hash] = alloc_symbol(name, symbolhash[hash]); new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
new->module = module; new->module = module;
if (crc) { if (crc) {
new->crc = *crc; new->crc = *crc;
...@@ -349,7 +351,8 @@ handle_modversions(struct module *mod, struct elf_info *info, ...@@ -349,7 +351,8 @@ handle_modversions(struct module *mod, struct elf_info *info,
break; break;
case SHN_UNDEF: case SHN_UNDEF:
/* undefined symbol */ /* undefined symbol */
if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
ELF_ST_BIND(sym->st_info) != STB_WEAK)
break; break;
/* ignore global offset table */ /* ignore global offset table */
if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
...@@ -370,6 +373,7 @@ handle_modversions(struct module *mod, struct elf_info *info, ...@@ -370,6 +373,7 @@ handle_modversions(struct module *mod, struct elf_info *info,
strlen(MODULE_SYMBOL_PREFIX)) == 0) strlen(MODULE_SYMBOL_PREFIX)) == 0)
mod->unres = alloc_symbol(symname + mod->unres = alloc_symbol(symname +
strlen(MODULE_SYMBOL_PREFIX), strlen(MODULE_SYMBOL_PREFIX),
ELF_ST_BIND(sym->st_info) == STB_WEAK,
mod->unres); mod->unres);
break; break;
default: default:
...@@ -476,7 +480,7 @@ read_symbols(char *modname) ...@@ -476,7 +480,7 @@ read_symbols(char *modname)
* the automatic versioning doesn't pick it up, but it's really * the automatic versioning doesn't pick it up, but it's really
* important anyhow */ * important anyhow */
if (modversions) if (modversions)
mod->unres = alloc_symbol("struct_module", mod->unres); mod->unres = alloc_symbol("struct_module", 0, mod->unres);
} }
#define SZ 500 #define SZ 500
...@@ -548,7 +552,7 @@ add_versions(struct buffer *b, struct module *mod) ...@@ -548,7 +552,7 @@ add_versions(struct buffer *b, struct module *mod)
for (s = mod->unres; s; s = s->next) { for (s = mod->unres; s; s = s->next) {
exp = find_symbol(s->name); exp = find_symbol(s->name);
if (!exp || exp->module == mod) { if (!exp || exp->module == mod) {
if (have_vmlinux) if (have_vmlinux && !s->weak)
fprintf(stderr, "*** Warning: \"%s\" [%s.ko] " fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
"undefined!\n", s->name, mod->name); "undefined!\n", s->name, mod->name);
continue; continue;
......
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