summaryrefslogtreecommitdiff
path: root/net/ipv6
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-05-06 16:49:41 -0700
committerJakub Kicinski <kuba@kernel.org>2026-05-06 16:49:42 -0700
commitdc61989e37726e0ff3d669e6ad94e62b97149329 (patch)
tree3c3f92340762c577852554e4a50960c598cc28f3 /net/ipv6
parentf4eac70d1e0c1fb6b3b4743ff12753c9fedb88e4 (diff)
parentf4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4 (diff)
Merge tag 'ipsec-2026-05-05' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2026-05-05 1. Fix an IPv6 encapsulation error path that leaked route references when UDPv6 ESP decapsulation resolved to an error route. From Yilin Zhu. 2. Fix AH with ESN on async crypto paths by accounting for the extra high-order sequence number when reconstructing the temporary authentication layout in the completion callbacks. From Michael Bomarito. 3. Fix XFRM output so it does not overwrite already-correct inner header pointers when a tunnel layer such as VXLAN has already saved them. The fix comes with new selftests. From Cosmin Ratiu. 4. Add the missing native payload size entry for XFRM_MSG_MAPPING in the compat translation path. From Ruijie Li. 5. Harden __xfrm_state_delete() against repeated or inconsistent unhashing of state list nodes by keying the removal on actual list membership and using delete-and-init helpers. From Michal Kosiorek. 6. Prevent ESP from decrypting shared splice-backed skb fragments in place by marking UDP splice frags as shared and forcing copy-on-write in ESP input when needed. From Kuan-Ting Chen. * tag 'ipsec-2026-05-05' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec: xfrm: esp: avoid in-place decrypt on shared skb frags xfrm: defensively unhash xfrm_state lists in __xfrm_state_delete xfrm: provide message size for XFRM_MSG_MAPPING xfrm: Don't clobber inner headers when already set tools/selftests: Add a VXLAN+IPsec traffic test tools/selftests: Use a sensible timeout value for iperf3 client xfrm: ah: account for ESN high bits in async callbacks ipv6: xfrm6: release dst on error in xfrm6_rcv_encap() ==================== Link: https://patch.msgid.link/20260505132326.1362733-1-steffen.klassert@secunet.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ah6.c14
-rw-r--r--net/ipv6/esp6.c3
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/xfrm6_protocol.c4
4 files changed, 19 insertions, 4 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index cb26beea4398..de1e68199a01 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
struct ipv6hdr *top_iph = ipv6_hdr(skb);
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
struct tmp_ext *iph_ext;
+ int seqhi_len = 0;
+ __be32 *seqhi;
extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
if (extlen)
extlen += sizeof(*iph_ext);
+ if (x->props.flags & XFRM_STATE_ESN)
+ seqhi_len = sizeof(*seqhi);
iph_base = AH_SKB_CB(skb)->tmp;
iph_ext = ah_tmp_ext(iph_base);
- icv = ah_tmp_icv(iph_ext, extlen);
+ seqhi = (__be32 *)((char *)iph_ext + extlen);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
@@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
int hdr_len = skb_network_header_len(skb);
int ah_hlen = ipv6_authlen(ah);
+ int seqhi_len = 0;
+ __be32 *seqhi;
if (err)
goto out;
+ if (x->props.flags & XFRM_STATE_ESN)
+ seqhi_len = sizeof(*seqhi);
work_iph = AH_SKB_CB(skb)->tmp;
auth_data = ah_tmp_auth(work_iph, hdr_len);
- icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
+ seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
if (err)
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 9f75313734f8..9c06c5a1419d 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -915,7 +915,8 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
nfrags = 1;
goto skip_cow;
- } else if (!skb_has_frag_list(skb)) {
+ } else if (!skb_has_frag_list(skb) &&
+ !skb_has_shared_frag(skb)) {
nfrags = skb_shinfo(skb)->nr_frags;
nfrags++;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 7e92909ab5be..1f2a33fbed6e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1794,6 +1794,8 @@ alloc_new_skb:
if (err < 0)
goto error;
copy = err;
+ if (!(flags & MSG_NO_SHARED_FRAGS))
+ skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG;
wmem_alloc_delta += copy;
} else if (!zc) {
int i = skb_shinfo(skb)->nr_frags;
diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c
index ea2f805d3b01..9b586fcec485 100644
--- a/net/ipv6/xfrm6_protocol.c
+++ b/net/ipv6/xfrm6_protocol.c
@@ -88,8 +88,10 @@ int xfrm6_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
dst = ip6_route_input_lookup(dev_net(skb->dev), skb->dev, &fl6,
skb, flags);
- if (dst->error)
+ if (dst->error) {
+ dst_release(dst);
goto drop;
+ }
skb_dst_set(skb, dst);
}