lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250311141238.19862-5-justin.iurman@uliege.be>
Date: Tue, 11 Mar 2025 15:12:35 +0100
From: Justin Iurman <justin.iurman@...ege.be>
To: netdev@...r.kernel.org
Cc: davem@...emloft.net,
	dsahern@...nel.org,
	edumazet@...gle.com,
	kuba@...nel.org,
	pabeni@...hat.com,
	horms@...nel.org,
	justin.iurman@...ege.be,
	David Lebrun <dlebrun@...gle.com>,
	Andrea Mayer <andrea.mayer@...roma2.it>,
	Stefano Salsano <stefano.salsano@...roma2.it>,
	Ahmed Abdelsalam <ahabdels.dev@...il.com>,
	Mathieu Xhonneux <m.xhonneux@...il.com>,
	Ido Schimmel <idosch@...dia.com>
Subject: [PATCH net 4/7] net: ipv6: seg6_local: fix lwtunnel_input() loop

Fix the lwtunnel_input() reentry loop in seg6_local when the destination
is the same after transformation. Some configurations leading to this
may be considered pathological, but we don't want the kernel to crash
even for these ones. This patch DOES NOT solve the crash reported in
[1], it'll be addressed separately as it's a different issue.

  [1] https://lore.kernel.org/netdev/2bc9e2079e864a9290561894d2a602d6@akamai.com/

Fixes: 140f04c33bbc ("ipv6: sr: implement several seg6local actions")
Fixes: 891ef8dd2a8d ("ipv6: sr: implement additional seg6local actions")
Fixes: 004d4b274e2a ("ipv6: sr: Add seg6local action End.BPF")
Fixes: 664d6f86868b ("seg6: add support for the SRv6 End.DT4 behavior")
Cc: David Lebrun <dlebrun@...gle.com>
Cc: Andrea Mayer <andrea.mayer@...roma2.it>
Cc: Stefano Salsano <stefano.salsano@...roma2.it>
Cc: Ahmed Abdelsalam <ahabdels.dev@...il.com>
Cc: Mathieu Xhonneux <m.xhonneux@...il.com>
Cc: Ido Schimmel <idosch@...dia.com>
Signed-off-by: Justin Iurman <justin.iurman@...ege.be>
---
 net/ipv6/seg6_local.c | 85 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 81 insertions(+), 4 deletions(-)

diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index ac1dbd492c22..15485010cdfb 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -378,8 +378,16 @@ static void seg6_next_csid_advance_arg(struct in6_addr *addr,
 static int input_action_end_finish(struct sk_buff *skb,
 				   struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
+
 	seg6_lookup_nexthop(skb, NULL, 0);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 }
 
@@ -418,8 +426,16 @@ static int end_next_csid_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 static int input_action_end_x_finish(struct sk_buff *skb,
 				     struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
+
 	seg6_lookup_nexthop(skb, &slwt->nh6, 0);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 }
 
@@ -825,6 +841,7 @@ static int input_action_end_x(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 
 static int input_action_end_t(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
 	struct ipv6_sr_hdr *srh;
 
 	srh = get_and_validate_srh(skb);
@@ -835,6 +852,12 @@ static int input_action_end_t(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 
 	seg6_lookup_nexthop(skb, NULL, slwt->table);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 
 drop:
@@ -902,11 +925,11 @@ static int input_action_end_dx2(struct sk_buff *skb,
 static int input_action_end_dx6_finish(struct net *net, struct sock *sk,
 				       struct sk_buff *skb)
 {
-	struct dst_entry *orig_dst = skb_dst(skb);
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
 	struct in6_addr *nhaddr = NULL;
 	struct seg6_local_lwt *slwt;
 
-	slwt = seg6_local_lwtunnel(orig_dst->lwtstate);
+	slwt = seg6_local_lwtunnel(lwtst);
 
 	/* The inner packet is not associated to any local interface,
 	 * so we do not call netif_rx().
@@ -919,6 +942,12 @@ static int input_action_end_dx6_finish(struct net *net, struct sock *sk,
 
 	seg6_lookup_nexthop(skb, nhaddr, 0);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 }
 
@@ -953,13 +982,13 @@ static int input_action_end_dx6(struct sk_buff *skb,
 static int input_action_end_dx4_finish(struct net *net, struct sock *sk,
 				       struct sk_buff *skb)
 {
-	struct dst_entry *orig_dst = skb_dst(skb);
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
 	enum skb_drop_reason reason;
 	struct seg6_local_lwt *slwt;
 	struct iphdr *iph;
 	__be32 nhaddr;
 
-	slwt = seg6_local_lwtunnel(orig_dst->lwtstate);
+	slwt = seg6_local_lwtunnel(lwtst);
 
 	iph = ip_hdr(skb);
 
@@ -973,6 +1002,12 @@ static int input_action_end_dx4_finish(struct net *net, struct sock *sk,
 		return -EINVAL;
 	}
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 }
 
@@ -1174,6 +1209,7 @@ static struct sk_buff *end_dt_vrf_core(struct sk_buff *skb,
 static int input_action_end_dt4(struct sk_buff *skb,
 				struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
 	enum skb_drop_reason reason;
 	struct iphdr *iph;
 
@@ -1197,6 +1233,12 @@ static int input_action_end_dt4(struct sk_buff *skb,
 	if (unlikely(reason))
 		goto drop;
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 
 drop:
@@ -1255,6 +1297,8 @@ static int seg6_end_dt6_build(struct seg6_local_lwt *slwt, const void *cfg,
 static int input_action_end_dt6(struct sk_buff *skb,
 				struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
+
 	if (!decap_and_validate(skb, IPPROTO_IPV6))
 		goto drop;
 
@@ -1279,6 +1323,12 @@ static int input_action_end_dt6(struct sk_buff *skb,
 	 */
 	seg6_lookup_any_nexthop(skb, NULL, 0, true);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 
 legacy_mode:
@@ -1287,6 +1337,12 @@ static int input_action_end_dt6(struct sk_buff *skb,
 
 	seg6_lookup_any_nexthop(skb, NULL, slwt->table, true);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 
 drop:
@@ -1327,6 +1383,7 @@ static int input_action_end_dt46(struct sk_buff *skb,
 /* push an SRH on top of the current one */
 static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
 	struct ipv6_sr_hdr *srh;
 	int err = -EINVAL;
 
@@ -1342,6 +1399,12 @@ static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 
 	seg6_lookup_nexthop(skb, NULL, 0);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 
 drop:
@@ -1353,6 +1416,7 @@ static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 static int input_action_end_b6_encap(struct sk_buff *skb,
 				     struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
 	struct ipv6_sr_hdr *srh;
 	int err = -EINVAL;
 
@@ -1373,6 +1437,12 @@ static int input_action_end_b6_encap(struct sk_buff *skb,
 
 	seg6_lookup_nexthop(skb, NULL, 0);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 
 drop:
@@ -1411,6 +1481,7 @@ bool seg6_bpf_has_valid_srh(struct sk_buff *skb)
 static int input_action_end_bpf(struct sk_buff *skb,
 				struct seg6_local_lwt *slwt)
 {
+	struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate;
 	struct seg6_bpf_srh_state *srh_state;
 	struct ipv6_sr_hdr *srh;
 	int ret;
@@ -1457,6 +1528,12 @@ static int input_action_end_bpf(struct sk_buff *skb,
 	if (ret != BPF_REDIRECT)
 		seg6_lookup_nexthop(skb, NULL, 0);
 
+	/* avoid lwtunnel_input() reentry loop when destination is the same
+	 * after transformation
+	 */
+	if (lwtst == skb_dst(skb)->lwtstate)
+		return lwtst->orig_input(skb);
+
 	return dst_input(skb);
 
 drop:
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ