mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-05 14:04:35 +00:00
devinet_ioctl(): take copyin/copyout to caller
Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
36fd633ec9
commit
03aef17bb7
4 changed files with 35 additions and 46 deletions
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ done:
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue