• Ridge Kennedy's avatar
    l2tp: Avoid schedule while atomic in exit_net · 12d656af
    Ridge Kennedy authored
    While destroying a network namespace that contains a L2TP tunnel a
    "BUG: scheduling while atomic" can be observed.
    
    Enabling lockdep shows that this is happening because l2tp_exit_net()
    is calling l2tp_tunnel_closeall() (via l2tp_tunnel_delete()) from
    within an RCU critical section.
    
    l2tp_exit_net() takes rcu_read_lock_bh()
      << list_for_each_entry_rcu() >>
      l2tp_tunnel_delete()
        l2tp_tunnel_closeall()
          __l2tp_session_unhash()
            synchronize_rcu() << Illegal inside RCU critical section >>
    
    BUG: sleeping function called from invalid context
    in_atomic(): 1, irqs_disabled(): 0, pid: 86, name: kworker/u16:2
    INFO: lockdep is turned off.
    CPU: 2 PID: 86 Comm: kworker/u16:2 Tainted: G        W  O    4.4.6-at1 #2
    Hardware name: Xen HVM domU, BIOS 4.6.1-xs125300 05/09/2016
    Workqueue: netns cleanup_net
     0000000000000000 ffff880202417b90 ffffffff812b0013 ffff880202410ac0
     ffffffff81870de8 ffff880202417bb8 ffffffff8107aee8 ffffffff81870de8
     0000000000000c51 0000000000000000 ffff880202417be0 ffffffff8107b024
    Call Trace:
     [<ffffffff812b0013>] dump_stack+0x85/0xc2
     [<ffffffff8107aee8>] ___might_sleep+0x148/0x240
     [<ffffffff8107b024>] __might_sleep+0x44/0x80
     [<ffffffff810b21bd>] synchronize_sched+0x2d/0xe0
     [<ffffffff8109be6d>] ? trace_hardirqs_on+0xd/0x10
     [<ffffffff8105c7bb>] ? __local_bh_enable_ip+0x6b/0xc0
     [<ffffffff816a1b00>] ? _raw_spin_unlock_bh+0x30/0x40
     [<ffffffff81667482>] __l2tp_session_unhash+0x172/0x220
     [<ffffffff81667397>] ? __l2tp_session_unhash+0x87/0x220
     [<ffffffff8166888b>] l2tp_tunnel_closeall+0x9b/0x140
     [<ffffffff81668c74>] l2tp_tunnel_delete+0x14/0x60
     [<ffffffff81668dd0>] l2tp_exit_net+0x110/0x270
     [<ffffffff81668d5c>] ? l2tp_exit_net+0x9c/0x270
     [<ffffffff815001c3>] ops_exit_list.isra.6+0x33/0x60
     [<ffffffff81501166>] cleanup_net+0x1b6/0x280
     ...
    
    This bug can easily be reproduced with a few steps:
    
     $ sudo unshare -n bash  # Create a shell in a new namespace
     # ip link set lo up
     # ip addr add 127.0.0.1 dev lo
     # ip l2tp add tunnel remote 127.0.0.1 local 127.0.0.1 tunnel_id 1 \
        peer_tunnel_id 1 udp_sport 50000 udp_dport 50000
     # ip l2tp add session name foo tunnel_id 1 session_id 1 \
        peer_session_id 1
     # ip link set foo up
     # exit  # Exit the shell, in turn exiting the namespace
     $ dmesg
     ...
     [942121.089216] BUG: scheduling while atomic: kworker/u16:3/13872/0x00000200
     ...
    
    To fix this, move the call to l2tp_tunnel_closeall() out of the RCU
    critical section, and instead call it from l2tp_tunnel_del_work(), which
    is running from the l2tp_wq workqueue.
    
    Fixes: 2b551c6e ("l2tp: close sessions before initiating tunnel delete")
    Signed-off-by: default avatarRidge Kennedy <ridge.kennedy@alliedtelesis.co.nz>
    Acked-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    12d656af
l2tp_core.c 51.2 KB