diff options
author | David S. Miller <davem@davemloft.net> | 2017-06-19 00:03:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-06-19 00:03:51 -0400 |
commit | 4b153ca989a9bf61f622ded32e1d689df88edaa5 (patch) | |
tree | 9f11467ff9b8899bd69ed71fd9dd2ade83ba876e | |
parent | 46f8cd9d2fc1e4e8b82b53a0007f6c92e80c930b (diff) | |
parent | 68dd02d19c811ca8ea60220a9d73e13b4bdad73a (diff) |
Merge tag 'mac80211-for-davem-2017-06-16' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211
Johannes Berg says:
====================
Here's just the fix for that ancient bug:
* remove wext calling ndo_do_ioctl, since nobody needs
that now and it makes the type change easier
* use struct iwreq instead of struct ifreq almost everywhere
in wireless extensions code
* copy only struct iwreq from userspace in dev_ioctl for the
wireless extensions, since it's smaller than struct ifreq
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/wext.h | 4 | ||||
-rw-r--r-- | net/core/dev_ioctl.c | 19 | ||||
-rw-r--r-- | net/wireless/wext-core.c | 22 |
3 files changed, 27 insertions, 18 deletions
diff --git a/include/net/wext.h b/include/net/wext.h index 345911965dbb..454ff763eeba 100644 --- a/include/net/wext.h +++ b/include/net/wext.h @@ -6,7 +6,7 @@ struct net; #ifdef CONFIG_WEXT_CORE -int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, +int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd, void __user *arg); int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, unsigned long arg); @@ -14,7 +14,7 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 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 ifreq *ifr, unsigned int cmd, +static inline int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd, void __user *arg) { return -EINVAL; diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index b94b1d293506..27fad31784a8 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -410,6 +410,22 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) 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; + + return wext_handle_ioctl(net, &iwr, cmd, arg); + } + if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; @@ -559,9 +575,6 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) ret = -EFAULT; return ret; } - /* Take care of Wireless Extensions */ - if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) - return wext_handle_ioctl(net, &ifr, cmd, arg); return -ENOTTY; } } diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 1a4db6790e20..6cdb054484d6 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -914,13 +914,12 @@ int call_commit_handler(struct net_device *dev) * Main IOCTl dispatcher. * Check the type of IOCTL and call the appropriate wrapper... */ -static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, +static int wireless_process_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private) { - struct iwreq *iwr = (struct iwreq *) ifr; struct net_device *dev; iw_handler handler; @@ -928,7 +927,7 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, * The copy_to/from_user() of ifr is also dealt with in there */ /* Make sure the device exist */ - if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) + if ((dev = __dev_get_by_name(net, iwr->ifr_name)) == NULL) return -ENODEV; /* A bunch of special cases, then the generic case... @@ -957,9 +956,6 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, else if (private) return private(dev, iwr, cmd, info, handler); } - /* Old driver API : call driver ioctl handler */ - if (dev->netdev_ops->ndo_do_ioctl) - return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); return -EOPNOTSUPP; } @@ -977,7 +973,7 @@ static int wext_permission_check(unsigned int cmd) } /* entry point from dev ioctl */ -static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, +static int wext_ioctl_dispatch(struct net *net, struct iwreq *iwr, unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private) @@ -987,9 +983,9 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, if (ret) return ret; - dev_load(net, ifr->ifr_name); + dev_load(net, iwr->ifr_name); rtnl_lock(); - ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); + ret = wireless_process_ioctl(net, iwr, cmd, info, standard, private); rtnl_unlock(); return ret; @@ -1039,18 +1035,18 @@ static int ioctl_standard_call(struct net_device * dev, } -int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, +int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd, void __user *arg) { struct iw_request_info info = { .cmd = cmd, .flags = 0 }; int ret; - ret = wext_ioctl_dispatch(net, ifr, cmd, &info, + ret = wext_ioctl_dispatch(net, iwr, cmd, &info, ioctl_standard_call, ioctl_private_call); if (ret >= 0 && IW_IS_GET(cmd) && - copy_to_user(arg, ifr, sizeof(struct iwreq))) + copy_to_user(arg, iwr, sizeof(struct iwreq))) return -EFAULT; return ret; @@ -1107,7 +1103,7 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, info.cmd = cmd; info.flags = IW_REQUEST_FLAG_COMPAT; - ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, + ret = wext_ioctl_dispatch(net, &iwr, cmd, &info, compat_standard_call, compat_private_call); |