Skip to content

Commit

Permalink
Merge branch 'netdev-name'
Browse files Browse the repository at this point in the history
Cong Wang says:

====================
net: forbid net devices named "all" "default" or "config"

/proc/sys/net/ipv[46]/conf/<dev> could conflict with
/proc/sys/net/ipv[46]/conf/(all|default). And /proc/net/vlan/<dev>
could conflict with /proc/net/vlan/config. Besides kernel warnings,
undefined behavior such as duplicated proc files also appears, therefore
we should forbid these names.

v2: introduce a helper function, suggested by Florian
    fix error handling for ipv6_add_dev() in addrconf_init()
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 29, 2014
2 parents 9d7e3ea + 9c5ff24 commit 772e702
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 45 deletions.
6 changes: 6 additions & 0 deletions include/net/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,12 @@ static inline int inet_is_local_reserved_port(struct net *net, int port)
return 0;
return test_bit(port, net->ipv4.sysctl_local_reserved_ports);
}

static inline bool sysctl_dev_name_is_allowed(const char *name)
{
return strcmp(name, "default") != 0 && strcmp(name, "all") != 0;
}

#else
static inline int inet_is_local_reserved_port(struct net *net, int port)
{
Expand Down
21 changes: 13 additions & 8 deletions net/8021q/vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,23 +325,24 @@ static void vlan_transfer_features(struct net_device *dev,
netdev_update_features(vlandev);
}

static void __vlan_device_event(struct net_device *dev, unsigned long event)
static int __vlan_device_event(struct net_device *dev, unsigned long event)
{
int err = 0;

switch (event) {
case NETDEV_CHANGENAME:
vlan_proc_rem_dev(dev);
if (vlan_proc_add_dev(dev) < 0)
pr_warn("failed to change proc name for %s\n",
dev->name);
err = vlan_proc_add_dev(dev);
break;
case NETDEV_REGISTER:
if (vlan_proc_add_dev(dev) < 0)
pr_warn("failed to add proc entry for %s\n", dev->name);
err = vlan_proc_add_dev(dev);
break;
case NETDEV_UNREGISTER:
vlan_proc_rem_dev(dev);
break;
}

return err;
}

static int vlan_device_event(struct notifier_block *unused, unsigned long event,
Expand All @@ -356,8 +357,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
bool last = false;
LIST_HEAD(list);

if (is_vlan_dev(dev))
__vlan_device_event(dev, event);
if (is_vlan_dev(dev)) {
int err = __vlan_device_event(dev, event);

if (err)
return notifier_from_errno(err);
}

if ((event == NETDEV_UP) &&
(dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
Expand Down
2 changes: 2 additions & 0 deletions net/8021q/vlanproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ int vlan_proc_add_dev(struct net_device *vlandev)
struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);

if (!strcmp(vlandev->name, name_conf))
return -EINVAL;
vlan->dent =
proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR,
vn->proc_vlan_dir, &vlandev_fops, vlandev);
Expand Down
36 changes: 27 additions & 9 deletions net/ipv4/devinet.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
int destroy);
#ifdef CONFIG_SYSCTL
static void devinet_sysctl_register(struct in_device *idev);
static int devinet_sysctl_register(struct in_device *idev);
static void devinet_sysctl_unregister(struct in_device *idev);
#else
static void devinet_sysctl_register(struct in_device *idev)
static int devinet_sysctl_register(struct in_device *idev)
{
return 0;
}
static void devinet_sysctl_unregister(struct in_device *idev)
{
Expand Down Expand Up @@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy);
static struct in_device *inetdev_init(struct net_device *dev)
{
struct in_device *in_dev;
int err = -ENOMEM;

ASSERT_RTNL();

Expand All @@ -252,15 +254,21 @@ static struct in_device *inetdev_init(struct net_device *dev)
/* Account for reference dev->ip_ptr (below) */
in_dev_hold(in_dev);

devinet_sysctl_register(in_dev);
err = devinet_sysctl_register(in_dev);
if (err) {
in_dev->dead = 1;
in_dev_put(in_dev);
in_dev = NULL;
goto out;
}
ip_mc_init_dev(in_dev);
if (dev->flags & IFF_UP)
ip_mc_up(in_dev);

/* we can receive as soon as ip_ptr is set -- do this last */
rcu_assign_pointer(dev->ip_ptr, in_dev);
out:
return in_dev;
return in_dev ?: ERR_PTR(err);
out_kfree:
kfree(in_dev);
in_dev = NULL;
Expand Down Expand Up @@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
if (!in_dev) {
if (event == NETDEV_REGISTER) {
in_dev = inetdev_init(dev);
if (!in_dev)
return notifier_from_errno(-ENOMEM);
if (IS_ERR(in_dev))
return notifier_from_errno(PTR_ERR(in_dev));
if (dev->flags & IFF_LOOPBACK) {
IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
Expand Down Expand Up @@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
kfree(t);
}

static void devinet_sysctl_register(struct in_device *idev)
static int devinet_sysctl_register(struct in_device *idev)
{
neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
__devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
int err;

if (!sysctl_dev_name_is_allowed(idev->dev->name))
return -EINVAL;

err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
if (err)
return err;
err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
&idev->cnf);
if (err)
neigh_sysctl_unregister(idev->arp_parms);
return err;
}

static void devinet_sysctl_unregister(struct in_device *idev)
Expand Down
82 changes: 54 additions & 28 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,12 @@ static inline u32 cstamp_delta(unsigned long cstamp)
}

#ifdef CONFIG_SYSCTL
static void addrconf_sysctl_register(struct inet6_dev *idev);
static int addrconf_sysctl_register(struct inet6_dev *idev);
static void addrconf_sysctl_unregister(struct inet6_dev *idev);
#else
static inline void addrconf_sysctl_register(struct inet6_dev *idev)
static inline int addrconf_sysctl_register(struct inet6_dev *idev)
{
return 0;
}

static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
Expand Down Expand Up @@ -310,16 +311,16 @@ static int snmp6_alloc_dev(struct inet6_dev *idev)
static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
{
struct inet6_dev *ndev;
int err = -ENOMEM;

ASSERT_RTNL();

if (dev->mtu < IPV6_MIN_MTU)
return NULL;
return ERR_PTR(-EINVAL);

ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);

if (ndev == NULL)
return NULL;
return ERR_PTR(err);

rwlock_init(&ndev->lock);
ndev->dev = dev;
Expand All @@ -332,7 +333,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
if (ndev->nd_parms == NULL) {
kfree(ndev);
return NULL;
return ERR_PTR(err);
}
if (ndev->cnf.forwarding)
dev_disable_lro(dev);
Expand All @@ -346,17 +347,14 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
neigh_parms_release(&nd_tbl, ndev->nd_parms);
dev_put(dev);
kfree(ndev);
return NULL;
return ERR_PTR(err);
}

if (snmp6_register_dev(ndev) < 0) {
ADBG(KERN_WARNING
"%s: cannot create /proc/net/dev_snmp6/%s\n",
__func__, dev->name);
neigh_parms_release(&nd_tbl, ndev->nd_parms);
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
return NULL;
goto err_release;
}

/* One reference from device. We must do this before
Expand Down Expand Up @@ -394,7 +392,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)

ipv6_mc_init_dev(ndev);
ndev->tstamp = jiffies;
addrconf_sysctl_register(ndev);
err = addrconf_sysctl_register(ndev);
if (err) {
ipv6_mc_destroy_dev(ndev);
del_timer(&ndev->regen_timer);
goto err_release;
}
/* protected by rtnl_lock */
rcu_assign_pointer(dev->ip6_ptr, ndev);

Expand All @@ -409,6 +412,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);

return ndev;

err_release:
neigh_parms_release(&nd_tbl, ndev->nd_parms);
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
return ERR_PTR(err);
}

static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
Expand All @@ -420,7 +429,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
idev = __in6_dev_get(dev);
if (!idev) {
idev = ipv6_add_dev(dev);
if (!idev)
if (IS_ERR(idev))
return NULL;
}

Expand Down Expand Up @@ -2830,8 +2839,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
case NETDEV_REGISTER:
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
idev = ipv6_add_dev(dev);
if (!idev)
return notifier_from_errno(-ENOMEM);
if (IS_ERR(idev))
return notifier_from_errno(PTR_ERR(idev));
}
break;

Expand All @@ -2851,7 +2860,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
if (!idev && dev->mtu >= IPV6_MIN_MTU)
idev = ipv6_add_dev(dev);

if (idev) {
if (!IS_ERR_OR_NULL(idev)) {
idev->if_flags |= IF_READY;
run_pending = 1;
}
Expand Down Expand Up @@ -2894,7 +2903,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
break;
}

if (idev) {
if (!IS_ERR_OR_NULL(idev)) {
if (run_pending)
addrconf_dad_run(idev);

Expand Down Expand Up @@ -2929,7 +2938,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,

if (!idev && dev->mtu >= IPV6_MIN_MTU) {
idev = ipv6_add_dev(dev);
if (idev)
if (!IS_ERR(idev))
break;
}

Expand All @@ -2950,10 +2959,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
if (idev) {
snmp6_unregister_dev(idev);
addrconf_sysctl_unregister(idev);
addrconf_sysctl_register(idev);
err = snmp6_register_dev(idev);
err = addrconf_sysctl_register(idev);
if (err)
return notifier_from_errno(err);
err = snmp6_register_dev(idev);
if (err) {
addrconf_sysctl_unregister(idev);
return notifier_from_errno(err);
}
}
break;

Expand Down Expand Up @@ -5248,12 +5261,23 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
kfree(t);
}

static void addrconf_sysctl_register(struct inet6_dev *idev)
static int addrconf_sysctl_register(struct inet6_dev *idev)
{
neigh_sysctl_register(idev->dev, idev->nd_parms,
&ndisc_ifinfo_sysctl_change);
__addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
idev, &idev->cnf);
int err;

if (!sysctl_dev_name_is_allowed(idev->dev->name))
return -EINVAL;

err = neigh_sysctl_register(idev->dev, idev->nd_parms,
&ndisc_ifinfo_sysctl_change);
if (err)
return err;
err = __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
idev, &idev->cnf);
if (err)
neigh_sysctl_unregister(idev->nd_parms);

return err;
}

static void addrconf_sysctl_unregister(struct inet6_dev *idev)
Expand Down Expand Up @@ -5338,6 +5362,7 @@ static struct rtnl_af_ops inet6_ops = {

int __init addrconf_init(void)
{
struct inet6_dev *idev;
int i, err;

err = ipv6_addr_label_init();
Expand Down Expand Up @@ -5376,11 +5401,12 @@ int __init addrconf_init(void)
* device and it being up should be removed.
*/
rtnl_lock();
if (!ipv6_add_dev(init_net.loopback_dev))
err = -ENOMEM;
idev = ipv6_add_dev(init_net.loopback_dev);
rtnl_unlock();
if (err)
if (IS_ERR(idev)) {
err = PTR_ERR(idev);
goto errlo;
}

for (i = 0; i < IN6_ADDR_HSIZE; i++)
INIT_HLIST_HEAD(&inet6_addr_lst[i]);
Expand Down

0 comments on commit 772e702

Please sign in to comment.