Commit ea07890a680273b25127129fb555aac0d9324bea
Committed by
Linus Torvalds
1 parent
ae84e32470
Fix race between rmmod and cat /proc/kallsyms
module_get_kallsym() leaks "struct module *" outside of module_mutex which is no-no, because module can dissapear right after mutex unlock. Copy all needed information from inside module_mutex into caller-supplied space. [bunk@stusta.de: is_exported() can now become static] Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru> Cc: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 29 additions and 34 deletions Side-by-side Diff
include/linux/module.h
... | ... | @@ -370,16 +370,14 @@ |
370 | 370 | struct module *__module_text_address(unsigned long addr); |
371 | 371 | int is_module_address(unsigned long addr); |
372 | 372 | |
373 | -/* Returns module and fills in value, defined and namebuf, or NULL if | |
373 | +/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if | |
374 | 374 | symnum out of range. */ |
375 | -struct module *module_get_kallsym(unsigned int symnum, unsigned long *value, | |
376 | - char *type, char *name); | |
375 | +int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |
376 | + char *name, char *module_name, int *exported); | |
377 | 377 | |
378 | 378 | /* Look for this name: can be of form module:name. */ |
379 | 379 | unsigned long module_kallsyms_lookup_name(const char *name); |
380 | 380 | |
381 | -int is_exported(const char *name, const struct module *mod); | |
382 | - | |
383 | 381 | extern void __module_put_and_exit(struct module *mod, long code) |
384 | 382 | __attribute__((noreturn)); |
385 | 383 | #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); |
386 | 384 | |
387 | 385 | |
... | ... | @@ -527,19 +525,14 @@ |
527 | 525 | return NULL; |
528 | 526 | } |
529 | 527 | |
530 | -static inline struct module *module_get_kallsym(unsigned int symnum, | |
531 | - unsigned long *value, | |
532 | - char *type, char *name) | |
528 | +static inline int module_get_kallsym(unsigned int symnum, unsigned long *value, | |
529 | + char *type, char *name, | |
530 | + char *module_name, int *exported) | |
533 | 531 | { |
534 | - return NULL; | |
532 | + return -ERANGE; | |
535 | 533 | } |
536 | 534 | |
537 | 535 | static inline unsigned long module_kallsyms_lookup_name(const char *name) |
538 | -{ | |
539 | - return 0; | |
540 | -} | |
541 | - | |
542 | -static inline int is_exported(const char *name, const struct module *mod) | |
543 | 536 | { |
544 | 537 | return 0; |
545 | 538 | } |
kernel/kallsyms.c
... | ... | @@ -301,25 +301,20 @@ |
301 | 301 | struct kallsym_iter |
302 | 302 | { |
303 | 303 | loff_t pos; |
304 | - struct module *owner; | |
305 | 304 | unsigned long value; |
306 | 305 | unsigned int nameoff; /* If iterating in core kernel symbols */ |
307 | 306 | char type; |
308 | 307 | char name[KSYM_NAME_LEN+1]; |
308 | + char module_name[MODULE_NAME_LEN + 1]; | |
309 | + int exported; | |
309 | 310 | }; |
310 | 311 | |
311 | 312 | static int get_ksymbol_mod(struct kallsym_iter *iter) |
312 | 313 | { |
313 | - iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms, | |
314 | - &iter->value, &iter->type, | |
315 | - iter->name); | |
316 | - if (iter->owner == NULL) | |
314 | + if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value, | |
315 | + &iter->type, iter->name, iter->module_name, | |
316 | + &iter->exported) < 0) | |
317 | 317 | return 0; |
318 | - | |
319 | - /* Label it "global" if it is exported, "local" if not exported. */ | |
320 | - iter->type = is_exported(iter->name, iter->owner) | |
321 | - ? toupper(iter->type) : tolower(iter->type); | |
322 | - | |
323 | 318 | return 1; |
324 | 319 | } |
325 | 320 | |
... | ... | @@ -328,7 +323,7 @@ |
328 | 323 | { |
329 | 324 | unsigned off = iter->nameoff; |
330 | 325 | |
331 | - iter->owner = NULL; | |
326 | + iter->module_name[0] = '\0'; | |
332 | 327 | iter->value = kallsyms_addresses[iter->pos]; |
333 | 328 | |
334 | 329 | iter->type = kallsyms_get_symbol_type(off); |
335 | 330 | |
... | ... | @@ -392,12 +387,17 @@ |
392 | 387 | if (!iter->name[0]) |
393 | 388 | return 0; |
394 | 389 | |
395 | - if (iter->owner) | |
390 | + if (iter->module_name[0]) { | |
391 | + char type; | |
392 | + | |
393 | + /* Label it "global" if it is exported, | |
394 | + * "local" if not exported. */ | |
395 | + type = iter->exported ? toupper(iter->type) : | |
396 | + tolower(iter->type); | |
396 | 397 | seq_printf(m, "%0*lx %c %s\t[%s]\n", |
397 | 398 | (int)(2*sizeof(void*)), |
398 | - iter->value, iter->type, iter->name, | |
399 | - module_name(iter->owner)); | |
400 | - else | |
399 | + iter->value, type, iter->name, iter->module_name); | |
400 | + } else | |
401 | 401 | seq_printf(m, "%0*lx %c %s\n", |
402 | 402 | (int)(2*sizeof(void*)), |
403 | 403 | iter->value, iter->type, iter->name); |
kernel/module.c
... | ... | @@ -1472,7 +1472,7 @@ |
1472 | 1472 | } |
1473 | 1473 | |
1474 | 1474 | #ifdef CONFIG_KALLSYMS |
1475 | -int is_exported(const char *name, const struct module *mod) | |
1475 | +static int is_exported(const char *name, const struct module *mod) | |
1476 | 1476 | { |
1477 | 1477 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) |
1478 | 1478 | return 1; |
... | ... | @@ -2124,8 +2124,8 @@ |
2124 | 2124 | return NULL; |
2125 | 2125 | } |
2126 | 2126 | |
2127 | -struct module *module_get_kallsym(unsigned int symnum, unsigned long *value, | |
2128 | - char *type, char *name) | |
2127 | +int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |
2128 | + char *name, char *module_name, int *exported) | |
2129 | 2129 | { |
2130 | 2130 | struct module *mod; |
2131 | 2131 | |
2132 | 2132 | |
2133 | 2133 | |
... | ... | @@ -2136,13 +2136,15 @@ |
2136 | 2136 | *type = mod->symtab[symnum].st_info; |
2137 | 2137 | strlcpy(name, mod->strtab + mod->symtab[symnum].st_name, |
2138 | 2138 | KSYM_NAME_LEN + 1); |
2139 | + strlcpy(module_name, mod->name, MODULE_NAME_LEN + 1); | |
2140 | + *exported = is_exported(name, mod); | |
2139 | 2141 | mutex_unlock(&module_mutex); |
2140 | - return mod; | |
2142 | + return 0; | |
2141 | 2143 | } |
2142 | 2144 | symnum -= mod->num_symtab; |
2143 | 2145 | } |
2144 | 2146 | mutex_unlock(&module_mutex); |
2145 | - return NULL; | |
2147 | + return -ERANGE; | |
2146 | 2148 | } |
2147 | 2149 | |
2148 | 2150 | static unsigned long mod_find_symname(struct module *mod, const char *name) |