diff options
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r-- | net/core/skbuff.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 2b40b5a9425b..f12e8a050edb 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -3670,6 +3670,25 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, | |||
3670 | int pos; | 3670 | int pos; |
3671 | int dummy; | 3671 | int dummy; |
3672 | 3672 | ||
3673 | if (list_skb && !list_skb->head_frag && skb_headlen(list_skb) && | ||
3674 | (skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY)) { | ||
3675 | /* gso_size is untrusted, and we have a frag_list with a linear | ||
3676 | * non head_frag head. | ||
3677 | * | ||
3678 | * (we assume checking the first list_skb member suffices; | ||
3679 | * i.e if either of the list_skb members have non head_frag | ||
3680 | * head, then the first one has too). | ||
3681 | * | ||
3682 | * If head_skb's headlen does not fit requested gso_size, it | ||
3683 | * means that the frag_list members do NOT terminate on exact | ||
3684 | * gso_size boundaries. Hence we cannot perform skb_frag_t page | ||
3685 | * sharing. Therefore we must fallback to copying the frag_list | ||
3686 | * skbs; we do so by disabling SG. | ||
3687 | */ | ||
3688 | if (mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb)) | ||
3689 | features &= ~NETIF_F_SG; | ||
3690 | } | ||
3691 | |||
3673 | __skb_push(head_skb, doffset); | 3692 | __skb_push(head_skb, doffset); |
3674 | proto = skb_network_protocol(head_skb, &dummy); | 3693 | proto = skb_network_protocol(head_skb, &dummy); |
3675 | if (unlikely(!proto)) | 3694 | if (unlikely(!proto)) |