l2tp: fix race in l2tp_recv_common()
Taking a reference on sessions in l2tp_recv_common() is racy; this
has to be done by the callers.
To this end, a new function is required (l2tp_session_get()) to
atomically lookup a session and take a reference on it. Callers then
have to manually drop this reference.
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>
This commit is contained in:

committed by
David S. Miller

parent
afe89962ee
commit
61b9a04772
@@ -143,19 +143,19 @@ static int l2tp_ip_recv(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
/* Ok, this is a data packet. Lookup the session. */
|
||||
session = l2tp_session_find(net, NULL, session_id);
|
||||
if (session == NULL)
|
||||
session = l2tp_session_get(net, NULL, session_id, true);
|
||||
if (!session)
|
||||
goto discard;
|
||||
|
||||
tunnel = session->tunnel;
|
||||
if (tunnel == NULL)
|
||||
goto discard;
|
||||
if (!tunnel)
|
||||
goto discard_sess;
|
||||
|
||||
/* Trace packet contents, if enabled */
|
||||
if (tunnel->debug & L2TP_MSG_DATA) {
|
||||
length = min(32u, skb->len);
|
||||
if (!pskb_may_pull(skb, length))
|
||||
goto discard;
|
||||
goto discard_sess;
|
||||
|
||||
/* Point to L2TP header */
|
||||
optr = ptr = skb->data;
|
||||
@@ -165,6 +165,7 @@ static int l2tp_ip_recv(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook);
|
||||
l2tp_session_dec_refcount(session);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -203,6 +204,12 @@ pass_up:
|
||||
|
||||
return sk_receive_skb(sk, skb, 1);
|
||||
|
||||
discard_sess:
|
||||
if (session->deref)
|
||||
session->deref(session);
|
||||
l2tp_session_dec_refcount(session);
|
||||
goto discard;
|
||||
|
||||
discard_put:
|
||||
sock_put(sk);
|
||||
|
||||
|
Reference in New Issue
Block a user