• Guillaume Nault's avatar
    l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall() · b228a940
    Guillaume Nault authored
    There are several ways to remove L2TP sessions:
    
      * deleting a session explicitly using the netlink interface (with
        L2TP_CMD_SESSION_DELETE),
      * deleting the session's parent tunnel (either by closing the
        tunnel's file descriptor or using the netlink interface),
      * closing the PPPOL2TP file descriptor of a PPP pseudo-wire.
    
    In some cases, when these methods are used concurrently on the same
    session, the session can be removed twice, leading to use-after-free
    bugs.
    
    This patch adds a 'dead' flag, used by l2tp_session_delete() and
    l2tp_tunnel_closeall() to prevent them from stepping on each other's
    toes.
    
    The session deletion path used when closing a PPPOL2TP file descriptor
    doesn't need to be adapted. It already has to ensure that a session
    remains valid for the lifetime of its PPPOL2TP file descriptor.
    So it takes an extra reference on the session in the ->session_close()
    callback (pppol2tp_session_close()), which is eventually dropped
    in the ->sk_destruct() callback of the PPPOL2TP socket
    (pppol2tp_session_destruct()).
    Still, __l2tp_session_unhash() and l2tp_session_queue_purge() can be
    called twice and even concurrently for a given session, but thanks to
    proper locking and re-initialisation of list fields, this is not an
    issue.
    Signed-off-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    b228a940
l2tp_core.c 51.5 KB