[PATCH net v2 2/2] xfrm: fix selector matching for IPv6 atomic fragments

From: Jérémy Jean

Date: Tue Nov 03 2026 - 18:01:32 EST


Commit 7e3a42a12c4b ("xfrm6: handling fragment") stopped decoding IPv6
selector fields after a Fragment header. That is correct for real
fragments because later fragments do not carry those fields, yet an
atomic fragment is different because it contains the complete datagram,
which allows XFRM to read its ports, ICMPv6 type and code, and GRE key.
Leaving those fields zero lets a plaintext atomic fragment miss a policy
that matches on one of them.

Leave ports, ICMPv6 type and code, and GRE key unset for real
fragments. For atomic fragments, treat the packet as a complete datagram
during IPv6 session decoding and recover the ports at the transport
offset found by the flow dissector.

Fixes: 7e3a42a12c4b ("xfrm6: handling fragment")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Jérémy Jean <Jeremy.Jean@xxxxxxxxxxxxxxxxx>
---
net/xfrm/xfrm_policy.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index bda5100c9fdbf..24470dbd82639 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3526,9 +3526,25 @@ int __xfrm_decode_session(struct net *net, struct sk_buff *skb, struct flowi *fl
decode_session4(&flkeys, fl, reverse);
break;
#if IS_ENABLED(CONFIG_IPV6)
- case AF_INET6:
+ case AF_INET6: {
+ struct frag_hdr _fh, *fh;
+ unsigned int offset = 0;
+
+ if ((flkeys.control.flags & FLOW_DIS_IS_FRAGMENT) &&
+ ipv6_find_hdr(skb, &offset, NEXTHDR_FRAGMENT,
+ NULL, NULL) == NEXTHDR_FRAGMENT) {
+ fh = skb_header_pointer(skb, offset, sizeof(_fh), &_fh);
+ if (fh && !(fh->frag_off & htons(IP6_OFFSET | IP6_MF))) {
+ flkeys.control.flags &= ~FLOW_DIS_IS_FRAGMENT;
+ flkeys.ports.ports = skb_flow_get_ports(skb,
+ flkeys.control.thoff,
+ flkeys.basic.ip_proto,
+ NULL, 0);
+ }
+ }
decode_session6(&flkeys, fl, reverse);
break;
+ }
#endif
default:
return -EAFNOSUPPORT;
--
2.47.3