Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
authorDavid S. Miller <davem@davemloft.net>
Tue, 22 Aug 2017 17:27:26 +0000 (10:27 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 22 Aug 2017 17:27:26 +0000 (10:27 -0700)
Steffen Klassert says:

====================
pull request (net): ipsec 2017-08-21

1) Fix memleaks when ESP takes an error path.

2) Fix null pointer dereference when creating a sub policy
   that matches the same outer flow as main policy does.
   From Koichiro Den.

3) Fix possible out-of-bound access in xfrm_migrate.
   This patch should go to the stable trees too.
   From Vladis Dronov.

4) ESP can return positive and negative error values,
   so treat both cases as an error.

Please pull or let me know if there are problems.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/esp4.c
net/ipv4/esp4_offload.c
net/ipv6/esp6.c
net/ipv6/esp6_offload.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c

index 0cbee0a666ffd2a1b7451b0b07513b1cf1cebfc0..dbb31a942dfa1bef204cc1459dbf1727923e089e 100644 (file)
@@ -381,7 +381,7 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
                           (unsigned char *)esph - skb->data,
                           assoclen + ivlen + esp->clen + alen);
        if (unlikely(err < 0))
-               goto error;
+               goto error_free;
 
        if (!esp->inplace) {
                int allocsize;
@@ -392,7 +392,7 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
                spin_lock_bh(&x->lock);
                if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
                        spin_unlock_bh(&x->lock);
-                       goto error;
+                       goto error_free;
                }
 
                skb_shinfo(skb)->nr_frags = 1;
@@ -409,7 +409,7 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
                                   (unsigned char *)esph - skb->data,
                                   assoclen + ivlen + esp->clen + alen);
                if (unlikely(err < 0))
-                       goto error;
+                       goto error_free;
        }
 
        if ((x->props.flags & XFRM_STATE_ESN))
@@ -442,8 +442,9 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
 
        if (sg != dsg)
                esp_ssg_unref(x, tmp);
-       kfree(tmp);
 
+error_free:
+       kfree(tmp);
 error:
        return err;
 }
@@ -695,8 +696,10 @@ skip_cow:
 
        sg_init_table(sg, nfrags);
        err = skb_to_sgvec(skb, sg, 0, skb->len);
-       if (unlikely(err < 0))
+       if (unlikely(err < 0)) {
+               kfree(tmp);
                goto out;
+       }
 
        skb->ip_summed = CHECKSUM_NONE;
 
index e0666016a7642c017b4693d32723245adc484982..50112324fa5c3638527b12477c356ce406ba9a36 100644 (file)
@@ -257,7 +257,7 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb,  netdev_features_
        esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
 
        err = esp_output_tail(x, skb, &esp);
-       if (err < 0)
+       if (err)
                return err;
 
        secpath_reset(skb);
index 9ed35473dcb53bd6ae52f8f86e1558410bbcd7b6..392def1fcf21e676780d1218ab7049461dbcdf88 100644 (file)
@@ -345,7 +345,7 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
                           (unsigned char *)esph - skb->data,
                           assoclen + ivlen + esp->clen + alen);
        if (unlikely(err < 0))
-               goto error;
+               goto error_free;
 
        if (!esp->inplace) {
                int allocsize;
@@ -356,7 +356,7 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
                spin_lock_bh(&x->lock);
                if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
                        spin_unlock_bh(&x->lock);
-                       goto error;
+                       goto error_free;
                }
 
                skb_shinfo(skb)->nr_frags = 1;
@@ -373,7 +373,7 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
                                   (unsigned char *)esph - skb->data,
                                   assoclen + ivlen + esp->clen + alen);
                if (unlikely(err < 0))
-                       goto error;
+                       goto error_free;
        }
 
        if ((x->props.flags & XFRM_STATE_ESN))
@@ -406,8 +406,9 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
 
        if (sg != dsg)
                esp_ssg_unref(x, tmp);
-       kfree(tmp);
 
+error_free:
+       kfree(tmp);
 error:
        return err;
 }
index f02f131f6435a967de395b9a7069051c93a039d7..1cf437f75b0bf2bc446337ededbf58bd22673823 100644 (file)
@@ -286,7 +286,7 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb,  netdev_features
        esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
 
        err = esp6_output_tail(x, skb, &esp);
-       if (err < 0)
+       if (err)
                return err;
 
        secpath_reset(skb);
index ff61d85579292dee8a7f1e9926e11734556f4fd9..6f5a0dad502f6ef39042fd2202c5e9e568511240 100644 (file)
@@ -3308,9 +3308,15 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
        struct xfrm_state *x_new[XFRM_MAX_DEPTH];
        struct xfrm_migrate *mp;
 
+       /* Stage 0 - sanity checks */
        if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
                goto out;
 
+       if (dir >= XFRM_POLICY_MAX) {
+               err = -EINVAL;
+               goto out;
+       }
+
        /* Stage 1 - find policy */
        if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
                err = -ENOENT;
index 6c0956d10db601add764616df62dbe19999c29b4..a792effdb0b5d51fb88835349a44a756d3a9e5e7 100644 (file)
@@ -1620,6 +1620,7 @@ int
 xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
               unsigned short family, struct net *net)
 {
+       int i;
        int err = 0;
        struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
        if (!afinfo)
@@ -1628,6 +1629,9 @@ xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
        spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/
        if (afinfo->tmpl_sort)
                err = afinfo->tmpl_sort(dst, src, n);
+       else
+               for (i = 0; i < n; i++)
+                       dst[i] = src[i];
        spin_unlock_bh(&net->xfrm.xfrm_state_lock);
        rcu_read_unlock();
        return err;
@@ -1638,6 +1642,7 @@ int
 xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
                unsigned short family)
 {
+       int i;
        int err = 0;
        struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
        struct net *net = xs_net(*src);
@@ -1648,6 +1653,9 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
        spin_lock_bh(&net->xfrm.xfrm_state_lock);
        if (afinfo->state_sort)
                err = afinfo->state_sort(dst, src, n);
+       else
+               for (i = 0; i < n; i++)
+                       dst[i] = src[i];
        spin_unlock_bh(&net->xfrm.xfrm_state_lock);
        rcu_read_unlock();
        return err;