]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: make skb_gso_segment error handling more robust
authorFlorian Westphal <fw@strlen.de>
Mon, 20 Oct 2014 11:49:17 +0000 (13:49 +0200)
committerZefan Li <lizefan@huawei.com>
Fri, 19 Jun 2015 03:40:33 +0000 (11:40 +0800)
commit 330966e501ffe282d7184fde4518d5e0c24bc7f8 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: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Cc: Ben Hutchings <ben@decadent.org.uk>
[lizf: Backported to 3.4: drop some hunks as there are fewer skb_gso_segment()
 users in 3.4]
Signed-off-by: Zefan Li <lizefan@huawei.com>
net/netfilter/nf_queue.c
net/openvswitch/datapath.c
net/xfrm/xfrm_output.c

index ce60cf0f6c11a49d9d8bc8bf5c8918d10dbfb316..9139a2642b9c91545dfbd2989f899df0d863dd99 100644 (file)
@@ -255,7 +255,7 @@ int nf_queue(struct sk_buff *skb,
         * returned by nf_queue.  For instance, callers rely on -ECANCELED to mean
         * 'ignore this hook'.
         */
-       if (IS_ERR(segs))
+       if (IS_ERR_OR_NULL(segs))
                goto out_err;
        queued = 0;
        err = 0;
index 1efa548ebb9d950701cd673203449245ed91f936..a92d635e0780292ecaf3676a50f7e4d272dbb73d 100644 (file)
@@ -271,6 +271,8 @@ static int queue_gso_packets(int dp_ifindex, struct sk_buff *skb,
        segs = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
        if (IS_ERR(segs))
                return PTR_ERR(segs);
+       if (segs == NULL)
+               return -EINVAL;
 
        /* Queue all of the segments. */
        skb = segs;
index 95a338c89f99d87af24ffa97faf17e1a7ef700e8..11dd2fbd476f90f6dd1919c405883bf73230f4ae 100644 (file)
@@ -151,6 +151,8 @@ static int xfrm_output_gso(struct sk_buff *skb)
        kfree_skb(skb);
        if (IS_ERR(segs))
                return PTR_ERR(segs);
+       if (segs == NULL)
+               return -EINVAL;
 
        do {
                struct sk_buff *nskb = segs->next;