linux/net/l2tp
Guillaume Nault f98be6c635 l2tp: initialise PPP sessions before registering them
pppol2tp_connect() initialises L2TP sessions after they've been exposed
to the rest of the system by l2tp_session_register(). This puts
sessions into transient states that are the source of several races, in
particular with session's deletion path.

This patch centralises the initialisation code into
pppol2tp_session_init(), which is called before the registration phase.
The only field that can't be set before session registration is the
pppol2tp socket pointer, which has already been converted to RCU. So
pppol2tp_connect() should now be race-free.

The session's .session_close() callback is now set before registration.
Therefore, it's always called when l2tp_core deletes the session, even
if it was created by pppol2tp_session_create() and hasn't been plugged
to a pppol2tp socket yet. That'd prevent session free because the extra
reference taken by pppol2tp_session_close() wouldn't be dropped by the
socket's ->sk_destruct() callback (pppol2tp_session_destruct()).
We could set .session_close() only while connecting a session to its
pppol2tp socket, or teach pppol2tp_session_close() to avoid grabbing a
reference when the session isn't connected, but that'd require adding
some form of synchronisation to be race free.

Instead of that, we can just let the pppol2tp socket hold a reference
on the session as soon as it starts depending on it (that is, in
pppol2tp_connect()). Then we don't need to utilise
pppol2tp_session_close() to hold a reference at the last moment to
prevent l2tp_core from dropping it.

When releasing the socket, pppol2tp_release() now deletes the session
using the standard l2tp_session_delete() function, instead of merely
removing it from hash tables. l2tp_session_delete() drops the reference
the sessions holds on itself, but also makes sure it doesn't remove a
session twice. So it can safely be called, even if l2tp_core already
tried, or is concurrently trying, to remove the session.
Finally, pppol2tp_session_destruct() drops the reference held by the
socket.

Fixes: fd558d186d ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts")
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-29 11:16:22 +09:00
..
Kconfig l2tp: Call udp_sock_create 2014-07-14 16:12:15 -07:00
l2tp_core.c l2tp: don't register sessions in l2tp_session_create() 2017-10-29 11:16:21 +09:00
l2tp_core.h l2tp: don't register sessions in l2tp_session_create() 2017-10-29 11:16:21 +09:00
l2tp_debugfs.c net, l2tp: convert l2tp_tunnel.ref_count from atomic_t to refcount_t 2017-07-04 22:35:15 +01:00
l2tp_eth.c l2tp: initialise l2tp_eth sessions before registering them 2017-10-29 11:16:22 +09:00
l2tp_ip6.c l2tp: fix race in l2tp_recv_common() 2017-04-01 20:16:41 -07:00
l2tp_ip.c l2tp: fix race in l2tp_recv_common() 2017-04-01 20:16:41 -07:00
l2tp_netlink.c l2tp: cleanup l2tp_tunnel_delete calls 2017-10-27 13:48:32 +09:00
l2tp_ppp.c l2tp: initialise PPP sessions before registering them 2017-10-29 11:16:22 +09:00
Makefile l2tp: introduce L2TPv3 IP encapsulation support for IPv6 2012-05-01 09:30:55 -04:00