[PATCH net] ipv6: sr: restore network header before forwarding

Jun Yang <[email protected]>
Newsgroups gmane.linux.network,gmane.linux.kernel.stable
Message-ID <[email protected]>
From: Jun Yang <[email protected]>

ipv6_srh_rcv() runs with skb->data at the Segment Routing Header while
skb_network_header() points at the fixed IPv6 header. It restores the
data position by pushing sizeof(struct ipv6hdr) before dst_input(),
which assumes the SRH immediately follows the IPv6 header. If another
extension header precedes the SRH, skb_network_offset() remains negative
and neighbour output passes it to __skb_pull() as an unsigned length.

Keep skb->data at the current extension header while rerouting and
restore it by the exact network offset before each dst_input() handoff.
Remove the fixed pull from the loopback path. This matches
ipv6_rthdr_rcv() and handles any valid preceding extension header.

The trace was captured with kernel release
7.2.0-rc2-00023-g714b725feef4-dirty:

  BUG: KASAN: use-after-free in eth_header (net/ethernet/eth.c:86)
  Write of size 2 at addr ffff8881247b9a3e by task ipv6_srh_poc/9336
  Call Trace:
   eth_header (net/ethernet/eth.c:86)
   neigh_resolve_output (net/core/neighbour.c:1611)
   ip6_finish_output2 (net/ipv6/ip6_output.c:136)
   ip6_forward (net/ipv6/ip6_output.c:690)
   ipv6_rthdr_rcv (net/ipv6/exthdrs.c:832)

Fixes: 1ababeba4a21 ("ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)")
Cc: [email protected]
Reported-by: TencentOS Corvus AI <[email protected]>
Assisted-by: tencentos-corvus-ai:kimi-k3
Signed-off-by: Jun Yang <[email protected]>
---
A KASAN reproducer for this issue is available if requested.

 net/ipv6/exthdrs.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 9c677eb1d1a6..4c407520e9da 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -452,8 +452,6 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
 	hdr->segments_left--;
 	addr = hdr->segments + hdr->segments_left;
 
-	skb_push(skb, sizeof(struct ipv6hdr));
-
 	if (skb->ip_summed == CHECKSUM_COMPLETE)
 		seg6_update_csum(skb);
 
@@ -462,6 +460,7 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
 	ip6_route_input(skb);
 
 	if (skb_dst(skb)->error) {
+		skb_push(skb, -skb_network_offset(skb));
 		dst_input(skb);
 		return -1;
 	}
@@ -476,10 +475,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
 		}
 		ipv6_hdr(skb)->hop_limit--;
 
-		skb_pull(skb, sizeof(struct ipv6hdr));
 		goto looped_back;
 	}
 
+	skb_push(skb, -skb_network_offset(skb));
 	dst_input(skb);
 
 	return -1;
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.