Skip to content

Commit

Permalink
Merge branch 'rebased-net-ioctl' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/viro/vfs

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jan 25, 2018
2 parents 955bd1d + 5c59e56 commit 8ec59b4
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 399 deletions.
2 changes: 1 addition & 1 deletion include/linux/inetdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 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);
struct in_device *inetdev_by_index(struct net *, int);
__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope);
Expand Down
1 change: 0 additions & 1 deletion include/linux/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
size_t size, int flags);
int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
size_t size, int flags);
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);

/* Routine returns the IP overhead imposed by a (caller-protected) socket. */
Expand Down
7 changes: 5 additions & 2 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -2761,7 +2761,8 @@ static inline bool dev_validate_header(const struct net_device *dev,
return false;
}

typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr,
int len, int size);
int register_gifconf(unsigned int family, gifconf_func_t *gifconf);
static inline int unregister_gifconf(unsigned int family)
{
Expand Down Expand Up @@ -3314,7 +3315,9 @@ int netdev_rx_handler_register(struct net_device *dev,
void netdev_rx_handler_unregister(struct net_device *dev);

bool dev_valid_name(const char *name);
int dev_ioctl(struct net *net, unsigned int cmd, void __user *);
int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
bool *need_copyout);
int dev_ifconf(struct net *net, struct ifconf *, int);
int dev_ethtool(struct net *net, struct ifreq *);
unsigned int dev_get_flags(const struct net_device *);
int __dev_change_flags(struct net_device *, unsigned int flags);
Expand Down
2 changes: 1 addition & 1 deletion include/net/route.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ unsigned int inet_addr_type_dev_table(struct net *net,
const struct net_device *dev,
__be32 addr);
void ip_rt_multicast_event(struct in_device *);
int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
int ip_rt_ioctl(struct net *, unsigned int cmd, struct rtentry *rt);
void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
struct rtable *rt_dst_alloc(struct net_device *dev,
unsigned int flags, u16 type,
Expand Down
4 changes: 2 additions & 2 deletions include/net/wext.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
struct net;

#ifdef CONFIG_WEXT_CORE
int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
int wext_handle_ioctl(struct net *net, unsigned int cmd,
void __user *arg);
int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg);

struct iw_statistics *get_wireless_stats(struct net_device *dev);
int call_commit_handler(struct net_device *dev);
#else
static inline int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
static inline int wext_handle_ioctl(struct net *net, unsigned int cmd,
void __user *arg)
{
return -EINVAL;
Expand Down
132 changes: 31 additions & 101 deletions net/core/dev_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,10 @@
* match. --pb
*/

static int dev_ifname(struct net *net, struct ifreq __user *arg)
static int dev_ifname(struct net *net, struct ifreq *ifr)
{
struct ifreq ifr;
int error;

/*
* Fetch the caller's info block.
*/

if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
return -EFAULT;
ifr.ifr_name[IFNAMSIZ-1] = 0;

error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex);
if (error)
return error;

if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return 0;
ifr->ifr_name[IFNAMSIZ-1] = 0;
return netdev_get_name(net, ifr->ifr_name, ifr->ifr_ifindex);
}

static gifconf_func_t *gifconf_list[NPROTO];
Expand Down Expand Up @@ -66,9 +50,8 @@ EXPORT_SYMBOL(register_gifconf);
* Thus we will need a 'compatibility mode'.
*/

static int dev_ifconf(struct net *net, char __user *arg)
int dev_ifconf(struct net *net, struct ifconf *ifc, int size)
{
struct ifconf ifc;
struct net_device *dev;
char __user *pos;
int len;
Expand All @@ -79,11 +62,8 @@ static int dev_ifconf(struct net *net, char __user *arg)
* Fetch the caller's info block.
*/

if (copy_from_user(&ifc, arg, sizeof(struct ifconf)))
return -EFAULT;

pos = ifc.ifc_buf;
len = ifc.ifc_len;
pos = ifc->ifc_buf;
len = ifc->ifc_len;

/*
* Loop over the interfaces, and write an info block for each.
Expand All @@ -95,10 +75,10 @@ static int dev_ifconf(struct net *net, char __user *arg)
if (gifconf_list[i]) {
int done;
if (!pos)
done = gifconf_list[i](dev, NULL, 0);
done = gifconf_list[i](dev, NULL, 0, size);
else
done = gifconf_list[i](dev, pos + total,
len - total);
len - total, size);
if (done < 0)
return -EFAULT;
total += done;
Expand All @@ -109,12 +89,12 @@ static int dev_ifconf(struct net *net, char __user *arg)
/*
* All done. Write the updated control block back to the caller.
*/
ifc.ifc_len = total;
ifc->ifc_len = total;

/*
* Both BSD and Solaris return 0 here, so we do too.
*/
return copy_to_user(arg, &ifc, sizeof(struct ifconf)) ? -EFAULT : 0;
return 0;
}

/*
Expand Down Expand Up @@ -406,53 +386,24 @@ EXPORT_SYMBOL(dev_load);
* positive or a negative errno code on error.
*/

int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_copyout)
{
struct ifreq ifr;
int ret;
char *colon;

/* One special case: SIOCGIFCONF takes ifconf argument
and requires shared lock, because it sleeps writing
to user space.
*/

if (cmd == SIOCGIFCONF) {
rtnl_lock();
ret = dev_ifconf(net, (char __user *) arg);
rtnl_unlock();
return ret;
}
if (need_copyout)
*need_copyout = true;
if (cmd == SIOCGIFNAME)
return dev_ifname(net, (struct ifreq __user *)arg);

/*
* Take care of Wireless Extensions. Unfortunately struct iwreq
* isn't a proper subset of struct ifreq (it's 8 byte shorter)
* so we need to treat it specially, otherwise applications may
* fault if the struct they're passing happens to land at the
* end of a mapped page.
*/
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
struct iwreq iwr;

if (copy_from_user(&iwr, arg, sizeof(iwr)))
return -EFAULT;

iwr.ifr_name[sizeof(iwr.ifr_name) - 1] = 0;
return dev_ifname(net, ifr);

return wext_handle_ioctl(net, &iwr, cmd, arg);
}

if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
return -EFAULT;

ifr.ifr_name[IFNAMSIZ-1] = 0;
ifr->ifr_name[IFNAMSIZ-1] = 0;

colon = strchr(ifr.ifr_name, ':');
colon = strchr(ifr->ifr_name, ':');
if (colon)
*colon = 0;

dev_load(net, ifr->ifr_name);

/*
* See which interface the caller is talking about.
*/
Expand All @@ -472,31 +423,19 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCGIFMAP:
case SIOCGIFINDEX:
case SIOCGIFTXQLEN:
dev_load(net, ifr.ifr_name);
rcu_read_lock();
ret = dev_ifsioc_locked(net, &ifr, cmd);
ret = dev_ifsioc_locked(net, ifr, cmd);
rcu_read_unlock();
if (!ret) {
if (colon)
*colon = ':';
if (copy_to_user(arg, &ifr,
sizeof(struct ifreq)))
ret = -EFAULT;
}
if (colon)
*colon = ':';
return ret;

case SIOCETHTOOL:
dev_load(net, ifr.ifr_name);
rtnl_lock();
ret = dev_ethtool(net, &ifr);
ret = dev_ethtool(net, ifr);
rtnl_unlock();
if (!ret) {
if (colon)
*colon = ':';
if (copy_to_user(arg, &ifr,
sizeof(struct ifreq)))
ret = -EFAULT;
}
if (colon)
*colon = ':';
return ret;

/*
Expand All @@ -510,17 +449,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCSIFNAME:
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
dev_load(net, ifr.ifr_name);
rtnl_lock();
ret = dev_ifsioc(net, &ifr, cmd);
ret = dev_ifsioc(net, ifr, cmd);
rtnl_unlock();
if (!ret) {
if (colon)
*colon = ':';
if (copy_to_user(arg, &ifr,
sizeof(struct ifreq)))
ret = -EFAULT;
}
if (colon)
*colon = ':';
return ret;

/*
Expand Down Expand Up @@ -561,10 +494,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
/* fall through */
case SIOCBONDSLAVEINFOQUERY:
case SIOCBONDINFOQUERY:
dev_load(net, ifr.ifr_name);
rtnl_lock();
ret = dev_ifsioc(net, &ifr, cmd);
ret = dev_ifsioc(net, ifr, cmd);
rtnl_unlock();
if (need_copyout)
*need_copyout = false;
return ret;

case SIOCGIFMEM:
Expand All @@ -584,13 +518,9 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
cmd == SIOCGHWTSTAMP ||
(cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15)) {
dev_load(net, ifr.ifr_name);
rtnl_lock();
ret = dev_ifsioc(net, &ifr, cmd);
ret = dev_ifsioc(net, ifr, cmd);
rtnl_unlock();
if (!ret && copy_to_user(arg, &ifr,
sizeof(struct ifreq)))
ret = -EFAULT;
return ret;
}
return -ENOTTY;
Expand Down
28 changes: 22 additions & 6 deletions net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,9 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct sock *sk = sock->sk;
int err = 0;
struct net *net = sock_net(sk);
void __user *p = (void __user *)arg;
struct ifreq ifr;
struct rtentry rt;

switch (cmd) {
case SIOCGSTAMP:
Expand All @@ -882,26 +885,39 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
case SIOCADDRT:
case SIOCDELRT:
if (copy_from_user(&rt, p, sizeof(struct rtentry)))
return -EFAULT;
err = ip_rt_ioctl(net, cmd, &rt);
break;
case SIOCRTMSG:
err = ip_rt_ioctl(net, cmd, (void __user *)arg);
err = -EINVAL;
break;
case SIOCDARP:
case SIOCGARP:
case SIOCSARP:
err = arp_ioctl(net, cmd, (void __user *)arg);
break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFBRDADDR:
case SIOCSIFBRDADDR:
case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
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 SIOCSIFPFLAGS:
case SIOCGIFPFLAGS:
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;
default:
if (sk->sk_prot->ioctl)
Expand Down
Loading

0 comments on commit 8ec59b4

Please sign in to comment.