Packets received through TUN or virtio-net can have gso_segs == 0,
with SKB_GSO_DODGY set until the segmentation metadata is checked.
When ESP defers segmentation, gso_segs is still zero, so the SA
sequence counter is not advanced. The segments receive sequence
numbers starting at oseq + 1, which subsequent packets can reuse,
causing AES-GCM nonce reuse.
This affects IPv4 and IPv6, with or without ESN, when the ESP offload
type is registered. Hardware encryption is not required.
Segment SKB_GSO_DODGY packets in xfrm_output() before allocating
sequence numbers, so each segment gets its own number. Set the ESP
encapsulation flag in xfrm_output_one(), after early segmentation, so
UFO fragment offsets and flags are filled in correctly.
Fixes: d7dbefc45cf5 ("xfrm: Add xfrm_replay_overflow functions for offloading")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Jérémy Jean <redacted>
---
net/xfrm/xfrm_output.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index f6644daa68ba..30b95aba10f0 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -505,6 +505,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
if (err <= 0 || x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
goto resume;
+ if (xfrm_offload(skb))
+ skb->encapsulation = 1;
+
do {
err = xfrm_skb_check_space(skb);
if (err) {@@ -812,10 +815,10 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
xfrm_state_hold(x);
xfrm_get_inner_ipproto(skb, x);
- skb->encapsulation = 1;
if (skb_is_gso(skb)) {
- if (skb->inner_protocol && x->props.mode == XFRM_MODE_TUNNEL)
+ if ((skb_shinfo(skb)->gso_type & SKB_GSO_DODGY) ||
+ (skb->inner_protocol && x->props.mode == XFRM_MODE_TUNNEL))
return xfrm_output_gso(net, sk, skb);
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;--
2.47.3