[PATCH v2] xfrm6: fix slab-out-of-bounds write in xfrm6_input_addr()

nicholas
2026-04-01T04:56:56Z

From: Nicholas Carlini <nicholas@carlini.com>

The bounds check guarding sp->xvec[sp->len++] uses == where >= is
required. When sp->len has already reached XFRM_MAX_DEPTH via prior
ESP processing in xfrm_input(), the check (1 + 6 == 6) is false and
the write goes out of bounds into the adjacent skbuff_ext_cache slab
object.

An unprivileged local user can trigger this by entering a
user+network namespace, configuring six transport-mode ESP SAs plus
one MIP6 routing SA, and injecting an IPv6 packet with six ESP
layers followed by multiple Routing Header Type 2 extensions.

The check was correct (>) when the function was introduced, but
was changed to == during a refactor in 2007.

Fixes: 9473e1f631de ("[XFRM] MIPv6: Fix to input RO state correctly.")
Reported-by: Milad Nasr <srxzr@anthropic.com>
Signed-off-by: Nicholas Carlini <nicholas@carlini.com>
---
v1 -> v2: fix whitespace (tabs), rebase on ipsec tree (Steffen Klassert)

v1: https://lore.kernel.org/netdev/20260328163516.2111971-1-nicholas@carlini.com

net/ipv6/xfrm6_input.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 9005fc156a2..a958c08589d 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -246,7 +246,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
goto drop;
}

- if (1 + sp->len == XFRM_MAX_DEPTH) {
+ if (1 + sp->len >= XFRM_MAX_DEPTH) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
goto drop;
}
--
2.43.0