From patchwork Thu Apr 2 17:32:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 228258 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.1 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C64A3C2BA12 for ; Thu, 2 Apr 2020 17:33:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5222F20737 for ; Thu, 2 Apr 2020 17:33:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848802; bh=1pIuzB4W0Eosq9gz9gNCtcL3U7BY3Gq0FE9pIv1cPok=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=gk+rChiWUO7ihoyVu3b0hcvMjdmKACJxr0AZ/yqfFJzRdO3d840japLvJemSCUMN7 PGTaFB204ykzKE5wlBPSkccv5qofAeHjX398jInMSak3afB57zU3lzWVznlii/it5j UqqPxZRyxgG/cyieMiDVJkSSXfZ2zKZsveLoyXX4= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388855AbgDBRdE (ORCPT ); Thu, 2 Apr 2020 13:33:04 -0400 Received: from mail.kernel.org ([198.145.29.99]:33262 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389964AbgDBRdD (ORCPT ); Thu, 2 Apr 2020 13:33:03 -0400 Received: from localhost.localdomain (236.31.169.217.in-addr.arpa [217.169.31.236]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 581D02080C; Thu, 2 Apr 2020 17:33:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848782; bh=1pIuzB4W0Eosq9gz9gNCtcL3U7BY3Gq0FE9pIv1cPok=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k+Uo6SzzDLKOrlGCAS3ZXF3JKsCb3RVvWXKvW2OlCRXsVIuz16KIE/FRZ7yoykS7x 7drQxbcMfAu1myReOlQfgUEVg5luH6FSmhud8aUl0msibPYYBFKNzjdTIUIsRJwfsh 1PN6kcM91lx+QGttCN49RCHplAi58nEHQaCyERHE= From: Will Deacon To: gregkh@linuxfoundation.org Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" , Will Deacon Subject: [PATCH 3/8] l2tp: fix race in l2tp_recv_common() Date: Thu, 2 Apr 2020 18:32:45 +0100 Message-Id: <20200402173250.7858-4-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200402173250.7858-1-will@kernel.org> References: <20200402173250.7858-1-will@kernel.org> MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Guillaume Nault commit 61b9a047729bb230978178bca6729689d0c50ca2 upstream. 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: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Will Deacon --- net/l2tp/l2tp_core.c | 73 ++++++++++++++++++++++++++++++++++++-------- net/l2tp/l2tp_core.h | 3 ++ net/l2tp/l2tp_ip.c | 17 ++++++++--- net/l2tp/l2tp_ip6.c | 18 ++++++++--- 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 429dbb064240..4d41fe40723d 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -277,6 +277,55 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn } EXPORT_SYMBOL_GPL(l2tp_session_find); +/* Like l2tp_session_find() but takes a reference on the returned session. + * Optionally calls session->ref() too if do_ref is true. + */ +struct l2tp_session *l2tp_session_get(struct net *net, + struct l2tp_tunnel *tunnel, + u32 session_id, bool do_ref) +{ + struct hlist_head *session_list; + struct l2tp_session *session; + + if (!tunnel) { + struct l2tp_net *pn = l2tp_pernet(net); + + session_list = l2tp_session_id_hash_2(pn, session_id); + + rcu_read_lock_bh(); + hlist_for_each_entry_rcu(session, session_list, global_hlist) { + if (session->session_id == session_id) { + l2tp_session_inc_refcount(session); + if (do_ref && session->ref) + session->ref(session); + rcu_read_unlock_bh(); + + return session; + } + } + rcu_read_unlock_bh(); + + return NULL; + } + + session_list = l2tp_session_id_hash(tunnel, session_id); + read_lock_bh(&tunnel->hlist_lock); + hlist_for_each_entry(session, session_list, hlist) { + if (session->session_id == session_id) { + l2tp_session_inc_refcount(session); + if (do_ref && session->ref) + session->ref(session); + read_unlock_bh(&tunnel->hlist_lock); + + return session; + } + } + read_unlock_bh(&tunnel->hlist_lock); + + return NULL; +} +EXPORT_SYMBOL_GPL(l2tp_session_get); + struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, bool do_ref) { @@ -636,6 +685,9 @@ discard: * a data (not control) frame before coming here. Fields up to the * session-id have already been parsed and ptr points to the data * after the session-id. + * + * session->ref() must have been called prior to l2tp_recv_common(). + * session->deref() will be called automatically after skb is processed. */ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, @@ -645,14 +697,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, int offset; u32 ns, nr; - /* The ref count is increased since we now hold a pointer to - * the session. Take care to decrement the refcnt when exiting - * this function from now on... - */ - l2tp_session_inc_refcount(session); - if (session->ref) - (*session->ref)(session); - /* Parse and check optional cookie */ if (session->peer_cookie_len > 0) { if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { @@ -803,8 +847,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, /* Try to dequeue as many skbs from reorder_q as we can. */ l2tp_recv_dequeue(session); - l2tp_session_dec_refcount(session); - return; discard: @@ -813,8 +855,6 @@ discard: if (session->deref) (*session->deref)(session); - - l2tp_session_dec_refcount(session); } EXPORT_SYMBOL(l2tp_recv_common); @@ -921,8 +961,14 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, } /* Find the session context */ - session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id); + session = l2tp_session_get(tunnel->l2tp_net, tunnel, session_id, true); if (!session || !session->recv_skb) { + if (session) { + if (session->deref) + session->deref(session); + l2tp_session_dec_refcount(session); + } + /* Not found? Pass to userspace to deal with */ l2tp_info(tunnel, L2TP_MSG_DATA, "%s: no session found (%u/%u). Passing up.\n", @@ -935,6 +981,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, goto error; l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook); + l2tp_session_dec_refcount(session); return 0; diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index fad47e9d74bc..705fbc63ddc2 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -243,6 +243,9 @@ out: return tunnel; } +struct l2tp_session *l2tp_session_get(struct net *net, + struct l2tp_tunnel *tunnel, + u32 session_id, bool do_ref); struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 7efb3cadc152..58f87bdd12c7 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -142,19 +142,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; @@ -167,6 +167,7 @@ static int l2tp_ip_recv(struct sk_buff *skb) goto discard; l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); + l2tp_session_dec_refcount(session); return 0; @@ -204,6 +205,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); diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 391dd9d8144f..af04a8a68269 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -154,19 +154,19 @@ static int l2tp_ip6_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; @@ -180,6 +180,8 @@ static int l2tp_ip6_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; pass_up: @@ -217,6 +219,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); From patchwork Thu Apr 2 17:32:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 228259 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.1 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45D61C2D0F3 for ; Thu, 2 Apr 2020 17:33:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C7B1A20737 for ; Thu, 2 Apr 2020 17:33:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848800; bh=sJF7vQJ8ozzfmrxTOD4ZSjgxGMIIeoVp+SeF6PQjLt8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=DPoIGfmPGe9qMMSqO1WmQFE2Ee/91ePT1g5N44/EtYikEsLafn4nZHzYplXxkIGIG tf+cLmgp2CSJ3I9LKp09eYCojBQY8SYR4B+eXpVn861jtEEkAbaCMjCuJYWWS+cwZ+ D41NNA6xA24kdLX/WzNuZ/bgl7eCfLiYxSvhxliY= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390003AbgDBRdF (ORCPT ); Thu, 2 Apr 2020 13:33:05 -0400 Received: from mail.kernel.org ([198.145.29.99]:33316 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389989AbgDBRdF (ORCPT ); Thu, 2 Apr 2020 13:33:05 -0400 Received: from localhost.localdomain (236.31.169.217.in-addr.arpa [217.169.31.236]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 0B0952078B; Thu, 2 Apr 2020 17:33:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848784; bh=sJF7vQJ8ozzfmrxTOD4ZSjgxGMIIeoVp+SeF6PQjLt8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=akwTSgasVO4KUgnagC8cQGTnd2zVWGrlHF6D+l6a4FGxBMezTYJX9a9+f/F+z+sZN 4XldhxcpxFs9Rhh21X1ijO9ZhsQthJOpNMZv3K5FpzW/D20T6BQy05iaX2uOcdOx8E xtTedkFHsQxb5rQRxUE/qys1oXCbl8X6sz0kZvqc= From: Will Deacon To: gregkh@linuxfoundation.org Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" , Will Deacon Subject: [PATCH 4/8] l2tp: ensure session can't get removed during pppol2tp_session_ioctl() Date: Thu, 2 Apr 2020 18:32:46 +0100 Message-Id: <20200402173250.7858-5-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200402173250.7858-1-will@kernel.org> References: <20200402173250.7858-1-will@kernel.org> MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Guillaume Nault commit 57377d63547861919ee634b845c7caa38de4a452 upstream. Holding a reference on session is required before calling pppol2tp_session_ioctl(). The session could get freed while processing the ioctl otherwise. Since pppol2tp_session_ioctl() uses the session's socket, we also need to take a reference on it in l2tp_session_get(). Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Will Deacon --- net/l2tp/l2tp_ppp.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index bc5fca07d2ee..74b211312d4d 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -1168,11 +1168,18 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel, if (stats.session_id != 0) { /* resend to session ioctl handler */ struct l2tp_session *session = - l2tp_session_find(sock_net(sk), tunnel, stats.session_id); - if (session != NULL) - err = pppol2tp_session_ioctl(session, cmd, arg); - else + l2tp_session_get(sock_net(sk), tunnel, + stats.session_id, true); + + if (session) { + err = pppol2tp_session_ioctl(session, cmd, + arg); + if (session->deref) + session->deref(session); + l2tp_session_dec_refcount(session); + } else { err = -EBADR; + } break; } #ifdef CONFIG_XFRM From patchwork Thu Apr 2 17:32:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 228260 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.1 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2C7E0C2BA12 for ; Thu, 2 Apr 2020 17:33:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0305D20737 for ; Thu, 2 Apr 2020 17:33:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848799; bh=xFeRDbN2a95z8dOx3Yw7IxgeW9E7HAdR3W5kLcO7yiQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=RDh/QXa9tJjm5eCiobksxMCU9bG31bnuj++UzEBb1o3x5IUNu2guIZSDtM0Gn17vU 8vj8NMo2wlDMW3Fv8Mu966D7nMDO3Mg8H2VaN65H17WIHEbkPQdzq9U8yaH86s+pxe PTK+XjqwkeXczZlYaYkj6jV0KvGRoBea9JxelWVM= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390052AbgDBRdJ (ORCPT ); Thu, 2 Apr 2020 13:33:09 -0400 Received: from mail.kernel.org ([198.145.29.99]:33424 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390035AbgDBRdJ (ORCPT ); Thu, 2 Apr 2020 13:33:09 -0400 Received: from localhost.localdomain (236.31.169.217.in-addr.arpa [217.169.31.236]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 63FCB2078B; Thu, 2 Apr 2020 17:33:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848787; bh=xFeRDbN2a95z8dOx3Yw7IxgeW9E7HAdR3W5kLcO7yiQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qWf52ruKxrYtqs74aKsmpaftse3RRFbTBcKV34jI7HGR2Vig86TKZMHxOwfPjf/u9 Yy9HzSOpsy34CqQQBQHiSIZLwkq/qX8RpbhxqvfJenHg7slL0Fvd1i9GYlHS5aXnHi ul0ZCn/ducKVPvMfBfjgzVivc+Mrs+hlQQ4NUSpA= From: Will Deacon To: gregkh@linuxfoundation.org Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, Gao Feng , "David S . Miller" , Will Deacon Subject: [PATCH 6/8] l2tp: Refactor the codes with existing macros instead of literal number Date: Thu, 2 Apr 2020 18:32:48 +0100 Message-Id: <20200402173250.7858-7-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200402173250.7858-1-will@kernel.org> References: <20200402173250.7858-1-will@kernel.org> MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Gao Feng commit 54c151d9ed1321e6e623c80ffe42cd2eb1571744 upstream. Use PPP_ALLSTATIONS, PPP_UI, and SEND_SHUTDOWN instead of 0xff, 0x03, and 2 separately. Signed-off-by: Gao Feng Acked-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Will Deacon --- net/l2tp/l2tp_ppp.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 97155145c0c5..98d4fa47b6a5 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -177,7 +177,7 @@ static int pppol2tp_recv_payload_hook(struct sk_buff *skb) if (!pskb_may_pull(skb, 2)) return 1; - if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03)) + if ((skb->data[0] == PPP_ALLSTATIONS) && (skb->data[1] == PPP_UI)) skb_pull(skb, 2); return 0; @@ -297,7 +297,6 @@ static void pppol2tp_session_sock_put(struct l2tp_session *session) static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) { - static const unsigned char ppph[2] = { 0xff, 0x03 }; struct sock *sk = sock->sk; struct sk_buff *skb; int error; @@ -327,7 +326,7 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m, error = -ENOMEM; skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len + - sizeof(ppph) + total_len, + 2 + total_len, /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */ 0, GFP_KERNEL); if (!skb) goto error_put_sess_tun; @@ -340,8 +339,8 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m, skb_reserve(skb, uhlen); /* Add PPP header */ - skb->data[0] = ppph[0]; - skb->data[1] = ppph[1]; + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; skb_put(skb, 2); /* Copy user data into skb */ @@ -384,7 +383,6 @@ error: */ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) { - static const u8 ppph[2] = { 0xff, 0x03 }; struct sock *sk = (struct sock *) chan->private; struct sock *sk_tun; struct l2tp_session *session; @@ -413,14 +411,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) sizeof(struct iphdr) + /* IP header */ uhlen + /* UDP header (if L2TP_ENCAPTYPE_UDP) */ session->hdr_len + /* L2TP header */ - sizeof(ppph); /* PPP header */ + 2; /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */ if (skb_cow_head(skb, headroom)) goto abort_put_sess_tun; /* Setup PPP header */ - __skb_push(skb, sizeof(ppph)); - skb->data[0] = ppph[0]; - skb->data[1] = ppph[1]; + __skb_push(skb, 2); + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; local_bh_disable(); l2tp_xmit_skb(session, skb, session->hdr_len); @@ -455,7 +453,7 @@ static void pppol2tp_session_close(struct l2tp_session *session) BUG_ON(session->magic != L2TP_SESSION_MAGIC); if (sock) { - inet_shutdown(sock, 2); + inet_shutdown(sock, SEND_SHUTDOWN); /* Don't let the session go away before our socket does */ l2tp_session_inc_refcount(session); } From patchwork Thu Apr 2 17:32:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 228261 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.1 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1499FC43331 for ; Thu, 2 Apr 2020 17:33:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D406A20737 for ; Thu, 2 Apr 2020 17:33:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848794; bh=Z2FGlzZ1BfBR2PNxxL1ZnwivTkdTJHsUzyKhfneWRO8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=DJvzcceo6sC5UY53FnYCpCt1IOQ3IOuVR/7q9dMCe0OuoGDodpMNIXcYGR1cHicyV cmMgKqWDEDsfr+gsTzLIBIbjX1TPTzDXsh5jT1DSs9xlSkanQMG5GrywesU4iinD4o 35qTFwsPQP/q1GmdlZWWRvrS0HM0MJlBiZ19eMoU= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390072AbgDBRdO (ORCPT ); Thu, 2 Apr 2020 13:33:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:33492 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390070AbgDBRdL (ORCPT ); Thu, 2 Apr 2020 13:33:11 -0400 Received: from localhost.localdomain (236.31.169.217.in-addr.arpa [217.169.31.236]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id D9A26212CC; Thu, 2 Apr 2020 17:33:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1585848791; bh=Z2FGlzZ1BfBR2PNxxL1ZnwivTkdTJHsUzyKhfneWRO8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jXDaXMXbUKy8Go3ZN9P3GW/UBSew3QYoHHJbOW5+1xAf1otoK62lUxDGhqSna1UjL R0bEzNuQ3q8BC6+Rh4Ale4ZwF/x4xIOo3eDs/bMOarNASTfKsPLTqlrP1w0P0Pn24+ P26AVibhr0KY7MuJtZf8gIu8MsB843cG3FtqHBdA= From: Will Deacon To: gregkh@linuxfoundation.org Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, g.nault@alphalink.fr, "David S . Miller" , Will Deacon Subject: [PATCH 8/8] l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall() Date: Thu, 2 Apr 2020 18:32:50 +0100 Message-Id: <20200402173250.7858-9-will@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200402173250.7858-1-will@kernel.org> References: <20200402173250.7858-1-will@kernel.org> MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Guillaume Nault commit b228a94066406b6c456321d69643b0d7ce11cfa6 upstream. 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: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Will Deacon --- net/l2tp/l2tp_core.c | 6 ++++++ net/l2tp/l2tp_core.h | 1 + 2 files changed, 7 insertions(+) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 03475b124841..2b8b5c57c7f0 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1351,6 +1351,9 @@ again: hlist_del_init(&session->hlist); + if (test_and_set_bit(0, &session->dead)) + goto again; + if (session->ref != NULL) (*session->ref)(session); @@ -1799,6 +1802,9 @@ EXPORT_SYMBOL_GPL(__l2tp_session_unhash); */ int l2tp_session_delete(struct l2tp_session *session) { + if (test_and_set_bit(0, &session->dead)) + return 0; + if (session->ref) (*session->ref)(session); __l2tp_session_unhash(session); diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 705fbc63ddc2..06323a12d62c 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -85,6 +85,7 @@ struct l2tp_session_cfg { struct l2tp_session { int magic; /* should be * L2TP_SESSION_MAGIC */ + long dead; struct l2tp_tunnel *tunnel; /* back pointer to tunnel * context */