Re: [syzbot] [bpf?] possible deadlock in kvfree_call_rcu

From: Hillf Danton
Date: Sun Mar 31 2024 - 02:26:17 EST


On Sat, 30 Mar 2024 18:55:41 +0100 Uladzislau Rezki <urezki@xxxxxxxxx>
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index d9642dd06c25..8867aac3668c 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -3467,19 +3467,19 @@ void kvfree_call_rcu(struct rcu_head *head, void *ptr)
> */
> kmemleak_ignore(ptr);
>
> - // Set timer to drain after KFREE_DRAIN_JIFFIES.
> - if (rcu_scheduler_active == RCU_SCHEDULER_RUNNING)
> - schedule_delayed_monitor_work(krcp);
> -

This is not enough at least WRT run_page_cache_worker() [1]

[1] https://lore.kernel.org/lkml/0000000000007a44120614e27cb7@xxxxxxxxxx/

while the reason why syzbot failed to catch the zone->per_cpu_pageset in
setup_zone_pageset() in mm/page_alloc.c is trylock [2]

[2] https://lore.kernel.org/lkml/000000000000a5ee4e0614ee586e@xxxxxxxxxx/

> unlock_return:
> krc_this_cpu_unlock(krcp, flags);
>
> - /*
> - * Inline kvfree() after synchronize_rcu(). We can do
> - * it from might_sleep() context only, so the current
> - * CPU can pass the QS state.
> - */
> - if (!success) {
> + if (success) {
> + // Set timer to drain after KFREE_DRAIN_JIFFIES.
> + if (rcu_scheduler_active == RCU_SCHEDULER_RUNNING)
> + schedule_delayed_monitor_work(krcp);
> + } else {
> + /*
> + * Inline kvfree() after synchronize_rcu(). We can do
> + * it from might_sleep() context only, so the current
> + * CPU can pass the QS state.
> + */
> debug_rcu_head_unqueue((struct rcu_head *) ptr);
> synchronize_rcu();
> kvfree(ptr);
>
>
> --