ERSPAN currently uses pskb_trim() when truncating packets to the device
MTU. For a CHECKSUM_PARTIAL skb, that helper can leave csum_start and
csum_offset pointing at a checksum field outside the new packet length.
The skb can then reach skb_checksum_help() during transmit validation,
which warns when the checksum offset is beyond skb_headlen().
Use pskb_trim_rcsum() in both ERSPAN transmit paths. It rejects a
CHECKSUM_PARTIAL skb whose checksum field is no longer in the trimmed
linear data and returns -EINVAL. The existing error paths then free the
skb instead of transmitting inconsistent checksum metadata.
This issue was found using a customized syzkaller-based fuzzer.
Tested on Linux v7.1-rc6 (e43ffb69e043), x86_64, with a diagnostic C
reproducer derived from the syzkaller reproducer and resolving erspan0
at runtime. The unpatched kernel reported
offset (4516) >= skb_headlen() (3730) and panicked with panic_on_warn.
The patched kernel ran the same program without the warning or panic.
Fixes: f192970de860 ("ip_gre: check packet length and mtu correctly in
erspan tx")
Found-by: Sechang Lim [off-list ref]
Signed-off-by: Kenneth Lee <redacted>
---
net/ipv4/ip_gre.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 169e2921a851..16f80620f6d1 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -576,7 +576,7 @@ static void erspan_fb_xmit(struct sk_buff *skb,
struct net_device *dev)
goto err_free_skb;
if (skb->len > dev->mtu + dev->hard_header_len) {
- if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
+ if (pskb_trim_rcsum(skb, dev->mtu + dev->hard_header_len))
goto err_free_skb;
truncate = true;
}@@ -723,7 +723,7 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb,
goto free_skb;
if (skb->len > dev->mtu + dev->hard_header_len) {
- if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
+ if (pskb_trim_rcsum(skb, dev->mtu + dev->hard_header_len))
goto free_skb;
truncate = true;
}--
2.53.0