summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/core/rtnetlink.c62
-rw-r--r--net/ipv4/devinet.c4
2 files changed, 48 insertions, 18 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a49cad25e577..20b550d07fe3 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -453,7 +453,7 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family)
453{ 453{
454 const struct rtnl_af_ops *ops; 454 const struct rtnl_af_ops *ops;
455 455
456 list_for_each_entry(ops, &rtnl_af_ops, list) { 456 list_for_each_entry_rcu(ops, &rtnl_af_ops, list) {
457 if (ops->family == family) 457 if (ops->family == family)
458 return ops; 458 return ops;
459 } 459 }
@@ -470,7 +470,7 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family)
470void rtnl_af_register(struct rtnl_af_ops *ops) 470void rtnl_af_register(struct rtnl_af_ops *ops)
471{ 471{
472 rtnl_lock(); 472 rtnl_lock();
473 list_add_tail(&ops->list, &rtnl_af_ops); 473 list_add_tail_rcu(&ops->list, &rtnl_af_ops);
474 rtnl_unlock(); 474 rtnl_unlock();
475} 475}
476EXPORT_SYMBOL_GPL(rtnl_af_register); 476EXPORT_SYMBOL_GPL(rtnl_af_register);
@@ -482,8 +482,10 @@ EXPORT_SYMBOL_GPL(rtnl_af_register);
482void rtnl_af_unregister(struct rtnl_af_ops *ops) 482void rtnl_af_unregister(struct rtnl_af_ops *ops)
483{ 483{
484 rtnl_lock(); 484 rtnl_lock();
485 list_del(&ops->list); 485 list_del_rcu(&ops->list);
486 rtnl_unlock(); 486 rtnl_unlock();
487
488 synchronize_rcu();
487} 489}
488EXPORT_SYMBOL_GPL(rtnl_af_unregister); 490EXPORT_SYMBOL_GPL(rtnl_af_unregister);
489 491
@@ -496,13 +498,15 @@ static size_t rtnl_link_get_af_size(const struct net_device *dev,
496 /* IFLA_AF_SPEC */ 498 /* IFLA_AF_SPEC */
497 size = nla_total_size(sizeof(struct nlattr)); 499 size = nla_total_size(sizeof(struct nlattr));
498 500
499 list_for_each_entry(af_ops, &rtnl_af_ops, list) { 501 rcu_read_lock();
502 list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) {
500 if (af_ops->get_link_af_size) { 503 if (af_ops->get_link_af_size) {
501 /* AF_* + nested data */ 504 /* AF_* + nested data */
502 size += nla_total_size(sizeof(struct nlattr)) + 505 size += nla_total_size(sizeof(struct nlattr)) +
503 af_ops->get_link_af_size(dev, ext_filter_mask); 506 af_ops->get_link_af_size(dev, ext_filter_mask);
504 } 507 }
505 } 508 }
509 rcu_read_unlock();
506 510
507 return size; 511 return size;
508} 512}
@@ -1393,7 +1397,7 @@ static int rtnl_fill_link_af(struct sk_buff *skb,
1393 if (!af_spec) 1397 if (!af_spec)
1394 return -EMSGSIZE; 1398 return -EMSGSIZE;
1395 1399
1396 list_for_each_entry(af_ops, &rtnl_af_ops, list) { 1400 list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) {
1397 struct nlattr *af; 1401 struct nlattr *af;
1398 int err; 1402 int err;
1399 1403
@@ -1516,12 +1520,16 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
1516 nla_put_s32(skb, IFLA_NEW_NETNSID, *new_nsid) < 0) 1520 nla_put_s32(skb, IFLA_NEW_NETNSID, *new_nsid) < 0)
1517 goto nla_put_failure; 1521 goto nla_put_failure;
1518 1522
1523 rcu_read_lock();
1519 if (rtnl_fill_link_af(skb, dev, ext_filter_mask)) 1524 if (rtnl_fill_link_af(skb, dev, ext_filter_mask))
1520 goto nla_put_failure; 1525 goto nla_put_failure_rcu;
1526 rcu_read_unlock();
1521 1527
1522 nlmsg_end(skb, nlh); 1528 nlmsg_end(skb, nlh);
1523 return 0; 1529 return 0;
1524 1530
1531nla_put_failure_rcu:
1532 rcu_read_unlock();
1525nla_put_failure: 1533nla_put_failure:
1526 nlmsg_cancel(skb, nlh); 1534 nlmsg_cancel(skb, nlh);
1527 return -EMSGSIZE; 1535 return -EMSGSIZE;
@@ -1783,17 +1791,27 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
1783 nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { 1791 nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
1784 const struct rtnl_af_ops *af_ops; 1792 const struct rtnl_af_ops *af_ops;
1785 1793
1786 if (!(af_ops = rtnl_af_lookup(nla_type(af)))) 1794 rcu_read_lock();
1795 af_ops = rtnl_af_lookup(nla_type(af));
1796 if (!af_ops) {
1797 rcu_read_unlock();
1787 return -EAFNOSUPPORT; 1798 return -EAFNOSUPPORT;
1799 }
1788 1800
1789 if (!af_ops->set_link_af) 1801 if (!af_ops->set_link_af) {
1802 rcu_read_unlock();
1790 return -EOPNOTSUPP; 1803 return -EOPNOTSUPP;
1804 }
1791 1805
1792 if (af_ops->validate_link_af) { 1806 if (af_ops->validate_link_af) {
1793 err = af_ops->validate_link_af(dev, af); 1807 err = af_ops->validate_link_af(dev, af);
1794 if (err < 0) 1808 if (err < 0) {
1809 rcu_read_unlock();
1795 return err; 1810 return err;
1811 }
1796 } 1812 }
1813
1814 rcu_read_unlock();
1797 } 1815 }
1798 } 1816 }
1799 1817
@@ -2251,13 +2269,18 @@ static int do_setlink(const struct sk_buff *skb,
2251 nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { 2269 nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
2252 const struct rtnl_af_ops *af_ops; 2270 const struct rtnl_af_ops *af_ops;
2253 2271
2272 rcu_read_lock();
2273
2254 if (!(af_ops = rtnl_af_lookup(nla_type(af)))) 2274 if (!(af_ops = rtnl_af_lookup(nla_type(af))))
2255 BUG(); 2275 BUG();
2256 2276
2257 err = af_ops->set_link_af(dev, af); 2277 err = af_ops->set_link_af(dev, af);
2258 if (err < 0) 2278 if (err < 0) {
2279 rcu_read_unlock();
2259 goto errout; 2280 goto errout;
2281 }
2260 2282
2283 rcu_read_unlock();
2261 status |= DO_SETLINK_NOTIFY; 2284 status |= DO_SETLINK_NOTIFY;
2262 } 2285 }
2263 } 2286 }
@@ -4004,25 +4027,30 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev,
4004 if (!attr) 4027 if (!attr)
4005 goto nla_put_failure; 4028 goto nla_put_failure;
4006 4029
4007 list_for_each_entry(af_ops, &rtnl_af_ops, list) { 4030 rcu_read_lock();
4031 list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) {
4008 if (af_ops->fill_stats_af) { 4032 if (af_ops->fill_stats_af) {
4009 struct nlattr *af; 4033 struct nlattr *af;
4010 int err; 4034 int err;
4011 4035
4012 af = nla_nest_start(skb, af_ops->family); 4036 af = nla_nest_start(skb, af_ops->family);
4013 if (!af) 4037 if (!af) {
4038 rcu_read_unlock();
4014 goto nla_put_failure; 4039 goto nla_put_failure;
4015 4040 }
4016 err = af_ops->fill_stats_af(skb, dev); 4041 err = af_ops->fill_stats_af(skb, dev);
4017 4042
4018 if (err == -ENODATA) 4043 if (err == -ENODATA) {
4019 nla_nest_cancel(skb, af); 4044 nla_nest_cancel(skb, af);
4020 else if (err < 0) 4045 } else if (err < 0) {
4046 rcu_read_unlock();
4021 goto nla_put_failure; 4047 goto nla_put_failure;
4048 }
4022 4049
4023 nla_nest_end(skb, af); 4050 nla_nest_end(skb, af);
4024 } 4051 }
4025 } 4052 }
4053 rcu_read_unlock();
4026 4054
4027 nla_nest_end(skb, attr); 4055 nla_nest_end(skb, attr);
4028 4056
@@ -4091,7 +4119,8 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev,
4091 /* for IFLA_STATS_AF_SPEC */ 4119 /* for IFLA_STATS_AF_SPEC */
4092 size += nla_total_size(0); 4120 size += nla_total_size(0);
4093 4121
4094 list_for_each_entry(af_ops, &rtnl_af_ops, list) { 4122 rcu_read_lock();
4123 list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) {
4095 if (af_ops->get_stats_af_size) { 4124 if (af_ops->get_stats_af_size) {
4096 size += nla_total_size( 4125 size += nla_total_size(
4097 af_ops->get_stats_af_size(dev)); 4126 af_ops->get_stats_af_size(dev));
@@ -4100,6 +4129,7 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev,
4100 size += nla_total_size(0); 4129 size += nla_total_size(0);
4101 } 4130 }
4102 } 4131 }
4132 rcu_read_unlock();
4103 } 4133 }
4104 4134
4105 return size; 4135 return size;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 7ce22a2c07ce..6d9b072d903b 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1757,7 +1757,7 @@ static int inet_validate_link_af(const struct net_device *dev,
1757 struct nlattr *a, *tb[IFLA_INET_MAX+1]; 1757 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1758 int err, rem; 1758 int err, rem;
1759 1759
1760 if (dev && !__in_dev_get_rtnl(dev)) 1760 if (dev && !__in_dev_get_rcu(dev))
1761 return -EAFNOSUPPORT; 1761 return -EAFNOSUPPORT;
1762 1762
1763 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL); 1763 err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL);
@@ -1781,7 +1781,7 @@ static int inet_validate_link_af(const struct net_device *dev,
1781 1781
1782static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla) 1782static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
1783{ 1783{
1784 struct in_device *in_dev = __in_dev_get_rtnl(dev); 1784 struct in_device *in_dev = __in_dev_get_rcu(dev);
1785 struct nlattr *a, *tb[IFLA_INET_MAX+1]; 1785 struct nlattr *a, *tb[IFLA_INET_MAX+1];
1786 int rem; 1786 int rem;
1787 1787