Commit 114b5b35 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d1bc24b 56c5ee1a
...@@ -2438,8 +2438,10 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc ...@@ -2438,8 +2438,10 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc
goto out; goto out;
} }
err = pfkey_xfrm_policy2msg(out_skb, xp, dir); err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
if (err < 0) if (err < 0) {
kfree_skb(out_skb);
goto out; goto out;
}
out_hdr = (struct sadb_msg *) out_skb->data; out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = hdr->sadb_msg_version; 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) ...@@ -2690,8 +2692,10 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
return PTR_ERR(out_skb); return PTR_ERR(out_skb);
err = pfkey_xfrm_policy2msg(out_skb, xp, dir); err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
if (err < 0) if (err < 0) {
kfree_skb(out_skb);
return err; return err;
}
out_hdr = (struct sadb_msg *) out_skb->data; out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = pfk->dump.msg_version; out_hdr->sadb_msg_version = pfk->dump.msg_version;
......
...@@ -15,6 +15,8 @@ config XFRM_ALGO ...@@ -15,6 +15,8 @@ config XFRM_ALGO
tristate tristate
select XFRM select XFRM
select CRYPTO select CRYPTO
select CRYPTO_HASH
select CRYPTO_BLKCIPHER
if INET if INET
config XFRM_USER config XFRM_USER
......
...@@ -133,7 +133,7 @@ static void xfrmi_dev_free(struct net_device *dev) ...@@ -133,7 +133,7 @@ static void xfrmi_dev_free(struct net_device *dev)
free_percpu(dev->tstats); 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 xfrm_if *xi = netdev_priv(dev);
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
...@@ -156,54 +156,7 @@ static int xfrmi_create2(struct net_device *dev) ...@@ -156,54 +156,7 @@ static int xfrmi_create2(struct net_device *dev)
return err; return err;
} }
static struct xfrm_if *xfrmi_create(struct net *net, struct xfrm_if_parms *p) static struct xfrm_if *xfrmi_locate(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)
{ {
struct xfrm_if __rcu **xip; struct xfrm_if __rcu **xip;
struct xfrm_if *xi; struct xfrm_if *xi;
...@@ -211,17 +164,11 @@ static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p, ...@@ -211,17 +164,11 @@ static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p,
for (xip = &xfrmn->xfrmi[0]; for (xip = &xfrmn->xfrmi[0];
(xi = rtnl_dereference(*xip)) != NULL; (xi = rtnl_dereference(*xip)) != NULL;
xip = &xi->next) { xip = &xi->next)
if (xi->p.if_id == p->if_id) { if (xi->p.if_id == p->if_id)
if (create)
return ERR_PTR(-EEXIST);
return xi; return xi;
}
} return NULL;
if (!create)
return ERR_PTR(-ENODEV);
return xfrmi_create(net, p);
} }
static void xfrmi_dev_uninit(struct net_device *dev) 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, ...@@ -686,21 +633,33 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
struct xfrm_if_parms *p; struct xfrm_if_parms p;
struct xfrm_if *xi; struct xfrm_if *xi;
int err;
xi = netdev_priv(dev); xfrmi_netlink_parms(data, &p);
p = &xi->p;
xfrmi_netlink_parms(data, p);
if (!tb[IFLA_IFNAME]) if (!tb[IFLA_IFNAME])
return -EINVAL; return -EINVAL;
nla_strlcpy(p->name, tb[IFLA_IFNAME], IFNAMSIZ); nla_strlcpy(p.name, tb[IFLA_IFNAME], IFNAMSIZ);
xi = xfrmi_locate(net, p, 1); xi = xfrmi_locate(net, &p);
return PTR_ERR_OR_ZERO(xi); 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) 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[], ...@@ -717,9 +676,8 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
xfrmi_netlink_parms(data, &xi->p); xfrmi_netlink_parms(data, &xi->p);
xi = xfrmi_locate(net, &xi->p, 0); xi = xfrmi_locate(net, &xi->p);
if (!xi) {
if (IS_ERR_OR_NULL(xi)) {
xi = netdev_priv(dev); xi = netdev_priv(dev);
} else { } else {
if (xi->dev != dev) if (xi->dev != dev)
......
...@@ -582,9 +582,6 @@ static void xfrm_bydst_resize(struct net *net, int dir) ...@@ -582,9 +582,6 @@ static void xfrm_bydst_resize(struct net *net, int dir)
spin_lock_bh(&net->xfrm.xfrm_policy_lock); spin_lock_bh(&net->xfrm.xfrm_policy_lock);
write_seqcount_begin(&xfrm_policy_hash_generation); 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, odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table,
lockdep_is_held(&net->xfrm.xfrm_policy_lock)); lockdep_is_held(&net->xfrm.xfrm_policy_lock));
...@@ -1280,13 +1277,17 @@ static void xfrm_hash_rebuild(struct work_struct *work) ...@@ -1280,13 +1277,17 @@ static void xfrm_hash_rebuild(struct work_struct *work)
hlist_for_each_entry_safe(policy, n, hlist_for_each_entry_safe(policy, n,
&net->xfrm.policy_inexact[dir], &net->xfrm.policy_inexact[dir],
bydst_inexact_list) bydst_inexact_list) {
hlist_del_rcu(&policy->bydst);
hlist_del_init(&policy->bydst_inexact_list); hlist_del_init(&policy->bydst_inexact_list);
}
hmask = net->xfrm.policy_bydst[dir].hmask; hmask = net->xfrm.policy_bydst[dir].hmask;
odst = net->xfrm.policy_bydst[dir].table; odst = net->xfrm.policy_bydst[dir].table;
for (i = hmask; i >= 0; i--) for (i = hmask; i >= 0; i--) {
INIT_HLIST_HEAD(odst + i); hlist_for_each_entry_safe(policy, n, odst + i, bydst)
hlist_del_rcu(&policy->bydst);
}
if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) { if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
/* dir out => dst = remote, src = local */ /* dir out => dst = remote, src = local */
net->xfrm.policy_bydst[dir].dbits4 = rbits4; net->xfrm.policy_bydst[dir].dbits4 = rbits4;
...@@ -1315,8 +1316,6 @@ static void xfrm_hash_rebuild(struct work_struct *work) ...@@ -1315,8 +1316,6 @@ static void xfrm_hash_rebuild(struct work_struct *work)
chain = policy_hash_bysel(net, &policy->selector, chain = policy_hash_bysel(net, &policy->selector,
policy->family, dir); policy->family, dir);
hlist_del_rcu(&policy->bydst);
if (!chain) { if (!chain) {
void *p = xfrm_policy_inexact_insert(policy, dir, 0); void *p = xfrm_policy_inexact_insert(policy, dir, 0);
......
...@@ -151,6 +151,25 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, ...@@ -151,6 +151,25 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
err = -EINVAL; err = -EINVAL;
switch (p->family) { 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: case AF_INET:
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32) if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
goto out; goto out;
......
...@@ -257,6 +257,29 @@ check_exceptions() ...@@ -257,6 +257,29 @@ check_exceptions()
return $lret 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 #check for needed privileges
if [ "$(id -u)" -ne 0 ];then if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges" echo "SKIP: Need root privileges"
...@@ -404,7 +427,9 @@ for n in ns3 ns4;do ...@@ -404,7 +427,9 @@ for n in ns3 ns4;do
ip -net $n xfrm policy set hthresh4 32 32 hthresh6 128 128 ip -net $n xfrm policy set hthresh4 32 32 hthresh6 128 128
sleep $((RANDOM%5)) sleep $((RANDOM%5))
done 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 for i in 1 2 3 4;do ip netns del ns$i;done
......
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