Skip to content

Commit dc61989

Browse files
committed
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>
2 parents f4eac70 + f4c50a4 commit dc61989

14 files changed

Lines changed: 270 additions & 20 deletions

File tree

net/ipv4/ah4.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
124124
struct iphdr *top_iph = ip_hdr(skb);
125125
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
126126
int ihl = ip_hdrlen(skb);
127+
int seqhi_len = 0;
128+
__be32 *seqhi;
127129

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

132137
top_iph->tos = iph->tos;
@@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
270275
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
271276
int ihl = ip_hdrlen(skb);
272277
int ah_hlen = (ah->hdrlen + 2) << 2;
278+
int seqhi_len = 0;
279+
__be32 *seqhi;
273280

274281
if (err)
275282
goto out;
276283

284+
if (x->props.flags & XFRM_STATE_ESN)
285+
seqhi_len = sizeof(*seqhi);
277286
work_iph = AH_SKB_CB(skb)->tmp;
278-
auth_data = ah_tmp_auth(work_iph, ihl);
287+
seqhi = (__be32 *)((char *)work_iph + ihl);
288+
auth_data = ah_tmp_auth(seqhi, seqhi_len);
279289
icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
280290

281291
err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;

net/ipv4/esp4.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
873873
nfrags = 1;
874874

875875
goto skip_cow;
876-
} else if (!skb_has_frag_list(skb)) {
876+
} else if (!skb_has_frag_list(skb) &&
877+
!skb_has_shared_frag(skb)) {
877878
nfrags = skb_shinfo(skb)->nr_frags;
878879
nfrags++;
879880

net/ipv4/ip_output.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,8 @@ static int __ip_append_data(struct sock *sk,
12331233
if (err < 0)
12341234
goto error;
12351235
copy = err;
1236+
if (!(flags & MSG_NO_SHARED_FRAGS))
1237+
skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG;
12361238
wmem_alloc_delta += copy;
12371239
} else if (!zc) {
12381240
int i = skb_shinfo(skb)->nr_frags;

net/ipv6/ah6.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
317317
struct ipv6hdr *top_iph = ipv6_hdr(skb);
318318
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
319319
struct tmp_ext *iph_ext;
320+
int seqhi_len = 0;
321+
__be32 *seqhi;
320322

321323
extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
322324
if (extlen)
323325
extlen += sizeof(*iph_ext);
324326

327+
if (x->props.flags & XFRM_STATE_ESN)
328+
seqhi_len = sizeof(*seqhi);
325329
iph_base = AH_SKB_CB(skb)->tmp;
326330
iph_ext = ah_tmp_ext(iph_base);
327-
icv = ah_tmp_icv(iph_ext, extlen);
331+
seqhi = (__be32 *)((char *)iph_ext + extlen);
332+
icv = ah_tmp_icv(seqhi, seqhi_len);
328333

329334
memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
330335
memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
@@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
471476
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
472477
int hdr_len = skb_network_header_len(skb);
473478
int ah_hlen = ipv6_authlen(ah);
479+
int seqhi_len = 0;
480+
__be32 *seqhi;
474481

475482
if (err)
476483
goto out;
477484

485+
if (x->props.flags & XFRM_STATE_ESN)
486+
seqhi_len = sizeof(*seqhi);
478487
work_iph = AH_SKB_CB(skb)->tmp;
479488
auth_data = ah_tmp_auth(work_iph, hdr_len);
480-
icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
489+
seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
490+
icv = ah_tmp_icv(seqhi, seqhi_len);
481491

482492
err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
483493
if (err)

net/ipv6/esp6.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,8 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
915915
nfrags = 1;
916916

917917
goto skip_cow;
918-
} else if (!skb_has_frag_list(skb)) {
918+
} else if (!skb_has_frag_list(skb) &&
919+
!skb_has_shared_frag(skb)) {
919920
nfrags = skb_shinfo(skb)->nr_frags;
920921
nfrags++;
921922

net/ipv6/ip6_output.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,8 @@ static int __ip6_append_data(struct sock *sk,
17941794
if (err < 0)
17951795
goto error;
17961796
copy = err;
1797+
if (!(flags & MSG_NO_SHARED_FRAGS))
1798+
skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG;
17971799
wmem_alloc_delta += copy;
17981800
} else if (!zc) {
17991801
int i = skb_shinfo(skb)->nr_frags;

net/ipv6/xfrm6_protocol.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,10 @@ int xfrm6_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
8888

8989
dst = ip6_route_input_lookup(dev_net(skb->dev), skb->dev, &fl6,
9090
skb, flags);
91-
if (dst->error)
91+
if (dst->error) {
92+
dst_release(dst);
9293
goto drop;
94+
}
9395
skb_dst_set(skb, dst);
9496
}
9597

net/xfrm/xfrm_output.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
6666
struct iphdr *iph = ip_hdr(skb);
6767
int ihl = iph->ihl * 4;
6868

69-
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
69+
if (!skb->inner_protocol)
70+
skb_set_inner_transport_header(skb,
71+
skb_transport_offset(skb));
7072

7173
skb_set_network_header(skb, -x->props.header_len);
7274
skb->mac_header = skb->network_header +
@@ -167,7 +169,9 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
167169
int hdr_len;
168170

169171
iph = ipv6_hdr(skb);
170-
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
172+
if (!skb->inner_protocol)
173+
skb_set_inner_transport_header(skb,
174+
skb_transport_offset(skb));
171175

172176
hdr_len = xfrm6_hdr_offset(x, skb, &prevhdr);
173177
if (hdr_len < 0)
@@ -276,8 +280,10 @@ static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
276280
struct iphdr *top_iph;
277281
int flags;
278282

279-
skb_set_inner_network_header(skb, skb_network_offset(skb));
280-
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
283+
if (!skb->inner_protocol) {
284+
skb_set_inner_network_header(skb, skb_network_offset(skb));
285+
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
286+
}
281287

282288
skb_set_network_header(skb, -x->props.header_len);
283289
skb->mac_header = skb->network_header +
@@ -321,8 +327,10 @@ static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
321327
struct ipv6hdr *top_iph;
322328
int dsfield;
323329

324-
skb_set_inner_network_header(skb, skb_network_offset(skb));
325-
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
330+
if (!skb->inner_protocol) {
331+
skb_set_inner_network_header(skb, skb_network_offset(skb));
332+
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
333+
}
326334

327335
skb_set_network_header(skb, -x->props.header_len);
328336
skb->mac_header = skb->network_header +

net/xfrm/xfrm_state.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -818,17 +818,17 @@ int __xfrm_state_delete(struct xfrm_state *x)
818818

819819
spin_lock(&net->xfrm.xfrm_state_lock);
820820
list_del(&x->km.all);
821-
hlist_del_rcu(&x->bydst);
822-
hlist_del_rcu(&x->bysrc);
823-
if (x->km.seq)
824-
hlist_del_rcu(&x->byseq);
821+
hlist_del_init_rcu(&x->bydst);
822+
hlist_del_init_rcu(&x->bysrc);
823+
if (!hlist_unhashed(&x->byseq))
824+
hlist_del_init_rcu(&x->byseq);
825825
if (!hlist_unhashed(&x->state_cache))
826826
hlist_del_rcu(&x->state_cache);
827827
if (!hlist_unhashed(&x->state_cache_input))
828828
hlist_del_rcu(&x->state_cache_input);
829829

830-
if (x->id.spi)
831-
hlist_del_rcu(&x->byspi);
830+
if (!hlist_unhashed(&x->byspi))
831+
hlist_del_init_rcu(&x->byspi);
832832
net->xfrm.state_num--;
833833
xfrm_nat_keepalive_state_updated(x);
834834
spin_unlock(&net->xfrm.xfrm_state_lock);

net/xfrm/xfrm_user.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3323,6 +3323,7 @@ const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
33233323
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),
33243324
[XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
33253325
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
3326+
[XFRM_MSG_MAPPING - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_mapping),
33263327
[XFRM_MSG_SETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
33273328
[XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
33283329
};

0 commit comments

Comments
 (0)