diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f0cf117f3566..93c2f440b9ec 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2201,7 +2201,12 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask) /* Set the tail pointer and length */ skb_put(n, skb->len); - BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len)); + if (unlikely(skb_copy_bits(skb, -headerlen, n->head, + headerlen + skb->len))) { + DEBUG_NET_WARN_ON_ONCE(1); + kfree_skb(n); + return NULL; + } skb_copy_header(n, skb); return n; @@ -2303,9 +2308,15 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, u8 *data; int i; - BUG_ON(nhead < 0); + if (unlikely(nhead < 0)) { + DEBUG_NET_WARN_ON_ONCE(1); + return -EINVAL; + } - BUG_ON(skb_shared(skb)); + if (unlikely(skb_shared(skb))) { + DEBUG_NET_WARN_ON_ONCE(1); + return -EINVAL; + } skb_zcopy_downgrade_managed(skb); @@ -2539,8 +2550,13 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, head_copy_off = newheadroom - head_copy_len; /* Copy the linear header and data. */ - BUG_ON(skb_copy_bits(skb, -head_copy_len, n->head + head_copy_off, - skb->len + head_copy_len)); + if (unlikely(skb_copy_bits(skb, -head_copy_len, + n->head + head_copy_off, + skb->len + head_copy_len))) { + DEBUG_NET_WARN_ON_ONCE(1); + kfree_skb(n); + return NULL; + } skb_copy_header(n, skb); @@ -3603,7 +3619,10 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum) } start = end; } - BUG_ON(len); + if (unlikely(len)) { + DEBUG_NET_WARN_ON_ONCE(1); + return 0; + } return csum; } @@ -3698,7 +3717,13 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, } start = end; } - BUG_ON(len); + if (unlikely(len)) { + DEBUG_NET_WARN_ON_ONCE(1); + /* Don't hand the caller a buffer with stale bytes in it. */ + if (len > 0) + memset(to, 0, len); + return 0; + } return csum; } EXPORT_SYMBOL(skb_copy_and_csum_bits); @@ -3768,7 +3793,10 @@ u32 skb_crc32c(const struct sk_buff *skb, int offset, int len, u32 crc) } start = end; } - BUG_ON(len); + if (unlikely(len)) { + DEBUG_NET_WARN_ON_ONCE(1); + return 0; + } return crc; } @@ -3889,7 +3917,10 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) struct page *page; unsigned int offset; - BUG_ON(!from->head_frag && !hlen); + if (unlikely(!from->head_frag && !hlen)) { + DEBUG_NET_WARN_ON_ONCE(1); + return -EFAULT; + } /* dont bother with small payloads */ if (len <= skb_tailroom(to)) @@ -3959,7 +3990,18 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) else csstart = skb_headlen(skb); - BUG_ON(csstart > skb_headlen(skb)); + if (unlikely(csstart < 0 || csstart > skb_headlen(skb) || + (skb->ip_summed == CHECKSUM_PARTIAL && + csstart + skb->csum_offset + sizeof(__sum16) > + skb->len))) { + DEBUG_NET_WARN_ON_ONCE(1); + /* Send the frame without the checksum filled in, or send + * zeroes if we can't even copy it. + */ + if (skb_copy_bits(skb, 0, to, skb->len)) + memset(to, 0, skb->len); + return; + } skb_copy_from_linear_data(skb, to, csstart); @@ -4293,7 +4335,10 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) int from, to, merge, todo; skb_frag_t *fragfrom, *fragto; - BUG_ON(shiftlen > skb->len); + if (unlikely(shiftlen > skb->len)) { + DEBUG_NET_WARN_ON_ONCE(1); + return 0; + } if (skb_headlen(skb)) return 0; @@ -4373,6 +4418,14 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) } } + /* The frags ran out before shiftlen did. Nothing has been committed + * yet, so back out. + */ + if (unlikely(todo > 0)) { + DEBUG_NET_WARN_ON_ONCE(1); + return 0; + } + /* Ready to "commit" this state change to tgt */ skb_shinfo(tgt)->nr_frags = to; @@ -4390,8 +4443,6 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++]; skb_shinfo(skb)->nr_frags = to; - BUG_ON(todo > 0 && !skb_shinfo(skb)->nr_frags); - onlymerged: /* Most likely the tgt won't ever need its checksum anymore, skb on * the other hand might need it if it needs to be resent @@ -4918,7 +4969,11 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) && (skb_headlen(list_skb) == len || sg)) { - BUG_ON(skb_headlen(list_skb) > len); + if (unlikely(skb_headlen(list_skb) > len)) { + DEBUG_NET_WARN_ON_ONCE(1); + err = -EINVAL; + goto err; + } nskb = skb_clone(list_skb, GFP_ATOMIC); if (unlikely(!nskb)) @@ -4931,7 +4986,12 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, pos += skb_headlen(list_skb); while (pos < offset + len) { - BUG_ON(i >= nfrags); + if (unlikely(i >= nfrags)) { + DEBUG_NET_WARN_ON_ONCE(1); + kfree_skb(nskb); + err = -EINVAL; + goto err; + } size = skb_frag_size(frag); if (pos + size > offset + len) @@ -5038,9 +5098,17 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, skb_shinfo(nskb)->flags |= skb_shinfo(frag_skb)->flags & SKBFL_SHARED_FRAG; if (!skb_headlen(list_skb)) { - BUG_ON(!nfrags); + if (unlikely(!nfrags)) { + DEBUG_NET_WARN_ON_ONCE(1); + err = -EINVAL; + goto err; + } } else { - BUG_ON(!list_skb->head_frag); + if (unlikely(!list_skb->head_frag)) { + DEBUG_NET_WARN_ON_ONCE(1); + err = -EINVAL; + goto err; + } /* to make room for head_frag. */ i--; @@ -5314,7 +5382,10 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len, } start = end; } - BUG_ON(len); + if (unlikely(len)) { + DEBUG_NET_WARN_ON_ONCE(1); + return -EINVAL; + } return elt; } @@ -6222,8 +6293,15 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, return false; if (len <= skb_tailroom(to) && skb_frags_readable(from)) { - if (len) - BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len)); + if (len) { + if (unlikely(skb_copy_bits(from, 0, + skb_tail_pointer(to), + len))) { + DEBUG_NET_WARN_ON_ONCE(1); + return false; + } + skb_put(to, len); + } *delta_truesize = 0; return true; }