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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
114b5b355e
|
@ -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)
|
||||||
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
|
||||||
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)
|
||||||
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 @@ out:
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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[],
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
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()
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue