On 7/10/19 6:09 AM, Xiaoming Ni wrote: > Registering the same notifier to a hook repeatedly can cause the hook > list to form a ring or lose other members of the list. > > case1: An infinite loop in notifier_chain_register() can cause soft lockup > atomic_notifier_chain_register(&test_notifier_list, &test1); > atomic_notifier_chain_register(&test_notifier_list, &test1); > atomic_notifier_chain_register(&test_notifier_list, &test2); > > case2: An infinite loop in notifier_chain_register() can cause soft lockup > atomic_notifier_chain_register(&test_notifier_list, &test1); > atomic_notifier_chain_register(&test_notifier_list, &test1); > atomic_notifier_call_chain(&test_notifier_list, 0, NULL); > > case3: lose other hook test2 > atomic_notifier_chain_register(&test_notifier_list, &test1); > atomic_notifier_chain_register(&test_notifier_list, &test2); > atomic_notifier_chain_register(&test_notifier_list, &test1); > > case4: Unregister returns 0, but the hook is still in the linked list, > and it is not really registered. If you call notifier_call_chain > after ko is unloaded, it will trigger oops. > > If the system is configured with softlockup_panic and the same > hook is repeatedly registered on the panic_notifier_list, it > will cause a loop panic. > > Add a check in notifier_chain_register() to avoid duplicate registration > > Signed-off-by: Xiaoming Ni <nixiaoming@xxxxxxxxxx> Reviewed-by: Vasily Averin <vvs@xxxxxxxxxxxxx> > --- > kernel/notifier.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/kernel/notifier.c b/kernel/notifier.c > index d9f5081..30bedb8 100644 > --- a/kernel/notifier.c > +++ b/kernel/notifier.c > @@ -23,7 +23,10 @@ static int notifier_chain_register(struct notifier_block **nl, > struct notifier_block *n) > { > while ((*nl) != NULL) { > - WARN_ONCE(((*nl) == n), "double register detected"); > + if (unlikely((*nl) == n)) { > + WARN(1, "double register detected"); > + return 0; > + } > if (n->priority > (*nl)->priority) > break; > nl = &((*nl)->next); >