Commit 03aef17b authored by Al Viro's avatar Al Viro

devinet_ioctl(): take copyin/copyout to caller

Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 36fd633e
...@@ -173,7 +173,7 @@ static inline struct net_device *ip_dev_find(struct net *net, __be32 addr) ...@@ -173,7 +173,7 @@ static inline struct net_device *ip_dev_find(struct net *net, __be32 addr)
} }
int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *);
void devinet_init(void); void devinet_init(void);
struct in_device *inetdev_by_index(struct net *, int); struct in_device *inetdev_by_index(struct net *, int);
__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope);
......
...@@ -872,6 +872,8 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -872,6 +872,8 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
void __user *p = (void __user *)arg;
struct ifreq ifr;
switch (cmd) { switch (cmd) {
case SIOCGSTAMP: case SIOCGSTAMP:
...@@ -891,17 +893,26 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -891,17 +893,26 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
err = arp_ioctl(net, cmd, (void __user *)arg); err = arp_ioctl(net, cmd, (void __user *)arg);
break; break;
case SIOCGIFADDR: case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFBRDADDR: case SIOCGIFBRDADDR:
case SIOCSIFBRDADDR:
case SIOCGIFNETMASK: case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
case SIOCGIFDSTADDR: case SIOCGIFDSTADDR:
case SIOCGIFPFLAGS:
if (copy_from_user(&ifr, p, sizeof(struct ifreq)))
return -EFAULT;
err = devinet_ioctl(net, cmd, &ifr);
if (!err && copy_to_user(p, &ifr, sizeof(struct ifreq)))
err = -EFAULT;
break;
case SIOCSIFADDR:
case SIOCSIFBRDADDR:
case SIOCSIFNETMASK:
case SIOCSIFDSTADDR: case SIOCSIFDSTADDR:
case SIOCSIFPFLAGS: case SIOCSIFPFLAGS:
case SIOCGIFPFLAGS:
case SIOCSIFFLAGS: case SIOCSIFFLAGS:
err = devinet_ioctl(net, cmd, (void __user *)arg); if (copy_from_user(&ifr, p, sizeof(struct ifreq)))
return -EFAULT;
err = devinet_ioctl(net, cmd, &ifr);
break; break;
default: default:
if (sk->sk_prot->ioctl) if (sk->sk_prot->ioctl)
......
...@@ -946,11 +946,10 @@ static int inet_abc_len(__be32 addr) ...@@ -946,11 +946,10 @@ static int inet_abc_len(__be32 addr)
} }
int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
{ {
struct ifreq ifr;
struct sockaddr_in sin_orig; struct sockaddr_in sin_orig;
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
struct in_device *in_dev; struct in_device *in_dev;
struct in_ifaddr **ifap = NULL; struct in_ifaddr **ifap = NULL;
struct in_ifaddr *ifa = NULL; struct in_ifaddr *ifa = NULL;
...@@ -959,22 +958,16 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -959,22 +958,16 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
int ret = -EFAULT; int ret = -EFAULT;
int tryaddrmatch = 0; int tryaddrmatch = 0;
/* ifr->ifr_name[IFNAMSIZ - 1] = 0;
* Fetch the caller's info block into kernel space
*/
if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
goto out;
ifr.ifr_name[IFNAMSIZ - 1] = 0;
/* save original address for comparison */ /* save original address for comparison */
memcpy(&sin_orig, sin, sizeof(*sin)); memcpy(&sin_orig, sin, sizeof(*sin));
colon = strchr(ifr.ifr_name, ':'); colon = strchr(ifr->ifr_name, ':');
if (colon) if (colon)
*colon = 0; *colon = 0;
dev_load(net, ifr.ifr_name); dev_load(net, ifr->ifr_name);
switch (cmd) { switch (cmd) {
case SIOCGIFADDR: /* Get interface address */ case SIOCGIFADDR: /* Get interface address */
...@@ -1014,7 +1007,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1014,7 +1007,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
rtnl_lock(); rtnl_lock();
ret = -ENODEV; ret = -ENODEV;
dev = __dev_get_by_name(net, ifr.ifr_name); dev = __dev_get_by_name(net, ifr->ifr_name);
if (!dev) if (!dev)
goto done; goto done;
...@@ -1031,7 +1024,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1031,7 +1024,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
This is checked above. */ This is checked above. */
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) { ifap = &ifa->ifa_next) {
if (!strcmp(ifr.ifr_name, ifa->ifa_label) && if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
sin_orig.sin_addr.s_addr == sin_orig.sin_addr.s_addr ==
ifa->ifa_local) { ifa->ifa_local) {
break; /* found */ break; /* found */
...@@ -1044,7 +1037,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1044,7 +1037,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
if (!ifa) { if (!ifa) {
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) ifap = &ifa->ifa_next)
if (!strcmp(ifr.ifr_name, ifa->ifa_label)) if (!strcmp(ifr->ifr_name, ifa->ifa_label))
break; break;
} }
} }
...@@ -1056,19 +1049,19 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1056,19 +1049,19 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
switch (cmd) { switch (cmd) {
case SIOCGIFADDR: /* Get interface address */ case SIOCGIFADDR: /* Get interface address */
sin->sin_addr.s_addr = ifa->ifa_local; sin->sin_addr.s_addr = ifa->ifa_local;
goto rarok; break;
case SIOCGIFBRDADDR: /* Get the broadcast address */ case SIOCGIFBRDADDR: /* Get the broadcast address */
sin->sin_addr.s_addr = ifa->ifa_broadcast; sin->sin_addr.s_addr = ifa->ifa_broadcast;
goto rarok; break;
case SIOCGIFDSTADDR: /* Get the destination address */ case SIOCGIFDSTADDR: /* Get the destination address */
sin->sin_addr.s_addr = ifa->ifa_address; sin->sin_addr.s_addr = ifa->ifa_address;
goto rarok; break;
case SIOCGIFNETMASK: /* Get the netmask for the interface */ case SIOCGIFNETMASK: /* Get the netmask for the interface */
sin->sin_addr.s_addr = ifa->ifa_mask; sin->sin_addr.s_addr = ifa->ifa_mask;
goto rarok; break;
case SIOCSIFFLAGS: case SIOCSIFFLAGS:
if (colon) { if (colon) {
...@@ -1076,11 +1069,11 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1076,11 +1069,11 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
if (!ifa) if (!ifa)
break; break;
ret = 0; ret = 0;
if (!(ifr.ifr_flags & IFF_UP)) if (!(ifr->ifr_flags & IFF_UP))
inet_del_ifa(in_dev, ifap, 1); inet_del_ifa(in_dev, ifap, 1);
break; break;
} }
ret = dev_change_flags(dev, ifr.ifr_flags); ret = dev_change_flags(dev, ifr->ifr_flags);
break; break;
case SIOCSIFADDR: /* Set interface address (and family) */ case SIOCSIFADDR: /* Set interface address (and family) */
...@@ -1095,7 +1088,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1095,7 +1088,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
break; break;
INIT_HLIST_NODE(&ifa->hash); INIT_HLIST_NODE(&ifa->hash);
if (colon) if (colon)
memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ); memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
else else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
} else { } else {
...@@ -1182,10 +1175,6 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1182,10 +1175,6 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
rtnl_unlock(); rtnl_unlock();
out: out:
return ret; return ret;
rarok:
rtnl_unlock();
ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
goto out;
} }
static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size) static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
......
...@@ -329,17 +329,6 @@ set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) ...@@ -329,17 +329,6 @@ set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
sin->sin_port = port; sin->sin_port = port;
} }
static int __init ic_devinet_ioctl(unsigned int cmd, struct ifreq *arg)
{
int res;
mm_segment_t oldfs = get_fs();
set_fs(get_ds());
res = devinet_ioctl(&init_net, cmd, (struct ifreq __user *) arg);
set_fs(oldfs);
return res;
}
static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg)
{ {
int res; int res;
...@@ -375,19 +364,19 @@ static int __init ic_setup_if(void) ...@@ -375,19 +364,19 @@ static int __init ic_setup_if(void)
memset(&ir, 0, sizeof(ir)); memset(&ir, 0, sizeof(ir));
strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->dev->name); strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->dev->name);
set_sockaddr(sin, ic_myaddr, 0); set_sockaddr(sin, ic_myaddr, 0);
if ((err = ic_devinet_ioctl(SIOCSIFADDR, &ir)) < 0) { if ((err = devinet_ioctl(&init_net, SIOCSIFADDR, &ir)) < 0) {
pr_err("IP-Config: Unable to set interface address (%d)\n", pr_err("IP-Config: Unable to set interface address (%d)\n",
err); err);
return -1; return -1;
} }
set_sockaddr(sin, ic_netmask, 0); set_sockaddr(sin, ic_netmask, 0);
if ((err = ic_devinet_ioctl(SIOCSIFNETMASK, &ir)) < 0) { if ((err = devinet_ioctl(&init_net, SIOCSIFNETMASK, &ir)) < 0) {
pr_err("IP-Config: Unable to set interface netmask (%d)\n", pr_err("IP-Config: Unable to set interface netmask (%d)\n",
err); err);
return -1; return -1;
} }
set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0);
if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { if ((err = devinet_ioctl(&init_net, SIOCSIFBRDADDR, &ir)) < 0) {
pr_err("IP-Config: Unable to set interface broadcast address (%d)\n", pr_err("IP-Config: Unable to set interface broadcast address (%d)\n",
err); err);
return -1; return -1;
......
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