Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv4: fail early when creating netdev named all or default

We create a proc dir for each network device, this will cause
conflicts when the devices have name "all" or "default".

Rather than emitting an ugly kernel warning, we could just
fail earlier by checking the device name.

Reported-by: Stephane Chazelas <stephane.chazelas@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

WANG Cong and committed by
David S. Miller
20e61da7 9d7e3ea7

+33 -9
+6
include/net/ip.h
··· 216 216 return 0; 217 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 225 #else 220 226 static inline int inet_is_local_reserved_port(struct net *net, int port) 221 227 {
+27 -9
net/ipv4/devinet.c
··· 180 180 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, 181 181 int destroy); 182 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 184 static void devinet_sysctl_unregister(struct in_device *idev); 185 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 190 static void devinet_sysctl_unregister(struct in_device *idev) 190 191 { ··· 233 232 static struct in_device *inetdev_init(struct net_device *dev) 234 233 { 235 234 struct in_device *in_dev; 235 + int err = -ENOMEM; 236 236 237 237 ASSERT_RTNL(); 238 238 ··· 254 252 /* Account for reference dev->ip_ptr (below) */ 255 253 in_dev_hold(in_dev); 256 254 257 - devinet_sysctl_register(in_dev); 255 + err = devinet_sysctl_register(in_dev); 256 + if (err) { 257 + in_dev->dead = 1; 258 + in_dev_put(in_dev); 259 + in_dev = NULL; 260 + goto out; 261 + } 258 262 ip_mc_init_dev(in_dev); 259 263 if (dev->flags & IFF_UP) 260 264 ip_mc_up(in_dev); ··· 268 260 /* we can receive as soon as ip_ptr is set -- do this last */ 269 261 rcu_assign_pointer(dev->ip_ptr, in_dev); 270 262 out: 271 - return in_dev; 263 + return in_dev ?: ERR_PTR(err); 272 264 out_kfree: 273 265 kfree(in_dev); 274 266 in_dev = NULL; ··· 1355 1347 if (!in_dev) { 1356 1348 if (event == NETDEV_REGISTER) { 1357 1349 in_dev = inetdev_init(dev); 1358 - if (!in_dev) 1359 - return notifier_from_errno(-ENOMEM); 1350 + if (IS_ERR(in_dev)) 1351 + return notifier_from_errno(PTR_ERR(in_dev)); 1360 1352 if (dev->flags & IFF_LOOPBACK) { 1361 1353 IN_DEV_CONF_SET(in_dev, NOXFRM, 1); 1362 1354 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); ··· 2190 2182 kfree(t); 2191 2183 } 2192 2184 2193 - static void devinet_sysctl_register(struct in_device *idev) 2185 + static int devinet_sysctl_register(struct in_device *idev) 2194 2186 { 2195 - neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); 2196 - __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, 2187 + int err; 2188 + 2189 + if (!sysctl_dev_name_is_allowed(idev->dev->name)) 2190 + return -EINVAL; 2191 + 2192 + err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); 2193 + if (err) 2194 + return err; 2195 + err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, 2197 2196 &idev->cnf); 2197 + if (err) 2198 + neigh_sysctl_unregister(idev->arp_parms); 2199 + return err; 2198 2200 } 2199 2201 2200 2202 static void devinet_sysctl_unregister(struct in_device *idev)