diff options
author | Arjan van de Ven <arjan@linux.intel.com> | 2008-08-15 18:29:38 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-09-10 03:08:50 -0400 |
commit | 1b2439dbb703ae8d95a9ce7ece6b7800b80f41f0 (patch) | |
tree | 63c6c105b86ce45ca010dca4bd501a924afd05d1 | |
parent | b09c3e3f1710b554348c98e78fbf4a661918779a (diff) |
debug: add notifier chain debugging
during some development we suspected a case where we left something
in a notifier chain that was from a module that was unloaded already...
and that sort of thing is rather hard to track down.
This patch adds a very simple sanity check (which isn't all that
expensive) to make sure the notifier we're about to call is
actually from either the kernel itself of from a still-loaded
module, avoiding a hard-to-chase-down crash.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | kernel/notifier.c | 16 | ||||
-rw-r--r-- | lib/Kconfig.debug | 10 |
2 files changed, 26 insertions, 0 deletions
diff --git a/kernel/notifier.c b/kernel/notifier.c index 823be11584ef..143fdd77dbf7 100644 --- a/kernel/notifier.c +++ b/kernel/notifier.c | |||
@@ -21,6 +21,10 @@ BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); | |||
21 | static int notifier_chain_register(struct notifier_block **nl, | 21 | static int notifier_chain_register(struct notifier_block **nl, |
22 | struct notifier_block *n) | 22 | struct notifier_block *n) |
23 | { | 23 | { |
24 | if (!kernel_text_address((unsigned long)n->notifier_call)) { | ||
25 | WARN(1, "Invalid notifier registered!"); | ||
26 | return 0; | ||
27 | } | ||
24 | while ((*nl) != NULL) { | 28 | while ((*nl) != NULL) { |
25 | if (n->priority > (*nl)->priority) | 29 | if (n->priority > (*nl)->priority) |
26 | break; | 30 | break; |
@@ -34,6 +38,10 @@ static int notifier_chain_register(struct notifier_block **nl, | |||
34 | static int notifier_chain_cond_register(struct notifier_block **nl, | 38 | static int notifier_chain_cond_register(struct notifier_block **nl, |
35 | struct notifier_block *n) | 39 | struct notifier_block *n) |
36 | { | 40 | { |
41 | if (!kernel_text_address((unsigned long)n->notifier_call)) { | ||
42 | WARN(1, "Invalid notifier registered!"); | ||
43 | return 0; | ||
44 | } | ||
37 | while ((*nl) != NULL) { | 45 | while ((*nl) != NULL) { |
38 | if ((*nl) == n) | 46 | if ((*nl) == n) |
39 | return 0; | 47 | return 0; |
@@ -82,6 +90,14 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl, | |||
82 | 90 | ||
83 | while (nb && nr_to_call) { | 91 | while (nb && nr_to_call) { |
84 | next_nb = rcu_dereference(nb->next); | 92 | next_nb = rcu_dereference(nb->next); |
93 | |||
94 | #ifdef CONFIG_DEBUG_NOTIFIERS | ||
95 | if (!kernel_text_address((unsigned long)nb->notifier_call)) { | ||
96 | WARN(1, "Invalid notifier called!"); | ||
97 | nb = next_nb; | ||
98 | continue; | ||
99 | } | ||
100 | #endif | ||
85 | ret = nb->notifier_call(nb, val, v); | 101 | ret = nb->notifier_call(nb, val, v); |
86 | 102 | ||
87 | if (nr_calls) | 103 | if (nr_calls) |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8b5a7d304a5f..342858fbabbc 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -536,6 +536,16 @@ config DEBUG_SG | |||
536 | 536 | ||
537 | If unsure, say N. | 537 | If unsure, say N. |
538 | 538 | ||
539 | config DEBUG_NOTIFIERS | ||
540 | bool "Debug notifier call chains" | ||
541 | depends on DEBUG_KERNEL | ||
542 | help | ||
543 | Enable this to turn on sanity checking for notifier call chains. | ||
544 | This is most useful for kernel developers to make sure that | ||
545 | modules properly unregister themselves from notifier chains. | ||
546 | This is a relatively cheap check but if you care about maximum | ||
547 | performance, say N. | ||
548 | |||
539 | config FRAME_POINTER | 549 | config FRAME_POINTER |
540 | bool "Compile the kernel with frame pointers" | 550 | bool "Compile the kernel with frame pointers" |
541 | depends on DEBUG_KERNEL && \ | 551 | depends on DEBUG_KERNEL && \ |