Commit 1be080b5 authored by Florian Westphal's avatar Florian Westphal Committed by Luis Henriques

net: make skb_gso_segment error handling more robust

commit 330966e5 upstream.

skb_gso_segment has three possible return values:
1. a pointer to the first segmented skb
2. an errno value (IS_ERR())
3. NULL.  This can happen when GSO is used for header verification.

However, several callers currently test IS_ERR instead of IS_ERR_OR_NULL
and would oops when NULL is returned.

Note that these call sites should never actually see such a NULL return
value; all callers mask out the GSO bits in the feature argument.

However, there have been issues with some protocol handlers erronously not
respecting the specified feature mask in some cases.

It is preferable to get 'have to turn off hw offloading, else slow' reports
rather than 'kernel crashes'.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent dcab0580
...@@ -231,7 +231,7 @@ static int ip_finish_output_gso(struct sk_buff *skb) ...@@ -231,7 +231,7 @@ static int ip_finish_output_gso(struct sk_buff *skb)
*/ */
features = netif_skb_features(skb); features = netif_skb_features(skb);
segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
if (IS_ERR(segs)) { if (IS_ERR_OR_NULL(segs)) {
kfree_skb(skb); kfree_skb(skb);
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -665,7 +665,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) ...@@ -665,7 +665,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
* returned by nf_queue. For instance, callers rely on -ECANCELED to * returned by nf_queue. For instance, callers rely on -ECANCELED to
* mean 'ignore this hook'. * mean 'ignore this hook'.
*/ */
if (IS_ERR(segs)) if (IS_ERR_OR_NULL(segs))
goto out_err; goto out_err;
queued = 0; queued = 0;
err = 0; err = 0;
......
...@@ -330,6 +330,8 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, ...@@ -330,6 +330,8 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
segs = __skb_gso_segment(skb, NETIF_F_SG, false); segs = __skb_gso_segment(skb, NETIF_F_SG, false);
if (IS_ERR(segs)) if (IS_ERR(segs))
return PTR_ERR(segs); return PTR_ERR(segs);
if (segs == NULL)
return -EINVAL;
/* Queue all of the segments. */ /* Queue all of the segments. */
skb = segs; skb = segs;
......
...@@ -157,6 +157,8 @@ static int xfrm_output_gso(struct sk_buff *skb) ...@@ -157,6 +157,8 @@ static int xfrm_output_gso(struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
if (IS_ERR(segs)) if (IS_ERR(segs))
return PTR_ERR(segs); return PTR_ERR(segs);
if (segs == NULL)
return -EINVAL;
do { do {
struct sk_buff *nskb = segs->next; struct sk_buff *nskb = segs->next;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment