Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 772e7023 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'netdev-name'



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: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d7e3ea7 9c5ff24f
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -216,6 +216,12 @@ static inline int inet_is_local_reserved_port(struct net *net, int port)
		return 0;
		return 0;
	return test_bit(port, net->ipv4.sysctl_local_reserved_ports);
	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
#else
static inline int inet_is_local_reserved_port(struct net *net, int port)
static inline int inet_is_local_reserved_port(struct net *net, int port)
{
{
+13 −8
Original line number Original line Diff line number Diff line
@@ -325,23 +325,24 @@ static void vlan_transfer_features(struct net_device *dev,
	netdev_update_features(vlandev);
	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) {
	switch (event) {
	case NETDEV_CHANGENAME:
	case NETDEV_CHANGENAME:
		vlan_proc_rem_dev(dev);
		vlan_proc_rem_dev(dev);
		if (vlan_proc_add_dev(dev) < 0)
		err = vlan_proc_add_dev(dev);
			pr_warn("failed to change proc name for %s\n",
				dev->name);
		break;
		break;
	case NETDEV_REGISTER:
	case NETDEV_REGISTER:
		if (vlan_proc_add_dev(dev) < 0)
		err = vlan_proc_add_dev(dev);
			pr_warn("failed to add proc entry for %s\n", dev->name);
		break;
		break;
	case NETDEV_UNREGISTER:
	case NETDEV_UNREGISTER:
		vlan_proc_rem_dev(dev);
		vlan_proc_rem_dev(dev);
		break;
		break;
	}
	}

	return err;
}
}


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


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

		if (err)
			return notifier_from_errno(err);
	}


	if ((event == NETDEV_UP) &&
	if ((event == NETDEV_UP) &&
	    (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
	    (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
+2 −0
Original line number Original line Diff line number Diff line
@@ -171,6 +171,8 @@ int vlan_proc_add_dev(struct net_device *vlandev)
	struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
	struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
	struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
	struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);


	if (!strcmp(vlandev->name, name_conf))
		return -EINVAL;
	vlan->dent =
	vlan->dent =
		proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR,
		proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR,
				 vn->proc_vlan_dir, &vlandev_fops, vlandev);
				 vn->proc_vlan_dir, &vlandev_fops, vlandev);
+27 −9
Original line number Original line Diff line number Diff line
@@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
			 int destroy);
			 int destroy);
#ifdef CONFIG_SYSCTL
#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);
static void devinet_sysctl_unregister(struct in_device *idev);
#else
#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)
static void devinet_sysctl_unregister(struct in_device *idev)
{
{
@@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy);
static struct in_device *inetdev_init(struct net_device *dev)
static struct in_device *inetdev_init(struct net_device *dev)
{
{
	struct in_device *in_dev;
	struct in_device *in_dev;
	int err = -ENOMEM;


	ASSERT_RTNL();
	ASSERT_RTNL();


@@ -252,7 +254,13 @@ static struct in_device *inetdev_init(struct net_device *dev)
	/* Account for reference dev->ip_ptr (below) */
	/* Account for reference dev->ip_ptr (below) */
	in_dev_hold(in_dev);
	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);
	ip_mc_init_dev(in_dev);
	if (dev->flags & IFF_UP)
	if (dev->flags & IFF_UP)
		ip_mc_up(in_dev);
		ip_mc_up(in_dev);
@@ -260,7 +268,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
	/* we can receive as soon as ip_ptr is set -- do this last */
	/* we can receive as soon as ip_ptr is set -- do this last */
	rcu_assign_pointer(dev->ip_ptr, in_dev);
	rcu_assign_pointer(dev->ip_ptr, in_dev);
out:
out:
	return in_dev;
	return in_dev ?: ERR_PTR(err);
out_kfree:
out_kfree:
	kfree(in_dev);
	kfree(in_dev);
	in_dev = NULL;
	in_dev = NULL;
@@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
	if (!in_dev) {
	if (!in_dev) {
		if (event == NETDEV_REGISTER) {
		if (event == NETDEV_REGISTER) {
			in_dev = inetdev_init(dev);
			in_dev = inetdev_init(dev);
			if (!in_dev)
			if (IS_ERR(in_dev))
				return notifier_from_errno(-ENOMEM);
				return notifier_from_errno(PTR_ERR(in_dev));
			if (dev->flags & IFF_LOOPBACK) {
			if (dev->flags & IFF_LOOPBACK) {
				IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
				IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
				IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
				IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
@@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
	kfree(t);
	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);
	int err;
	__devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,

	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);
					&idev->cnf);
	if (err)
		neigh_sysctl_unregister(idev->arp_parms);
	return err;
}
}


static void devinet_sysctl_unregister(struct in_device *idev)
static void devinet_sysctl_unregister(struct in_device *idev)
+54 −28
Original line number Original line Diff line number Diff line
@@ -108,11 +108,12 @@ static inline u32 cstamp_delta(unsigned long cstamp)
}
}


#ifdef CONFIG_SYSCTL
#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);
static void addrconf_sysctl_unregister(struct inet6_dev *idev);
#else
#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)
static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
@@ -310,16 +311,16 @@ err_ip:
static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
{
{
	struct inet6_dev *ndev;
	struct inet6_dev *ndev;
	int err = -ENOMEM;


	ASSERT_RTNL();
	ASSERT_RTNL();


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


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

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


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


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


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


	ipv6_mc_init_dev(ndev);
	ipv6_mc_init_dev(ndev);
	ndev->tstamp = jiffies;
	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 */
	/* protected by rtnl_lock */
	rcu_assign_pointer(dev->ip6_ptr, ndev);
	rcu_assign_pointer(dev->ip6_ptr, ndev);


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


	return ndev;
	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)
static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
@@ -420,7 +429,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
	idev = __in6_dev_get(dev);
	idev = __in6_dev_get(dev);
	if (!idev) {
	if (!idev) {
		idev = ipv6_add_dev(dev);
		idev = ipv6_add_dev(dev);
		if (!idev)
		if (IS_ERR(idev))
			return NULL;
			return NULL;
	}
	}


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


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


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


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


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


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


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


@@ -5248,12 +5261,23 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
	kfree(t);
	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,
	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);
				    &ndisc_ifinfo_sysctl_change);
	__addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
	if (err)
		return err;
	err = __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
					 idev, &idev->cnf);
					 idev, &idev->cnf);
	if (err)
		neigh_sysctl_unregister(idev->nd_parms);

	return err;
}
}


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


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


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


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