For a CHECKSUM_COMPLETE skb, pskb_trim_rcsum() subtracts the checksum of the trimmed bytes from skb->csum. It gets that checksum from skb_checksum(), which returns 0 if the trimmed range runs into an unreadable frag_list member or past the end of the skb. skb->csum then still covers the trimmed bytes. commit 2e357f002c61 ("net: Avoid checksumming unreadable skb tail on trim") handles an skb that is itself unreadable, but not a readable head with an unreadable frag_list member. Use skb_checksum_full(). When it fails, do what pskb_trim_rcsum() already does for an unreadable skb. Set CHECKSUM_NONE if the remaining packet can be read, so that software checksums it, and fail the trim with -EFAULT if it can't. The stale skb->csum was only reproduced with a hand-built skb in a test module. Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags") Fixes: 20ddd0fd2fcd ("net: skbuff: don't BUG() on leftover length in skb_checksum() and friends") Signed-off-by: Josef Bacik --- net/core/skbuff.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 5f997edf3519..68801a4f471b 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2821,9 +2821,23 @@ static int pskb_trim_rcsum_complete(struct sk_buff *skb, unsigned int len) int delta = skb->len - len; if (skb_frags_readable(skb)) { - skb->csum = csum_block_sub(skb->csum, - skb_checksum(skb, len, delta, 0), - len); + __wsum csum = 0; + int err; + + if (!skb_checksum_full(skb, len, delta, &csum)) { + skb->csum = csum_block_sub(skb->csum, csum, len); + return 0; + } + + /* The trimmed bytes can't be checksummed, so skb->csum can't + * be adjusted. Software can checksum the remaining packet + * after trimming, as long as it can read it. + */ + csum = 0; + err = skb_checksum_full(skb, 0, len, &csum); + if (err) + return err; + skb->ip_summed = CHECKSUM_NONE; return 0; } -- 2.55.0