All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH ipsec v2] xfrm: ah6: validate routing header segments_left
@ 2026-07-23  9:35 Asim Viladi Oglu Manizada
  2026-07-28  8:00 ` Steffen Klassert
  0 siblings, 1 reply; 2+ messages in thread
From: Asim Viladi Oglu Manizada @ 2026-07-23  9:35 UTC (permalink / raw)
  To: netdev; +Cc: steffen.klassert, herbert, davem, edumazet, kuba, pabeni, horms

AH6 rearranges routing-header addresses before computing or verifying the
ICV. ipv6_rearrange_rthdr() assumes that segments_left is not larger than
the number of addresses described by the routing header's hdrlen field.

That assumption does not hold for raw IPv6 HDRINCL packets. A packet with
hdrlen equal to 2 describes one address, but can carry an arbitrary
segments_left value. With segments_left equal to 255, the function moves
its address pointer 4,064 bytes backwards and passes a 4,064-byte length to
memmove(), resulting in an out-of-bounds access.

Validate the invariant locally before modifying the routing header or
performing any address-pointer arithmetic, and propagate malformed-header
errors to the existing AH6 input and output error paths.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: avom-custom-harness:gpt-5.5-qwen3.6-mod-mix
Signed-off-by: Asim Viladi Oglu Manizada <manizada@pm.me>
---

v2:
  - Document the return value of ipv6_rearrange_rthdr().

v1: https://lore.kernel.org/netdev/20260721222824.2508529-1-manizada@pm.me/

 net/ipv6/ah6.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 76f7a2de9108..c96f7e0d0a48 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -232,26 +232,28 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des
  *	Rearrange the destination address in @iph and the addresses in @rthdr
  *	so that they appear in the order they will at the final destination.
  *	See Appendix A2 of RFC 2402 for details.
+ *
+ * Return: 0 on success, -EINVAL if segments_left exceeds the number of
+ * addresses described by hdrlen.
  */
-static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
+static int ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
 {
-	int segments, segments_left;
+	unsigned int segments, segments_left;
 	struct in6_addr *addrs;
 	struct in6_addr final_addr;
 
 	segments_left = rthdr->segments_left;
 	if (segments_left == 0)
-		return;
-	rthdr->segments_left = 0;
+		return 0;
 
-	/* The value of rthdr->hdrlen has been verified either by the system
-	 * call if it is locally generated, or by ipv6_rthdr_rcv() for incoming
-	 * packets.  So we can assume that it is even and that segments is
-	 * greater than or equal to segments_left.
-	 *
-	 * For the same reason we can assume that this option is of type 0.
+	/* Raw locally generated packets can reach AH6 without the invariant
+	 * required by the rt0-style address rearrangement below.
 	 */
 	segments = rthdr->hdrlen >> 1;
+	if (segments_left > segments)
+		return -EINVAL;
+
+	rthdr->segments_left = 0;
 
 	addrs = ((struct rt0_hdr *)rthdr)->addr;
 	final_addr = addrs[segments - 1];
@@ -261,6 +263,8 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
 
 	addrs[0] = iph->daddr;
 	iph->daddr = final_addr;
+
+	return 0;
 }
 
 static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
@@ -273,6 +277,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
 	} exthdr = { .iph = iph };
 	char *end = exthdr.raw + len;
 	int nexthdr = iph->nexthdr;
+	int err;
 
 	exthdr.iph++;
 
@@ -292,7 +297,9 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
 			break;
 
 		case NEXTHDR_ROUTING:
-			ipv6_rearrange_rthdr(iph, exthdr.rth);
+			err = ipv6_rearrange_rthdr(iph, exthdr.rth);
+			if (err)
+				return err;
 			break;
 
 		default:
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH ipsec v2] xfrm: ah6: validate routing header segments_left
  2026-07-23  9:35 [PATCH ipsec v2] xfrm: ah6: validate routing header segments_left Asim Viladi Oglu Manizada
@ 2026-07-28  8:00 ` Steffen Klassert
  0 siblings, 0 replies; 2+ messages in thread
From: Steffen Klassert @ 2026-07-28  8:00 UTC (permalink / raw)
  To: Asim Viladi Oglu Manizada
  Cc: netdev, herbert, davem, edumazet, kuba, pabeni, horms

On Thu, Jul 23, 2026 at 09:35:48AM +0000, Asim Viladi Oglu Manizada wrote:
> AH6 rearranges routing-header addresses before computing or verifying the
> ICV. ipv6_rearrange_rthdr() assumes that segments_left is not larger than
> the number of addresses described by the routing header's hdrlen field.
> 
> That assumption does not hold for raw IPv6 HDRINCL packets. A packet with
> hdrlen equal to 2 describes one address, but can carry an arbitrary
> segments_left value. With segments_left equal to 255, the function moves
> its address pointer 4,064 bytes backwards and passes a 4,064-byte length to
> memmove(), resulting in an out-of-bounds access.
> 
> Validate the invariant locally before modifying the routing header or
> performing any address-pointer arithmetic, and propagate malformed-header
> errors to the existing AH6 input and output error paths.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Assisted-by: avom-custom-harness:gpt-5.5-qwen3.6-mod-mix
> Signed-off-by: Asim Viladi Oglu Manizada <manizada@pm.me>

Applied, thanks a lot!

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-28  8:00 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23  9:35 [PATCH ipsec v2] xfrm: ah6: validate routing header segments_left Asim Viladi Oglu Manizada
2026-07-28  8:00 ` Steffen Klassert

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.