Skip to content

Commit 0c69a46

Browse files
Christian Langrockgregkh
authored andcommitted
xfrm: replay: Fix ESN wrap around for GSO
[ Upstream commit 4b549cc ] When using GSO it can happen that the wrong seq_hi is used for the last packets before the wrap around. This can lead to double usage of a sequence number. To avoid this, we should serialize this last GSO packet. Fixes: d7dbefc ("xfrm: Add xfrm_replay_overflow functions for offloading") Co-developed-by: Steffen Klassert <[email protected]> Signed-off-by: Christian Langrock <[email protected]> Signed-off-by: Steffen Klassert <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent ecc6ce4 commit 0c69a46

File tree

4 files changed

+21
-2
lines changed

4 files changed

+21
-2
lines changed

net/ipv4/esp4_offload.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
311311
xo->seq.low += skb_shinfo(skb)->gso_segs;
312312
}
313313

314+
if (xo->seq.low < seq)
315+
xo->seq.hi++;
316+
314317
esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32));
315318

316319
ip_hdr(skb)->tot_len = htons(skb->len);

net/ipv6/esp6_offload.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features
343343
xo->seq.low += skb_shinfo(skb)->gso_segs;
344344
}
345345

346+
if (xo->seq.low < seq)
347+
xo->seq.hi++;
348+
346349
esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
347350

348351
len = skb->len - sizeof(struct ipv6hdr);

net/xfrm/xfrm_device.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ static void xfrm_outer_mode_prep(struct xfrm_state *x, struct sk_buff *skb)
9797
}
9898
}
9999

100+
static inline bool xmit_xfrm_check_overflow(struct sk_buff *skb)
101+
{
102+
struct xfrm_offload *xo = xfrm_offload(skb);
103+
__u32 seq = xo->seq.low;
104+
105+
seq += skb_shinfo(skb)->gso_segs;
106+
if (unlikely(seq < xo->seq.low))
107+
return true;
108+
109+
return false;
110+
}
111+
100112
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again)
101113
{
102114
int err;
@@ -134,7 +146,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
134146
return skb;
135147
}
136148

137-
if (skb_is_gso(skb) && unlikely(x->xso.dev != dev)) {
149+
if (skb_is_gso(skb) && (unlikely(x->xso.dev != dev) ||
150+
unlikely(xmit_xfrm_check_overflow(skb)))) {
138151
struct sk_buff *segs;
139152

140153
/* Packet got rerouted, fixup features and segment it. */

net/xfrm/xfrm_replay.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff
714714
oseq += skb_shinfo(skb)->gso_segs;
715715
}
716716

717-
if (unlikely(oseq < replay_esn->oseq)) {
717+
if (unlikely(xo->seq.low < replay_esn->oseq)) {
718718
XFRM_SKB_CB(skb)->seq.output.hi = ++oseq_hi;
719719
xo->seq.hi = oseq_hi;
720720
replay_esn->oseq_hi = oseq_hi;

0 commit comments

Comments
 (0)