Commit a06f6211ef9b1785922f9d0e8766d63ac4e66de1

Authored by Masami Hiramatsu
Committed by Linus Torvalds
1 parent 12da3b888b

module: add within_module_core() and within_module_init()

This series of patches allows kprobes to probe module's __init and __exit
functions.  This means, you can probe driver initialization and
terminating.

Currently, kprobes can't probe __init function because these functions are
freed after module initialization.  And it also can't probe module __exit
functions because kprobe increments reference count of target module and
user can't unload it.  this means __exit functions never be called unless
removing probes from the module.

To solve both cases, this series of patches introduces GONE flag and sets
it when the target code is freed(for this purpose, kprobes hooks
MODULE_STATE_* events).  This also removes refcount incrementing for
allowing user to unload target module.  Users can check which probes are
GONE by debugfs interface.  For taking timing of freeing module's .init
text, these also include a patch which adds module's notifier of
MODULE_STATE_LIVE event.

This patch:

Add within_module_core() and within_module_init() for checking whether an
address is in the module .init.text section or .text section, and replace
within() local inline functions in kernel/module.c with them.

kprobes uses these functions to check where the kprobe is inserted.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 20 additions and 8 deletions Side-by-side Diff

include/linux/module.h
... ... @@ -365,6 +365,18 @@
365 365 struct module *__module_text_address(unsigned long addr);
366 366 int is_module_address(unsigned long addr);
367 367  
  368 +static inline int within_module_core(unsigned long addr, struct module *mod)
  369 +{
  370 + return (unsigned long)mod->module_core <= addr &&
  371 + addr < (unsigned long)mod->module_core + mod->core_size;
  372 +}
  373 +
  374 +static inline int within_module_init(unsigned long addr, struct module *mod)
  375 +{
  376 + return (unsigned long)mod->module_init <= addr &&
  377 + addr < (unsigned long)mod->module_init + mod->init_size;
  378 +}
  379 +
368 380 /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
369 381 symnum out of range. */
370 382 int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
... ... @@ -2390,7 +2390,7 @@
2390 2390 unsigned long nextval;
2391 2391  
2392 2392 /* At worse, next value is at end of module */
2393   - if (within(addr, mod->module_init, mod->init_size))
  2393 + if (within_module_init(addr, mod))
2394 2394 nextval = (unsigned long)mod->module_init+mod->init_text_size;
2395 2395 else
2396 2396 nextval = (unsigned long)mod->module_core+mod->core_text_size;
... ... @@ -2438,8 +2438,8 @@
2438 2438  
2439 2439 preempt_disable();
2440 2440 list_for_each_entry_rcu(mod, &modules, list) {
2441   - if (within(addr, mod->module_init, mod->init_size)
2442   - || within(addr, mod->module_core, mod->core_size)) {
  2441 + if (within_module_init(addr, mod) ||
  2442 + within_module_core(addr, mod)) {
2443 2443 if (modname)
2444 2444 *modname = mod->name;
2445 2445 ret = get_ksymbol(mod, addr, size, offset);
... ... @@ -2461,8 +2461,8 @@
2461 2461  
2462 2462 preempt_disable();
2463 2463 list_for_each_entry_rcu(mod, &modules, list) {
2464   - if (within(addr, mod->module_init, mod->init_size) ||
2465   - within(addr, mod->module_core, mod->core_size)) {
  2464 + if (within_module_init(addr, mod) ||
  2465 + within_module_core(addr, mod)) {
2466 2466 const char *sym;
2467 2467  
2468 2468 sym = get_ksymbol(mod, addr, NULL, NULL);
... ... @@ -2485,8 +2485,8 @@
2485 2485  
2486 2486 preempt_disable();
2487 2487 list_for_each_entry_rcu(mod, &modules, list) {
2488   - if (within(addr, mod->module_init, mod->init_size) ||
2489   - within(addr, mod->module_core, mod->core_size)) {
  2488 + if (within_module_init(addr, mod) ||
  2489 + within_module_core(addr, mod)) {
2490 2490 const char *sym;
2491 2491  
2492 2492 sym = get_ksymbol(mod, addr, size, offset);
... ... @@ -2705,7 +2705,7 @@
2705 2705 preempt_disable();
2706 2706  
2707 2707 list_for_each_entry_rcu(mod, &modules, list) {
2708   - if (within(addr, mod->module_core, mod->core_size)) {
  2708 + if (within_module_core(addr, mod)) {
2709 2709 preempt_enable();
2710 2710 return 1;
2711 2711 }