Commit a937e1e4 authored by Stephen Hemminger's avatar Stephen Hemminger

[NET]: Add SIOCSIGNAME wildcarding and name validation, with help from Jean Tourrilhes.

parent 424e8db5
...@@ -620,6 +620,21 @@ struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short ma ...@@ -620,6 +620,21 @@ struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short ma
return NULL; return NULL;
} }
/**
* dev_valid_name - check if name is okay for network device
* @name: name string
*
* Network device names need to be valid file names to
* to allow sysfs to work
*/
int dev_valid_name(const char *name)
{
return !(*name == '\0'
|| !strcmp(name, ".")
|| !strcmp(name, "..")
|| strchr(name, '/'));
}
/** /**
* dev_alloc_name - allocate a name for a device * dev_alloc_name - allocate a name for a device
* @dev: device * @dev: device
...@@ -660,6 +675,41 @@ int dev_alloc_name(struct net_device *dev, const char *name) ...@@ -660,6 +675,41 @@ int dev_alloc_name(struct net_device *dev, const char *name)
return -ENFILE; /* Over 100 of the things .. bail out! */ return -ENFILE; /* Over 100 of the things .. bail out! */
} }
/**
* dev_change_name - change name of a device
* @dev: device
* @name: name (or format string) must be at least IFNAMSIZ
*
* Change name of a device, can pass format strings "eth%d".
* for wildcarding.
*/
int dev_change_name(struct net_device *dev, char *newname)
{
ASSERT_RTNL();
if (dev->flags & IFF_UP)
return -EBUSY;
if (!dev_valid_name(newname))
return -EINVAL;
if (strchr(newname, '%')) {
int err = dev_alloc_name(dev, newname);
if (err)
return err;
strcpy(newname, dev->name);
}
else if (__dev_get_by_name(newname))
return -EEXIST;
else
strlcpy(dev->name, newname, IFNAMSIZ);
class_device_rename(&dev->class_dev, dev->name);
notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
return 0;
}
/** /**
* dev_alloc - allocate a network device and name * dev_alloc - allocate a network device and name
* @name: name format string * @name: name format string
...@@ -2341,20 +2391,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) ...@@ -2341,20 +2391,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
return 0; return 0;
case SIOCSIFNAME: case SIOCSIFNAME:
if (dev->flags & IFF_UP)
return -EBUSY;
ifr->ifr_newname[IFNAMSIZ-1] = '\0'; ifr->ifr_newname[IFNAMSIZ-1] = '\0';
if (__dev_get_by_name(ifr->ifr_newname)) return dev_change_name(dev, ifr->ifr_newname);
return -EEXIST;
err = class_device_rename(&dev->class_dev,
ifr->ifr_newname);
if (!err) {
strlcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);
notifier_call_chain(&netdev_chain,
NETDEV_CHANGENAME, dev);
}
return err;
/* /*
* Unknown or private ioctl * Unknown or private ioctl
...@@ -2487,6 +2525,7 @@ int dev_ioctl(unsigned int cmd, void *arg) ...@@ -2487,6 +2525,7 @@ int dev_ioctl(unsigned int cmd, void *arg)
*/ */
case SIOCGMIIPHY: case SIOCGMIIPHY:
case SIOCGMIIREG: case SIOCGMIIREG:
case SIOCSIFNAME:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
dev_load(ifr.ifr_name); dev_load(ifr.ifr_name);
...@@ -2518,7 +2557,6 @@ int dev_ioctl(unsigned int cmd, void *arg) ...@@ -2518,7 +2557,6 @@ int dev_ioctl(unsigned int cmd, void *arg)
case SIOCDELMULTI: case SIOCDELMULTI:
case SIOCSIFHWBROADCAST: case SIOCSIFHWBROADCAST:
case SIOCSIFTXQLEN: case SIOCSIFTXQLEN:
case SIOCSIFNAME:
case SIOCSMIIREG: case SIOCSMIIREG:
case SIOCBONDENSLAVE: case SIOCBONDENSLAVE:
case SIOCBONDRELEASE: case SIOCBONDRELEASE:
...@@ -2669,6 +2707,11 @@ int register_netdevice(struct net_device *dev) ...@@ -2669,6 +2707,11 @@ int register_netdevice(struct net_device *dev)
} }
} }
if (!dev_valid_name(dev->name)) {
ret = -EINVAL;
goto out_err;
}
dev->ifindex = dev_new_index(); dev->ifindex = dev_new_index();
if (dev->iflink == -1) if (dev->iflink == -1)
dev->iflink = dev->ifindex; dev->iflink = dev->ifindex;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment