diff options
-rw-r--r-- | include/net/ip.h | 6 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 36 |
2 files changed, 33 insertions, 9 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index ca14799545fd..09b32da1b929 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -216,6 +216,12 @@ static inline int inet_is_local_reserved_port(struct net *net, int port) | |||
216 | return 0; | 216 | return 0; |
217 | return test_bit(port, net->ipv4.sysctl_local_reserved_ports); | 217 | return test_bit(port, net->ipv4.sysctl_local_reserved_ports); |
218 | } | 218 | } |
219 | |||
220 | static inline bool sysctl_dev_name_is_allowed(const char *name) | ||
221 | { | ||
222 | return strcmp(name, "default") != 0 && strcmp(name, "all") != 0; | ||
223 | } | ||
224 | |||
219 | #else | 225 | #else |
220 | static inline int inet_is_local_reserved_port(struct net *net, int port) | 226 | static inline int inet_is_local_reserved_port(struct net *net, int port) |
221 | { | 227 | { |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e9449376b58e..214882e7d6de 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); | |||
180 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 180 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
181 | int destroy); | 181 | int destroy); |
182 | #ifdef CONFIG_SYSCTL | 182 | #ifdef CONFIG_SYSCTL |
183 | static void devinet_sysctl_register(struct in_device *idev); | 183 | static int devinet_sysctl_register(struct in_device *idev); |
184 | static void devinet_sysctl_unregister(struct in_device *idev); | 184 | static void devinet_sysctl_unregister(struct in_device *idev); |
185 | #else | 185 | #else |
186 | static void devinet_sysctl_register(struct in_device *idev) | 186 | static int devinet_sysctl_register(struct in_device *idev) |
187 | { | 187 | { |
188 | return 0; | ||
188 | } | 189 | } |
189 | static void devinet_sysctl_unregister(struct in_device *idev) | 190 | static void devinet_sysctl_unregister(struct in_device *idev) |
190 | { | 191 | { |
@@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy); | |||
232 | static struct in_device *inetdev_init(struct net_device *dev) | 233 | static struct in_device *inetdev_init(struct net_device *dev) |
233 | { | 234 | { |
234 | struct in_device *in_dev; | 235 | struct in_device *in_dev; |
236 | int err = -ENOMEM; | ||
235 | 237 | ||
236 | ASSERT_RTNL(); | 238 | ASSERT_RTNL(); |
237 | 239 | ||
@@ -252,7 +254,13 @@ static struct in_device *inetdev_init(struct net_device *dev) | |||
252 | /* Account for reference dev->ip_ptr (below) */ | 254 | /* Account for reference dev->ip_ptr (below) */ |
253 | in_dev_hold(in_dev); | 255 | in_dev_hold(in_dev); |
254 | 256 | ||
255 | devinet_sysctl_register(in_dev); | 257 | err = devinet_sysctl_register(in_dev); |
258 | if (err) { | ||
259 | in_dev->dead = 1; | ||
260 | in_dev_put(in_dev); | ||
261 | in_dev = NULL; | ||
262 | goto out; | ||
263 | } | ||
256 | ip_mc_init_dev(in_dev); | 264 | ip_mc_init_dev(in_dev); |
257 | if (dev->flags & IFF_UP) | 265 | if (dev->flags & IFF_UP) |
258 | ip_mc_up(in_dev); | 266 | ip_mc_up(in_dev); |
@@ -260,7 +268,7 @@ static struct in_device *inetdev_init(struct net_device *dev) | |||
260 | /* we can receive as soon as ip_ptr is set -- do this last */ | 268 | /* we can receive as soon as ip_ptr is set -- do this last */ |
261 | rcu_assign_pointer(dev->ip_ptr, in_dev); | 269 | rcu_assign_pointer(dev->ip_ptr, in_dev); |
262 | out: | 270 | out: |
263 | return in_dev; | 271 | return in_dev ?: ERR_PTR(err); |
264 | out_kfree: | 272 | out_kfree: |
265 | kfree(in_dev); | 273 | kfree(in_dev); |
266 | in_dev = NULL; | 274 | in_dev = NULL; |
@@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, | |||
1347 | if (!in_dev) { | 1355 | if (!in_dev) { |
1348 | if (event == NETDEV_REGISTER) { | 1356 | if (event == NETDEV_REGISTER) { |
1349 | in_dev = inetdev_init(dev); | 1357 | in_dev = inetdev_init(dev); |
1350 | if (!in_dev) | 1358 | if (IS_ERR(in_dev)) |
1351 | return notifier_from_errno(-ENOMEM); | 1359 | return notifier_from_errno(PTR_ERR(in_dev)); |
1352 | if (dev->flags & IFF_LOOPBACK) { | 1360 | if (dev->flags & IFF_LOOPBACK) { |
1353 | IN_DEV_CONF_SET(in_dev, NOXFRM, 1); | 1361 | IN_DEV_CONF_SET(in_dev, NOXFRM, 1); |
1354 | IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); | 1362 | IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); |
@@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) | |||
2182 | kfree(t); | 2190 | kfree(t); |
2183 | } | 2191 | } |
2184 | 2192 | ||
2185 | static void devinet_sysctl_register(struct in_device *idev) | 2193 | static int devinet_sysctl_register(struct in_device *idev) |
2186 | { | 2194 | { |
2187 | neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); | 2195 | int err; |
2188 | __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, | 2196 | |
2197 | if (!sysctl_dev_name_is_allowed(idev->dev->name)) | ||
2198 | return -EINVAL; | ||
2199 | |||
2200 | err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); | ||
2201 | if (err) | ||
2202 | return err; | ||
2203 | err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, | ||
2189 | &idev->cnf); | 2204 | &idev->cnf); |
2205 | if (err) | ||
2206 | neigh_sysctl_unregister(idev->arp_parms); | ||
2207 | return err; | ||
2190 | } | 2208 | } |
2191 | 2209 | ||
2192 | static void devinet_sysctl_unregister(struct in_device *idev) | 2210 | static void devinet_sysctl_unregister(struct in_device *idev) |