mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
xfrm: replay: Fix ESN wrap around for GSO
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: d7dbefc45c
("xfrm: Add xfrm_replay_overflow functions for offloading")
Co-developed-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Christian Langrock <christian.langrock@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
parent
d83f7040e1
commit
4b549ccce9
4 changed files with 21 additions and 2 deletions
|
@ -314,6 +314,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
|
||||||
xo->seq.low += skb_shinfo(skb)->gso_segs;
|
xo->seq.low += skb_shinfo(skb)->gso_segs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xo->seq.low < seq)
|
||||||
|
xo->seq.hi++;
|
||||||
|
|
||||||
esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32));
|
esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32));
|
||||||
|
|
||||||
ip_hdr(skb)->tot_len = htons(skb->len);
|
ip_hdr(skb)->tot_len = htons(skb->len);
|
||||||
|
|
|
@ -346,6 +346,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features
|
||||||
xo->seq.low += skb_shinfo(skb)->gso_segs;
|
xo->seq.low += skb_shinfo(skb)->gso_segs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xo->seq.low < seq)
|
||||||
|
xo->seq.hi++;
|
||||||
|
|
||||||
esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
|
esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
|
||||||
|
|
||||||
len = skb->len - sizeof(struct ipv6hdr);
|
len = skb->len - sizeof(struct ipv6hdr);
|
||||||
|
|
|
@ -97,6 +97,18 @@ static void xfrm_outer_mode_prep(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool xmit_xfrm_check_overflow(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct xfrm_offload *xo = xfrm_offload(skb);
|
||||||
|
__u32 seq = xo->seq.low;
|
||||||
|
|
||||||
|
seq += skb_shinfo(skb)->gso_segs;
|
||||||
|
if (unlikely(seq < xo->seq.low))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again)
|
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -134,7 +146,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skb_is_gso(skb) && unlikely(x->xso.dev != dev)) {
|
if (skb_is_gso(skb) && (unlikely(x->xso.dev != dev) ||
|
||||||
|
unlikely(xmit_xfrm_check_overflow(skb)))) {
|
||||||
struct sk_buff *segs;
|
struct sk_buff *segs;
|
||||||
|
|
||||||
/* Packet got rerouted, fixup features and segment it. */
|
/* Packet got rerouted, fixup features and segment it. */
|
||||||
|
|
|
@ -714,7 +714,7 @@ static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff
|
||||||
oseq += skb_shinfo(skb)->gso_segs;
|
oseq += skb_shinfo(skb)->gso_segs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(oseq < replay_esn->oseq)) {
|
if (unlikely(xo->seq.low < replay_esn->oseq)) {
|
||||||
XFRM_SKB_CB(skb)->seq.output.hi = ++oseq_hi;
|
XFRM_SKB_CB(skb)->seq.output.hi = ++oseq_hi;
|
||||||
xo->seq.hi = oseq_hi;
|
xo->seq.hi = oseq_hi;
|
||||||
replay_esn->oseq_hi = oseq_hi;
|
replay_esn->oseq_hi = oseq_hi;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue