• Guillaume Nault's avatar
    l2tp: protect sock pointer of struct pppol2tp_session with RCU · 7b91551a
    Guillaume Nault authored
    BugLink: https://bugs.launchpad.net/bugs/1883916
    
    commit ee40fb2e upstream.
    
    pppol2tp_session_create() registers sessions that can't have their
    corresponding socket initialised. This socket has to be created by
    userspace, then connected to the session by pppol2tp_connect().
    Therefore, we need to protect the pppol2tp socket pointer of L2TP
    sessions, so that it can safely be updated when userspace is connecting
    or closing the socket. This will eventually allow pppol2tp_connect()
    to avoid generating transient states while initialising its parts of the
    session.
    
    To this end, this patch protects the pppol2tp socket pointer using RCU.
    
    The pppol2tp socket pointer is still set in pppol2tp_connect(), but
    only once we know the function isn't going to fail. It's eventually
    reset by pppol2tp_release(), which now has to wait for a grace period
    to elapse before it can drop the last reference on the socket. This
    ensures that pppol2tp_session_get_sock() can safely grab a reference
    on the socket, even after ps->sk is reset to NULL but before this
    operation actually gets visible from pppol2tp_session_get_sock().
    
    The rest is standard RCU conversion: pppol2tp_recv(), which already
    runs in atomic context, is simply enclosed by rcu_read_lock() and
    rcu_read_unlock(), while other functions are converted to use
    pppol2tp_session_get_sock() followed by sock_put().
    pppol2tp_session_setsockopt() is a special case. It used to retrieve
    the pppol2tp socket from the L2TP session, which itself was retrieved
    from the pppol2tp socket. Therefore we can just avoid dereferencing
    ps->sk and directly use the original socket pointer instead.
    
    With all users of ps->sk now handling NULL and concurrent updates, the
    L2TP ->ref() and ->deref() callbacks aren't needed anymore. Therefore,
    rather than converting pppol2tp_session_sock_hold() and
    pppol2tp_session_sock_put(), we can just drop them.
    Signed-off-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    Signed-off-by: default avatarGiuliano Procida <gprocida@google.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
    Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
    7b91551a
l2tp_ppp.c 48.7 KB