aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorMaxim Mikityanskiy <maximmi@mellanox.com>2019-05-21 02:40:04 -0400
committerDavid S. Miller <davem@davemloft.net>2019-05-22 15:07:25 -0400
commit7dc2bccab0ee37ac28096b8fcdc390a679a15841 (patch)
treea747c5ea65b10d25d71cabbe1d6eeb351bac6a79 /net/ipv6
parent54dee406374ce8adb352c48e175176247cb8db7c (diff)
Validate required parameters in inet6_validate_link_af
inet6_set_link_af requires that at least one of IFLA_INET6_TOKEN or IFLA_INET6_ADDR_GET_MODE is passed. If none of them is passed, it returns -EINVAL, which may cause do_setlink() to fail in the middle of processing other commands and give the following warning message: A link change request failed with some changes committed already. Interface eth0 may have been left with an inconsistent configuration, please check. Check the presence of at least one of them in inet6_validate_link_af to detect invalid parameters at an early stage, before do_setlink does anything. Also validate the address generation mode at an early stage. Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c57
1 files changed, 35 insertions, 22 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f96d1de79509..b51630ddb728 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5661,18 +5661,6 @@ static const struct nla_policy inet6_af_policy[IFLA_INET6_MAX + 1] = {
5661 [IFLA_INET6_TOKEN] = { .len = sizeof(struct in6_addr) }, 5661 [IFLA_INET6_TOKEN] = { .len = sizeof(struct in6_addr) },
5662}; 5662};
5663 5663
5664static int inet6_validate_link_af(const struct net_device *dev,
5665 const struct nlattr *nla)
5666{
5667 struct nlattr *tb[IFLA_INET6_MAX + 1];
5668
5669 if (dev && !__in6_dev_get(dev))
5670 return -EAFNOSUPPORT;
5671
5672 return nla_parse_nested_deprecated(tb, IFLA_INET6_MAX, nla,
5673 inet6_af_policy, NULL);
5674}
5675
5676static int check_addr_gen_mode(int mode) 5664static int check_addr_gen_mode(int mode)
5677{ 5665{
5678 if (mode != IN6_ADDR_GEN_MODE_EUI64 && 5666 if (mode != IN6_ADDR_GEN_MODE_EUI64 &&
@@ -5693,14 +5681,44 @@ static int check_stable_privacy(struct inet6_dev *idev, struct net *net,
5693 return 1; 5681 return 1;
5694} 5682}
5695 5683
5684static int inet6_validate_link_af(const struct net_device *dev,
5685 const struct nlattr *nla)
5686{
5687 struct nlattr *tb[IFLA_INET6_MAX + 1];
5688 struct inet6_dev *idev = NULL;
5689 int err;
5690
5691 if (dev) {
5692 idev = __in6_dev_get(dev);
5693 if (!idev)
5694 return -EAFNOSUPPORT;
5695 }
5696
5697 err = nla_parse_nested_deprecated(tb, IFLA_INET6_MAX, nla,
5698 inet6_af_policy, NULL);
5699 if (err)
5700 return err;
5701
5702 if (!tb[IFLA_INET6_TOKEN] && !tb[IFLA_INET6_ADDR_GEN_MODE])
5703 return -EINVAL;
5704
5705 if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
5706 u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]);
5707
5708 if (check_addr_gen_mode(mode) < 0)
5709 return -EINVAL;
5710 if (dev && check_stable_privacy(idev, dev_net(dev), mode) < 0)
5711 return -EINVAL;
5712 }
5713
5714 return 0;
5715}
5716
5696static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) 5717static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
5697{ 5718{
5698 int err = -EINVAL;
5699 struct inet6_dev *idev = __in6_dev_get(dev); 5719 struct inet6_dev *idev = __in6_dev_get(dev);
5700 struct nlattr *tb[IFLA_INET6_MAX + 1]; 5720 struct nlattr *tb[IFLA_INET6_MAX + 1];
5701 5721 int err;
5702 if (!idev)
5703 return -EAFNOSUPPORT;
5704 5722
5705 if (nla_parse_nested_deprecated(tb, IFLA_INET6_MAX, nla, NULL, NULL) < 0) 5723 if (nla_parse_nested_deprecated(tb, IFLA_INET6_MAX, nla, NULL, NULL) < 0)
5706 BUG(); 5724 BUG();
@@ -5714,15 +5732,10 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
5714 if (tb[IFLA_INET6_ADDR_GEN_MODE]) { 5732 if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
5715 u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); 5733 u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]);
5716 5734
5717 if (check_addr_gen_mode(mode) < 0 ||
5718 check_stable_privacy(idev, dev_net(dev), mode) < 0)
5719 return -EINVAL;
5720
5721 idev->cnf.addr_gen_mode = mode; 5735 idev->cnf.addr_gen_mode = mode;
5722 err = 0;
5723 } 5736 }
5724 5737
5725 return err; 5738 return 0;
5726} 5739}
5727 5740
5728static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 5741static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,