aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2017-06-14 03:28:11 -0400
committerJohannes Berg <johannes.berg@intel.com>2017-06-14 07:52:44 -0400
commit68dd02d19c811ca8ea60220a9d73e13b4bdad73a (patch)
treefc5f16101d532733fd8e4d34ea064313580fa163
parent4f39a1f5870104b1670df2c09c831ac281896545 (diff)
dev_ioctl: copy only the smaller struct iwreq for wext
Unfortunately, struct iwreq isn't a proper subset of struct ifreq, but is still handled by the same code path. Robert reported that then applications may (randomly) fault if the struct iwreq they pass happens to land within 8 bytes of the end of a mapping (the struct is only 32 bytes, vs. struct ifreq's 40 bytes). To fix this, pull out the code handling wireless extension ioctls and copy only the smaller structure in this case. This bug goes back a long time, I tracked that it was introduced into mainline in 2.1.15, over 20 years ago! This fixes https://bugzilla.kernel.org/show_bug.cgi?id=195869 Reported-by: Robert O'Callahan <robert@ocallahan.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/wext.h4
-rw-r--r--net/core/dev_ioctl.c19
-rw-r--r--net/wireless/wext-core.c6
3 files changed, 21 insertions, 8 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 @@
6struct net; 6struct net;
7 7
8#ifdef CONFIG_WEXT_CORE 8#ifdef CONFIG_WEXT_CORE
9int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 9int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
10 void __user *arg); 10 void __user *arg);
11int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 11int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
12 unsigned long arg); 12 unsigned long arg);
@@ -14,7 +14,7 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
14struct iw_statistics *get_wireless_stats(struct net_device *dev); 14struct iw_statistics *get_wireless_stats(struct net_device *dev);
15int call_commit_handler(struct net_device *dev); 15int call_commit_handler(struct net_device *dev);
16#else 16#else
17static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 17static inline int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
18 void __user *arg) 18 void __user *arg)
19{ 19{
20 return -EINVAL; 20 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)
410 if (cmd == SIOCGIFNAME) 410 if (cmd == SIOCGIFNAME)
411 return dev_ifname(net, (struct ifreq __user *)arg); 411 return dev_ifname(net, (struct ifreq __user *)arg);
412 412
413 /*
414 * Take care of Wireless Extensions. Unfortunately struct iwreq
415 * isn't a proper subset of struct ifreq (it's 8 byte shorter)
416 * so we need to treat it specially, otherwise applications may
417 * fault if the struct they're passing happens to land at the
418 * end of a mapped page.
419 */
420 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
421 struct iwreq iwr;
422
423 if (copy_from_user(&iwr, arg, sizeof(iwr)))
424 return -EFAULT;
425
426 return wext_handle_ioctl(net, &iwr, cmd, arg);
427 }
428
413 if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) 429 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
414 return -EFAULT; 430 return -EFAULT;
415 431
@@ -559,9 +575,6 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
559 ret = -EFAULT; 575 ret = -EFAULT;
560 return ret; 576 return ret;
561 } 577 }
562 /* Take care of Wireless Extensions */
563 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
564 return wext_handle_ioctl(net, &ifr, cmd, arg);
565 return -ENOTTY; 578 return -ENOTTY;
566 } 579 }
567} 580}
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index 12949c8d3e5f..6cdb054484d6 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -1035,18 +1035,18 @@ static int ioctl_standard_call(struct net_device * dev,
1035} 1035}
1036 1036
1037 1037
1038int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 1038int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
1039 void __user *arg) 1039 void __user *arg)
1040{ 1040{
1041 struct iw_request_info info = { .cmd = cmd, .flags = 0 }; 1041 struct iw_request_info info = { .cmd = cmd, .flags = 0 };
1042 int ret; 1042 int ret;
1043 1043
1044 ret = wext_ioctl_dispatch(net, (void *)ifr, cmd, &info, 1044 ret = wext_ioctl_dispatch(net, iwr, cmd, &info,
1045 ioctl_standard_call, 1045 ioctl_standard_call,
1046 ioctl_private_call); 1046 ioctl_private_call);
1047 if (ret >= 0 && 1047 if (ret >= 0 &&
1048 IW_IS_GET(cmd) && 1048 IW_IS_GET(cmd) &&
1049 copy_to_user(arg, ifr, sizeof(struct iwreq))) 1049 copy_to_user(arg, iwr, sizeof(struct iwreq)))
1050 return -EFAULT; 1050 return -EFAULT;
1051 1051
1052 return ret; 1052 return ret;