Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
authorDavid S. Miller <davem@davemloft.net>
Fri, 5 Jul 2019 21:58:22 +0000 (14:58 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 5 Jul 2019 21:58:22 +0000 (14:58 -0700)
Steffen Klassert says:

====================
pull request (net): ipsec 2019-07-05

1)  Fix xfrm selector prefix length validation for
    inter address family tunneling.
    From Anirudh Gupta.

2) Fix a memleak in pfkey.
   From Jeremy Sowden.

3) Fix SA selector validation to allow empty selectors again.
   From Nicolas Dichtel.

4) Select crypto ciphers for xfrm_algo, this fixes some
   randconfig builds. From Arnd Bergmann.

5) Remove a duplicated assignment in xfrm_bydst_resize.
   From Cong Wang.

6) Fix a hlist corruption on hash rebuild.
   From Florian Westphal.

7) Fix a memory leak when creating xfrm interfaces.
   From Nicolas Dichtel.

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

Signed-off-by: David S. Miller <davem@davemloft.net>
net/key/af_key.c
net/xfrm/Kconfig
net/xfrm/xfrm_interface.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
tools/testing/selftests/net/xfrm_policy.sh

index a50dd6f34b917c2609be28b634f6f90506a0f8a5..fe5fc4bab7eeb5c463d0bdd6b371c53b313e53d9 100644 (file)
@@ -2438,8 +2438,10 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc
                goto out;
        }
        err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
-       if (err < 0)
+       if (err < 0) {
+               kfree_skb(out_skb);
                goto out;
+       }
 
        out_hdr = (struct sadb_msg *) out_skb->data;
        out_hdr->sadb_msg_version = hdr->sadb_msg_version;
@@ -2690,8 +2692,10 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
                return PTR_ERR(out_skb);
 
        err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
-       if (err < 0)
+       if (err < 0) {
+               kfree_skb(out_skb);
                return err;
+       }
 
        out_hdr = (struct sadb_msg *) out_skb->data;
        out_hdr->sadb_msg_version = pfk->dump.msg_version;
index c967fc3c38c8727d7187c8d5f5cea0ffaf8d90a3..51bb6018f3bf3d1e2cddf3273e36448b2a8fa6af 100644 (file)
@@ -15,6 +15,8 @@ config XFRM_ALGO
        tristate
        select XFRM
        select CRYPTO
+       select CRYPTO_HASH
+       select CRYPTO_BLKCIPHER
 
 if INET
 config XFRM_USER
index ad3a2555c517f961c26712c4fcab60728bcf5798..7dbe0c608df58d609199dc94297f060ce547ec8c 100644 (file)
@@ -133,7 +133,7 @@ static void xfrmi_dev_free(struct net_device *dev)
        free_percpu(dev->tstats);
 }
 
-static int xfrmi_create2(struct net_device *dev)
+static int xfrmi_create(struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
        struct net *net = dev_net(dev);
@@ -156,54 +156,7 @@ out:
        return err;
 }
 
-static struct xfrm_if *xfrmi_create(struct net *net, struct xfrm_if_parms *p)
-{
-       struct net_device *dev;
-       struct xfrm_if *xi;
-       char name[IFNAMSIZ];
-       int err;
-
-       if (p->name[0]) {
-               strlcpy(name, p->name, IFNAMSIZ);
-       } else {
-               err = -EINVAL;
-               goto failed;
-       }
-
-       dev = alloc_netdev(sizeof(*xi), name, NET_NAME_UNKNOWN, xfrmi_dev_setup);
-       if (!dev) {
-               err = -EAGAIN;
-               goto failed;
-       }
-
-       dev_net_set(dev, net);
-
-       xi = netdev_priv(dev);
-       xi->p = *p;
-       xi->net = net;
-       xi->dev = dev;
-       xi->phydev = dev_get_by_index(net, p->link);
-       if (!xi->phydev) {
-               err = -ENODEV;
-               goto failed_free;
-       }
-
-       err = xfrmi_create2(dev);
-       if (err < 0)
-               goto failed_dev_put;
-
-       return xi;
-
-failed_dev_put:
-       dev_put(xi->phydev);
-failed_free:
-       free_netdev(dev);
-failed:
-       return ERR_PTR(err);
-}
-
-static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p,
-                                  int create)
+static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p)
 {
        struct xfrm_if __rcu **xip;
        struct xfrm_if *xi;
@@ -211,17 +164,11 @@ static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p,
 
        for (xip = &xfrmn->xfrmi[0];
             (xi = rtnl_dereference(*xip)) != NULL;
-            xip = &xi->next) {
-               if (xi->p.if_id == p->if_id) {
-                       if (create)
-                               return ERR_PTR(-EEXIST);
-
+            xip = &xi->next)
+               if (xi->p.if_id == p->if_id)
                        return xi;
-               }
-       }
-       if (!create)
-               return ERR_PTR(-ENODEV);
-       return xfrmi_create(net, p);
+
+       return NULL;
 }
 
 static void xfrmi_dev_uninit(struct net_device *dev)
@@ -686,21 +633,33 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
                        struct netlink_ext_ack *extack)
 {
        struct net *net = dev_net(dev);
-       struct xfrm_if_parms *p;
+       struct xfrm_if_parms p;
        struct xfrm_if *xi;
+       int err;
 
-       xi = netdev_priv(dev);
-       p = &xi->p;
-
-       xfrmi_netlink_parms(data, p);
+       xfrmi_netlink_parms(data, &p);
 
        if (!tb[IFLA_IFNAME])
                return -EINVAL;
 
-       nla_strlcpy(p->name, tb[IFLA_IFNAME], IFNAMSIZ);
+       nla_strlcpy(p.name, tb[IFLA_IFNAME], IFNAMSIZ);
 
-       xi = xfrmi_locate(net, p, 1);
-       return PTR_ERR_OR_ZERO(xi);
+       xi = xfrmi_locate(net, &p);
+       if (xi)
+               return -EEXIST;
+
+       xi = netdev_priv(dev);
+       xi->p = p;
+       xi->net = net;
+       xi->dev = dev;
+       xi->phydev = dev_get_by_index(net, p.link);
+       if (!xi->phydev)
+               return -ENODEV;
+
+       err = xfrmi_create(dev);
+       if (err < 0)
+               dev_put(xi->phydev);
+       return err;
 }
 
 static void xfrmi_dellink(struct net_device *dev, struct list_head *head)
@@ -717,9 +676,8 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
 
        xfrmi_netlink_parms(data, &xi->p);
 
-       xi = xfrmi_locate(net, &xi->p, 0);
-
-       if (IS_ERR_OR_NULL(xi)) {
+       xi = xfrmi_locate(net, &xi->p);
+       if (!xi) {
                xi = netdev_priv(dev);
        } else {
                if (xi->dev != dev)
index b1694d5d15d350b4f53175f0e1c49dfee6efc972..4fb58dfecc7a1daef5be0758e56d0014b8962208 100644 (file)
@@ -582,9 +582,6 @@ static void xfrm_bydst_resize(struct net *net, int dir)
        spin_lock_bh(&net->xfrm.xfrm_policy_lock);
        write_seqcount_begin(&xfrm_policy_hash_generation);
 
-       odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table,
-                               lockdep_is_held(&net->xfrm.xfrm_policy_lock));
-
        odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table,
                                lockdep_is_held(&net->xfrm.xfrm_policy_lock));
 
@@ -1280,13 +1277,17 @@ static void xfrm_hash_rebuild(struct work_struct *work)
 
                hlist_for_each_entry_safe(policy, n,
                                          &net->xfrm.policy_inexact[dir],
-                                         bydst_inexact_list)
+                                         bydst_inexact_list) {
+                       hlist_del_rcu(&policy->bydst);
                        hlist_del_init(&policy->bydst_inexact_list);
+               }
 
                hmask = net->xfrm.policy_bydst[dir].hmask;
                odst = net->xfrm.policy_bydst[dir].table;
-               for (i = hmask; i >= 0; i--)
-                       INIT_HLIST_HEAD(odst + i);
+               for (i = hmask; i >= 0; i--) {
+                       hlist_for_each_entry_safe(policy, n, odst + i, bydst)
+                               hlist_del_rcu(&policy->bydst);
+               }
                if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
                        /* dir out => dst = remote, src = local */
                        net->xfrm.policy_bydst[dir].dbits4 = rbits4;
@@ -1315,8 +1316,6 @@ static void xfrm_hash_rebuild(struct work_struct *work)
                chain = policy_hash_bysel(net, &policy->selector,
                                          policy->family, dir);
 
-               hlist_del_rcu(&policy->bydst);
-
                if (!chain) {
                        void *p = xfrm_policy_inexact_insert(policy, dir, 0);
 
index 173477211e4027bd0810ba8833eb62f010733b64..b88ba45ff1ace6ff986cf214c9fd8d1b8730261d 100644 (file)
@@ -151,6 +151,25 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
 
        err = -EINVAL;
        switch (p->family) {
+       case AF_INET:
+               break;
+
+       case AF_INET6:
+#if IS_ENABLED(CONFIG_IPV6)
+               break;
+#else
+               err = -EAFNOSUPPORT;
+               goto out;
+#endif
+
+       default:
+               goto out;
+       }
+
+       switch (p->sel.family) {
+       case AF_UNSPEC:
+               break;
+
        case AF_INET:
                if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
                        goto out;
index 71d7fdc513c1bbe270688d732a415c390007ec45..5445943bf07f222acaba83a253668ec06db032e5 100755 (executable)
@@ -257,6 +257,29 @@ check_exceptions()
        return $lret
 }
 
+check_hthresh_repeat()
+{
+       local log=$1
+       i=0
+
+       for i in $(seq 1 10);do
+               ip -net ns1 xfrm policy update src e000:0001::0000 dst ff01::0014:0000:0001 dir in tmpl src :: dst :: proto esp mode tunnel priority 100 action allow || break
+               ip -net ns1 xfrm policy set hthresh6 0 28 || break
+
+               ip -net ns1 xfrm policy update src e000:0001::0000 dst ff01::01 dir in tmpl src :: dst :: proto esp mode tunnel priority 100 action allow || break
+               ip -net ns1 xfrm policy set hthresh6 0 28 || break
+       done
+
+       if [ $i -ne 10 ] ;then
+               echo "FAIL: $log" 1>&2
+               ret=1
+               return 1
+       fi
+
+       echo "PASS: $log"
+       return 0
+}
+
 #check for needed privileges
 if [ "$(id -u)" -ne 0 ];then
        echo "SKIP: Need root privileges"
@@ -404,7 +427,9 @@ for n in ns3 ns4;do
        ip -net $n xfrm policy set hthresh4 32 32 hthresh6 128 128
        sleep $((RANDOM%5))
 done
-check_exceptions "exceptions and block policies after hresh change to normal"
+check_exceptions "exceptions and block policies after htresh change to normal"
+
+check_hthresh_repeat "policies with repeated htresh change"
 
 for i in 1 2 3 4;do ip netns del ns$i;done