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>
This commit is contained in:
Arjan van de Ven 2008-08-15 15:29:38 -07:00 коммит произвёл Ingo Molnar
Родитель b09c3e3f17
Коммит 1b2439dbb7
2 изменённых файлов: 26 добавлений и 0 удалений

Просмотреть файл

@ -21,6 +21,10 @@ BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
static int notifier_chain_register(struct notifier_block **nl, static int notifier_chain_register(struct notifier_block **nl,
struct notifier_block *n) struct notifier_block *n)
{ {
if (!kernel_text_address((unsigned long)n->notifier_call)) {
WARN(1, "Invalid notifier registered!");
return 0;
}
while ((*nl) != NULL) { while ((*nl) != NULL) {
if (n->priority > (*nl)->priority) if (n->priority > (*nl)->priority)
break; break;
@ -34,6 +38,10 @@ static int notifier_chain_register(struct notifier_block **nl,
static int notifier_chain_cond_register(struct notifier_block **nl, static int notifier_chain_cond_register(struct notifier_block **nl,
struct notifier_block *n) struct notifier_block *n)
{ {
if (!kernel_text_address((unsigned long)n->notifier_call)) {
WARN(1, "Invalid notifier registered!");
return 0;
}
while ((*nl) != NULL) { while ((*nl) != NULL) {
if ((*nl) == n) if ((*nl) == n)
return 0; return 0;
@ -82,6 +90,14 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl,
while (nb && nr_to_call) { while (nb && nr_to_call) {
next_nb = rcu_dereference(nb->next); next_nb = rcu_dereference(nb->next);
#ifdef CONFIG_DEBUG_NOTIFIERS
if (!kernel_text_address((unsigned long)nb->notifier_call)) {
WARN(1, "Invalid notifier called!");
nb = next_nb;
continue;
}
#endif
ret = nb->notifier_call(nb, val, v); ret = nb->notifier_call(nb, val, v);
if (nr_calls) if (nr_calls)

Просмотреть файл

@ -536,6 +536,16 @@ config DEBUG_SG
If unsure, say N. If unsure, say N.
config DEBUG_NOTIFIERS
bool "Debug notifier call chains"
depends on DEBUG_KERNEL
help
Enable this to turn on sanity checking for notifier call chains.
This is most useful for kernel developers to make sure that
modules properly unregister themselves from notifier chains.
This is a relatively cheap check but if you care about maximum
performance, say N.
config FRAME_POINTER config FRAME_POINTER
bool "Compile the kernel with frame pointers" bool "Compile the kernel with frame pointers"
depends on DEBUG_KERNEL && \ depends on DEBUG_KERNEL && \