Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NET]: Fix ___pskb_trim when entire frag_list needs dropping

When the trim point is within the head and there is no paged data,
___pskb_trim fails to drop the first element in the frag_list.
This patch fixes this by moving the len <= offset case out of the
page data loop.

This patch also adds a missing kfree_skb on the frag that we just
cloned.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
f4d26fb3 9cd3ecd6

+10 -4
+10 -4
net/core/skbuff.c
··· 846 846 unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))) 847 847 return err; 848 848 849 - for (i = 0; i < nfrags; i++) { 849 + i = 0; 850 + if (offset >= len) 851 + goto drop_pages; 852 + 853 + for (; i < nfrags; i++) { 850 854 int end = offset + skb_shinfo(skb)->frags[i].size; 851 855 852 856 if (end < len) { ··· 858 854 continue; 859 855 } 860 856 861 - if (len > offset) 862 - skb_shinfo(skb)->frags[i++].size = len - offset; 857 + skb_shinfo(skb)->frags[i++].size = len - offset; 863 858 859 + drop_pages: 864 860 skb_shinfo(skb)->nr_frags = i; 865 861 866 862 for (; i < nfrags; i++) ··· 868 864 869 865 if (skb_shinfo(skb)->frag_list) 870 866 skb_drop_fraglist(skb); 871 - break; 867 + goto done; 872 868 } 873 869 874 870 for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp); ··· 883 879 return -ENOMEM; 884 880 885 881 nfrag->next = frag->next; 882 + kfree_skb(frag); 886 883 frag = nfrag; 887 884 *fragp = frag; 888 885 } ··· 902 897 break; 903 898 } 904 899 900 + done: 905 901 if (len > skb_headlen(skb)) { 906 902 skb->data_len -= skb->len - len; 907 903 skb->len = len;