Commit dc61989e authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
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: default avatarJakub Kicinski <kuba@kernel.org>
parents f4eac70d f4c50a40
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
	struct iphdr *top_iph = ip_hdr(skb);
	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
	int ihl = ip_hdrlen(skb);
	int seqhi_len = 0;
	__be32 *seqhi;

	if (x->props.flags & XFRM_STATE_ESN)
		seqhi_len = sizeof(*seqhi);
	iph = AH_SKB_CB(skb)->tmp;
	icv = ah_tmp_icv(iph, ihl);
	seqhi = (__be32 *)((char *)iph + ihl);
	icv = ah_tmp_icv(seqhi, seqhi_len);
	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);

	top_iph->tos = iph->tos;
@@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
	int ihl = ip_hdrlen(skb);
	int ah_hlen = (ah->hdrlen + 2) << 2;
	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, ihl);
	seqhi = (__be32 *)((char *)work_iph + ihl);
	auth_data = ah_tmp_auth(seqhi, seqhi_len);
	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);

	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
+2 −1
Original line number Diff line number Diff line
@@ -873,7 +873,8 @@ static int esp_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++;

+2 −0
Original line number Diff line number Diff line
@@ -1233,6 +1233,8 @@ static int __ip_append_data(struct sock *sk,
			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;
+12 −2
Original line number Diff line number Diff line
@@ -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)
+2 −1
Original line number Diff line number Diff line
@@ -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++;

Loading