From patchwork Sun Feb 9 19:38:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Iurman X-Patchwork-Id: 13967087 X-Patchwork-Delegate: kuba@kernel.org Received: from serv108.segi.ulg.ac.be (serv108.segi.ulg.ac.be [139.165.32.111]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC7EB1E0B73 for ; Sun, 9 Feb 2025 19:44:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=139.165.32.111 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739130294; cv=none; b=h8BXfXh7lv3f+707vgfmGlB+VeGjwx23KkYfinXlvS26k6WM88LW1cSn20BkhaOgTV/gOO5b9+Vh46tFhjPBLGgxBWViim0pHeJTOJRJGxbDdNH8Ir8S9vuRWWKPRBEm90MRvS66k2kNtDMDCmvueJn9eXfYht+pQJwQ58gRAXA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739130294; c=relaxed/simple; bh=nkcqBUFSpYOC8+1KW/7plIBhdHc1vBKyJSHKWDkHXHY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gKW2wgbcMuvmKcg0jeKeTI50elXU7Ow64gR52huYMfrBQUf8X3YgFthDVxigYnFnwQCmkO/8mZA2IT6o5fUWObdzIHXAnTAVlccR5CkIwP0m43KKW9UF4OEkbzo1E/mXRzMhA5Bfm7IQY6t755K0d8/ENuhB/fzxHc+/BYoI8NA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uliege.be; spf=pass smtp.mailfrom=uliege.be; dkim=pass (2048-bit key) header.d=uliege.be header.i=@uliege.be header.b=QgVz8BVc; arc=none smtp.client-ip=139.165.32.111 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uliege.be Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=uliege.be Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=uliege.be header.i=@uliege.be header.b="QgVz8BVc" Received: from ubuntu.home (lfbn-ncy-1-721-166.w86-216.abo.wanadoo.fr [86.216.56.166]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by serv108.segi.ulg.ac.be (Postfix) with ESMTPSA id 3C1F1200E2B5; Sun, 9 Feb 2025 20:39:35 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 serv108.segi.ulg.ac.be 3C1F1200E2B5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=uliege.be; s=ulg20190529; t=1739129975; bh=/XYTpL152c1a9qxMGc25FVY8Y43KP5x6gdKY70nEbRQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QgVz8BVcDZbPaK9ma0CCba3U+vewRqHo1fiE7Gmlm88FI3Xq6Q8koC9OiUGjAFYjA E2lcXJjdo6Ew8iAVnvlgR3ITp7OhWQO45jcu5QcEtdRTTj1rFw4WwRzUyIOgfRjorA lRX3VVwRH/GCAVP6E3KLNyoKp5w07U4FQQHpOzrrMre7TtJ13CSD4QyRTwhErpAnnx GrUzLgryNMfni2eElNU6HHUvnSDahPsyLouDJkC3nnmPu2cU0DGJ9Rpror2OpDDeK0 OXE10C3Mgz00/yOWjbNRwEwyQ062X5/1CWBp8Sbt+fg6tNI73duMaCItDnOCM8XGRx /nJSK1y9otAWA== From: Justin Iurman To: netdev@vger.kernel.org Cc: davem@davemloft.net, dsahern@kernel.org, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, justin.iurman@uliege.be, Alexander Aring , David Lebrun Subject: [PATCH net 1/3] net: ipv6: fix dst ref loops on input in lwtunnels Date: Sun, 9 Feb 2025 20:38:38 +0100 Message-Id: <20250209193840.20509-2-justin.iurman@uliege.be> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250209193840.20509-1-justin.iurman@uliege.be> References: <20250209193840.20509-1-justin.iurman@uliege.be> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org As a follow up to 92191dd10730 ("net: ipv6: fix dst ref loops in rpl, seg6 and ioam6 lwtunnels"), we also need a conditional dst cache on input for seg6_iptunnel and rpl_iptunnel to prevent dst ref loops (i.e., if the packet destination did not change, we may end up recording a reference to the lwtunnel in its own cache, and the lwtunnel state will never be freed). Fixes: a7a29f9c361f ("net: ipv6: add rpl sr tunnel") Fixes: af4a2209b134 ("ipv6: sr: use dst_cache in seg6_input") Signed-off-by: Justin Iurman Cc: Alexander Aring Cc: David Lebrun --- net/ipv6/rpl_iptunnel.c | 14 ++++++++++++-- net/ipv6/seg6_iptunnel.c | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c index 0ac4283acdf2..c26bf284459f 100644 --- a/net/ipv6/rpl_iptunnel.c +++ b/net/ipv6/rpl_iptunnel.c @@ -262,10 +262,18 @@ static int rpl_input(struct sk_buff *skb) { struct dst_entry *orig_dst = skb_dst(skb); struct dst_entry *dst = NULL; + struct lwtunnel_state *lwtst; struct rpl_lwt *rlwt; int err; - rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate); + /* Get the address of lwtstate now, because "orig_dst" may not be there + * anymore after a call to skb_dst_drop(). Note that ip6_route_input() + * also calls skb_dst_drop(). Below, we compare the address of lwtstate + * to detect loops. + */ + lwtst = orig_dst->lwtstate; + + rlwt = rpl_lwt_lwtunnel(lwtst); local_bh_disable(); dst = dst_cache_get(&rlwt->cache); @@ -280,7 +288,9 @@ static int rpl_input(struct sk_buff *skb) if (!dst) { ip6_route_input(skb); dst = skb_dst(skb); - if (!dst->error) { + + /* cache only if we don't create a dst reference loop */ + if (!dst->error && lwtst != dst->lwtstate) { local_bh_disable(); dst_cache_set_ip6(&rlwt->cache, dst, &ipv6_hdr(skb)->saddr); diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 33833b2064c0..6045e850b4bf 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -472,10 +472,18 @@ static int seg6_input_core(struct net *net, struct sock *sk, { struct dst_entry *orig_dst = skb_dst(skb); struct dst_entry *dst = NULL; + struct lwtunnel_state *lwtst; struct seg6_lwt *slwt; int err; - slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); + /* Get the address of lwtstate now, because "orig_dst" may not be there + * anymore after a call to skb_dst_drop(). Note that ip6_route_input() + * also calls skb_dst_drop(). Below, we compare the address of lwtstate + * to detect loops. + */ + lwtst = orig_dst->lwtstate; + + slwt = seg6_lwt_lwtunnel(lwtst); local_bh_disable(); dst = dst_cache_get(&slwt->cache); @@ -490,7 +498,9 @@ static int seg6_input_core(struct net *net, struct sock *sk, if (!dst) { ip6_route_input(skb); dst = skb_dst(skb); - if (!dst->error) { + + /* cache only if we don't create a dst reference loop */ + if (!dst->error && lwtst != dst->lwtstate) { local_bh_disable(); dst_cache_set_ip6(&slwt->cache, dst, &ipv6_hdr(skb)->saddr); From patchwork Sun Feb 9 19:38:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Iurman X-Patchwork-Id: 13967088 X-Patchwork-Delegate: kuba@kernel.org Received: from serv108.segi.ulg.ac.be (serv108.segi.ulg.ac.be [139.165.32.111]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC72D1922D4 for ; Sun, 9 Feb 2025 19:44:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=139.165.32.111 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739130294; cv=none; b=gRvnmR4hyo6uI1InhMgvNcP0wvWyFfyM18mZC55v+9LCQh15bkKKrYSkr7+/MJOx0Rt6hWJtMhuwao8it0AIWoj3sUF7lImWyoLis3ME+mDcv3wbuYC3xlRs/Gj878BsTU9E4G7+fq6Wn9LPolfPFzTC2NbLO/XdU6sKObGoMxs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739130294; c=relaxed/simple; bh=E3LEoMRUMOWBDckm9WJCQRAd5S81W5whDtPuflfSrVc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=otb1DZtGOmZ2g2uWr5D6O90IKnp8nhO9bewRT8m8ReQwsoDHa8oqYbmFoZnE8KIn8OAG2ZOmBAe83VxLWciQRXbR8pE4N8nu7i6o4mVD2FNPqguKLlAONe0CM2XnBjE+PR+oTJ6WAz3cPmUFeF++29LeLOe8Vht3gVcOCn5Yl3g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uliege.be; spf=pass smtp.mailfrom=uliege.be; dkim=pass (2048-bit key) header.d=uliege.be header.i=@uliege.be header.b=yj4DgFkH; arc=none smtp.client-ip=139.165.32.111 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uliege.be Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=uliege.be Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=uliege.be header.i=@uliege.be header.b="yj4DgFkH" Received: from ubuntu.home (lfbn-ncy-1-721-166.w86-216.abo.wanadoo.fr [86.216.56.166]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by serv108.segi.ulg.ac.be (Postfix) with ESMTPSA id A01C2200E2B6; Sun, 9 Feb 2025 20:39:35 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 serv108.segi.ulg.ac.be A01C2200E2B6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=uliege.be; s=ulg20190529; t=1739129975; bh=zo1j2QF7d/fcfR/IWYHBQm4HXrB3wgrskVqsm3RwpHM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=yj4DgFkH/ogimnyEa2Bj91DMiF22zIDpFhGtCc86PW4uJpkPRaZwOfeqFgYY5oLf8 tTKljEeElZMYqih4623zeiRkfsyhRppjqYejxcCQstBVOVLS/KccsQSkD9xbfQ/7wq XTMy63Ft4N9l5NkuGxeV+FLETrDzYbLaxpU6sZC46DUBMVR6HNFvrNJbsimctQRRK6 v0kQhWrotlqIp/FbUZ0cDl+tdMzzVgrh/W/PLHJ1WoFgqRqr9MsK5FlofXVkAMrOUl e3uDV9R4x4RctoO6htoMUjjyy5IM5atKRdPvhsLWQj9gyW1yqNWmyOChYK5SlgHhiB POrdgXDJBTukA== From: Justin Iurman To: netdev@vger.kernel.org Cc: davem@davemloft.net, dsahern@kernel.org, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, justin.iurman@uliege.be, Alexander Aring , David Lebrun Subject: [PATCH net 2/3] net: ipv6: fix lwtunnel loops in ioam6, rpl and seg6 Date: Sun, 9 Feb 2025 20:38:39 +0100 Message-Id: <20250209193840.20509-3-justin.iurman@uliege.be> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250209193840.20509-1-justin.iurman@uliege.be> References: <20250209193840.20509-1-justin.iurman@uliege.be> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org When the destination is the same post-transformation, we enter a lwtunnel loop. This is true for ioam6_iptunnel, rpl_iptunnel, and seg6_iptunnel, in both input() and output() handlers respectively, where either dst_input() or dst_output() is called at the end. It happens for instance with the ioam6 inline mode, but can also happen for any of them as long as the post-transformation destination still matches the fib entry. Note that ioam6_iptunnel was already comparing the old and new destination address to prevent the loop, but it is not enough (e.g., other addresses can still match the same subnet). Here is an example for rpl_input(): dump_stack_lvl+0x60/0x80 rpl_input+0x9d/0x320 lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 [...] lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 lwtunnel_input+0x64/0xa0 ip6_sublist_rcv_finish+0x85/0x90 ip6_sublist_rcv+0x236/0x2f0 ... until rpl_do_srh() fails, which means skb_cow_head() failed. This patch prevents that kind of loop by redirecting to the origin input() or output() when the destination is the same post-transformation. Fixes: 8cb3bf8bff3c ("ipv6: ioam: Add support for the ip6ip6 encapsulation") Fixes: a7a29f9c361f ("net: ipv6: add rpl sr tunnel") Fixes: 6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels") Signed-off-by: Justin Iurman Cc: Alexander Aring Cc: David Lebrun --- net/ipv6/ioam6_iptunnel.c | 6 ++---- net/ipv6/rpl_iptunnel.c | 10 ++++++++++ net/ipv6/seg6_iptunnel.c | 33 +++++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/net/ipv6/ioam6_iptunnel.c b/net/ipv6/ioam6_iptunnel.c index 2c383c12a431..6c61b306f2e9 100644 --- a/net/ipv6/ioam6_iptunnel.c +++ b/net/ipv6/ioam6_iptunnel.c @@ -337,7 +337,6 @@ static int ioam6_do_encap(struct net *net, struct sk_buff *skb, static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb), *cache_dst = NULL; - struct in6_addr orig_daddr; struct ioam6_lwt *ilwt; int err = -EINVAL; u32 pkt_cnt; @@ -352,8 +351,6 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb) if (pkt_cnt % ilwt->freq.n >= ilwt->freq.k) goto out; - orig_daddr = ipv6_hdr(skb)->daddr; - local_bh_disable(); cache_dst = dst_cache_get(&ilwt->cache); local_bh_enable(); @@ -422,7 +419,8 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb) goto drop; } - if (!ipv6_addr_equal(&orig_daddr, &ipv6_hdr(skb)->daddr)) { + /* avoid a lwtunnel_input() loop when dst_entry is the same */ + if (dst->lwtstate != cache_dst->lwtstate) { skb_dst_drop(skb); skb_dst_set(skb, cache_dst); return dst_output(net, sk, skb); diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c index c26bf284459f..dc004e9aa649 100644 --- a/net/ipv6/rpl_iptunnel.c +++ b/net/ipv6/rpl_iptunnel.c @@ -247,6 +247,12 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb) goto drop; } + /* avoid a lwtunnel_output() loop when dst_entry is the same */ + if (orig_dst->lwtstate == dst->lwtstate) { + dst_release(dst); + return orig_dst->lwtstate->orig_output(net, sk, skb); + } + skb_dst_drop(skb); skb_dst_set(skb, dst); @@ -305,6 +311,10 @@ static int rpl_input(struct sk_buff *skb) skb_dst_set(skb, dst); } + /* avoid a lwtunnel_input() loop when dst_entry is the same */ + if (lwtst == dst->lwtstate) + return dst->lwtstate->orig_input(skb); + return dst_input(skb); drop: diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 6045e850b4bf..9fce6b2dbd54 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -467,9 +467,16 @@ static int seg6_input_finish(struct net *net, struct sock *sk, return dst_input(skb); } +static int seg6_input_redirect_finish(struct net *net, struct sock *sk, + struct sk_buff *skb) +{ + return skb_dst(skb)->lwtstate->orig_input(skb); +} + static int seg6_input_core(struct net *net, struct sock *sk, struct sk_buff *skb) { + int (*input_func)(struct net *, struct sock *, struct sk_buff *); struct dst_entry *orig_dst = skb_dst(skb); struct dst_entry *dst = NULL; struct lwtunnel_state *lwtst; @@ -515,12 +522,18 @@ static int seg6_input_core(struct net *net, struct sock *sk, skb_dst_set(skb, dst); } + /* avoid a lwtunnel_input() loop when dst_entry is the same */ + if (lwtst == dst->lwtstate) + input_func = seg6_input_redirect_finish; + else + input_func = seg6_input_finish; + if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled)) return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, dev_net(skb->dev), NULL, skb, NULL, - skb_dst(skb)->dev, seg6_input_finish); + skb_dst(skb)->dev, input_func); - return seg6_input_finish(dev_net(skb->dev), NULL, skb); + return input_func(dev_net(skb->dev), NULL, skb); drop: kfree_skb(skb); return err; @@ -554,6 +567,7 @@ static int seg6_input(struct sk_buff *skb) static int seg6_output_core(struct net *net, struct sock *sk, struct sk_buff *skb) { + int (*output_func)(struct net *, struct sock *, struct sk_buff *); struct dst_entry *orig_dst = skb_dst(skb); struct dst_entry *dst = NULL; struct seg6_lwt *slwt; @@ -598,14 +612,21 @@ static int seg6_output_core(struct net *net, struct sock *sk, goto drop; } - skb_dst_drop(skb); - skb_dst_set(skb, dst); + /* avoid a lwtunnel_output() loop when dst_entry is the same */ + if (orig_dst->lwtstate == dst->lwtstate) { + dst_release(dst); + output_func = orig_dst->lwtstate->orig_output; + } else { + skb_dst_drop(skb); + skb_dst_set(skb, dst); + output_func = dst_output; + } if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled)) return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb, - NULL, skb_dst(skb)->dev, dst_output); + NULL, skb_dst(skb)->dev, output_func); - return dst_output(net, sk, skb); + return output_func(net, sk, skb); drop: dst_release(dst); kfree_skb(skb); From patchwork Sun Feb 9 19:38:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Justin Iurman X-Patchwork-Id: 13967089 X-Patchwork-Delegate: kuba@kernel.org Received: from serv108.segi.ulg.ac.be (serv108.segi.ulg.ac.be [139.165.32.111]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D66E81E231A for ; Sun, 9 Feb 2025 19:44:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=139.165.32.111 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739130295; cv=none; b=ka2QVTUmMqXS6+yjoNgipZvWKhX1uNXZ75Wq8eil3XflIE/X+AYGXbC2g4iYy1iaunDAf/5fyGWx2aXtZPXkYfK+svtQ8yGNwdbf8yWg/xsm70mgC80yu/r8Ms8Lmq5kZx93DNaDRLnR4FRh6k5O9otu5i0mUSZOjwOiHRZC8q8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739130295; c=relaxed/simple; bh=sa7e51/w+DCZXb0mLrZPoVCOgp02JE689pS4IVsWYJU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=i8V6bZlOMIEdp9fSb8kia5xKGQsOyi12L35hEZwSPdJ73UF/nUu2JQgt5bfUN5NRWA4aUIrJcsY7PAlAL2JE7bW32z6skKiuH85vVLooOrAEIUUpoP64iqvlnUuqy7Qys9pNsjAa98hqw6W+xLrPuUp6/iO0cGYnG0oLP7vnKFc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uliege.be; spf=pass smtp.mailfrom=uliege.be; dkim=pass (2048-bit key) header.d=uliege.be header.i=@uliege.be header.b=B5plJkhb; arc=none smtp.client-ip=139.165.32.111 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=uliege.be Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=uliege.be Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=uliege.be header.i=@uliege.be header.b="B5plJkhb" Received: from ubuntu.home (lfbn-ncy-1-721-166.w86-216.abo.wanadoo.fr [86.216.56.166]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by serv108.segi.ulg.ac.be (Postfix) with ESMTPSA id 0E16A200E2B8; Sun, 9 Feb 2025 20:39:36 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 serv108.segi.ulg.ac.be 0E16A200E2B8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=uliege.be; s=ulg20190529; t=1739129976; bh=BcQoNa2dVJYJXIinBzkuvymO9wfzsaRF1eTbnNsCWIY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=B5plJkhbJcXkEI7erJQg4h8pKY2mgyzIlL4nbREv1WpCaBDkDQqT82qPJoujhir43 6JDUU57P3SwGKwTrWyW/WoHxdRxDA0dMWesxHBiwrvNTXyIVlsmwBl0vFYxlvZYl3M w12ZmUDKQ0IUKCOPUU062vQBfBmfDNp9jAZt0nEhbSWSlYl4ofqgjhrk+wNMHuiay0 e6MEtO3V+hUQLiqw+Vldjz33jCcY6OQWWnvOzKHR+PeWV/ObXIhJ84eCNmpLt67B2/ hLNThabnT2+lrxUsFoP7dqBcZsOQo2//hZ4wiD0i6YXVcqg4Gdep492AaWU9CiTpU4 2sJRmcvELgTYg== From: Justin Iurman To: netdev@vger.kernel.org Cc: davem@davemloft.net, dsahern@kernel.org, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, justin.iurman@uliege.be Subject: [PATCH net 3/3] net: ipv6: fix consecutive input and output transformation in lwtunnels Date: Sun, 9 Feb 2025 20:38:40 +0100 Message-Id: <20250209193840.20509-4-justin.iurman@uliege.be> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250209193840.20509-1-justin.iurman@uliege.be> References: <20250209193840.20509-1-justin.iurman@uliege.be> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Some lwtunnel users implement both lwt input and output handlers. If the post-transformation destination on input is the same, the output handler is also called and the same transformation is applied (again). Here are the users: ila, bpf, rpl, seg6. The first one (ila) does not need this fix, since it already implements a check to avoid such a duplicate. The second (bpf) may need this fix, but I'm not familiar with that code path and will keep it out of this patch. The two others (rpl and seg6) do need this patch. Due to the ila implementation (as an example), we cannot fix the issue in lwtunnel_input() and lwtunnel_output() directly. Instead, we need to do it on a case-by-case basis. This patch fixes both rpl_iptunnel and seg6_iptunnel users. The fix re-uses skb->redirected in input handlers to notify corresponding output handlers that the transformation was already applied and to skip it. The "redirected" field seems safe to be used here. Fixes a7a29f9c361f ("net: ipv6: add rpl sr tunnel") Fixes 6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels") Signed-off-by: Justin Iurman --- net/ipv6/rpl_iptunnel.c | 14 ++++++++++++-- net/ipv6/seg6_iptunnel.c | 16 +++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c index dc004e9aa649..2dc1f2297e39 100644 --- a/net/ipv6/rpl_iptunnel.c +++ b/net/ipv6/rpl_iptunnel.c @@ -208,6 +208,12 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb) struct rpl_lwt *rlwt; int err; + /* Don't re-apply the transformation when rpl_input() already did it */ + if (skb_is_redirected(skb)) { + skb_reset_redirect(skb); + return orig_dst->lwtstate->orig_output(net, sk, skb); + } + rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate); local_bh_disable(); @@ -311,9 +317,13 @@ static int rpl_input(struct sk_buff *skb) skb_dst_set(skb, dst); } - /* avoid a lwtunnel_input() loop when dst_entry is the same */ - if (lwtst == dst->lwtstate) + /* avoid a lwtunnel_input() loop when dst_entry is the same, and make + * sure rpl_output() does not apply the transformation one more time + */ + if (lwtst == dst->lwtstate) { + skb_set_redirected_noclear(skb, true); return dst->lwtstate->orig_input(skb); + } return dst_input(skb); diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 9fce6b2dbd54..539c79903ffa 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -522,11 +522,15 @@ static int seg6_input_core(struct net *net, struct sock *sk, skb_dst_set(skb, dst); } - /* avoid a lwtunnel_input() loop when dst_entry is the same */ - if (lwtst == dst->lwtstate) + /* avoid a lwtunnel_input() loop when dst_entry is the same, and make + * sure seg6_output() does not apply the transformation one more time + */ + if (lwtst == dst->lwtstate) { + skb_set_redirected_noclear(skb, true); input_func = seg6_input_redirect_finish; - else + } else { input_func = seg6_input_finish; + } if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled)) return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, @@ -573,6 +577,12 @@ static int seg6_output_core(struct net *net, struct sock *sk, struct seg6_lwt *slwt; int err; + /* Don't re-apply the transformation when seg6_input() already did it */ + if (skb_is_redirected(skb)) { + skb_reset_redirect(skb); + return orig_dst->lwtstate->orig_output(net, sk, skb); + } + slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); local_bh_disable();