Skip to content

Commit 68dd02d

Browse files
committed
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 <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent 4f39a1f commit 68dd02d

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

include/net/wext.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
struct net;
77

88
#ifdef CONFIG_WEXT_CORE
9-
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
9+
int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
1010
void __user *arg);
1111
int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1212
unsigned long arg);
1313

1414
struct iw_statistics *get_wireless_stats(struct net_device *dev);
1515
int call_commit_handler(struct net_device *dev);
1616
#else
17-
static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
17+
static inline int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
1818
void __user *arg)
1919
{
2020
return -EINVAL;

net/core/dev_ioctl.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,22 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
410410
if (cmd == SIOCGIFNAME)
411411
return dev_ifname(net, (struct ifreq __user *)arg);
412412

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+
413429
if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
414430
return -EFAULT;
415431

@@ -559,9 +575,6 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
559575
ret = -EFAULT;
560576
return ret;
561577
}
562-
/* Take care of Wireless Extensions */
563-
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
564-
return wext_handle_ioctl(net, &ifr, cmd, arg);
565578
return -ENOTTY;
566579
}
567580
}

net/wireless/wext-core.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,18 +1035,18 @@ static int ioctl_standard_call(struct net_device * dev,
10351035
}
10361036

10371037

1038-
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
1038+
int wext_handle_ioctl(struct net *net, struct iwreq *iwr, unsigned int cmd,
10391039
void __user *arg)
10401040
{
10411041
struct iw_request_info info = { .cmd = cmd, .flags = 0 };
10421042
int ret;
10431043

1044-
ret = wext_ioctl_dispatch(net, (void *)ifr, cmd, &info,
1044+
ret = wext_ioctl_dispatch(net, iwr, cmd, &info,
10451045
ioctl_standard_call,
10461046
ioctl_private_call);
10471047
if (ret >= 0 &&
10481048
IW_IS_GET(cmd) &&
1049-
copy_to_user(arg, ifr, sizeof(struct iwreq)))
1049+
copy_to_user(arg, iwr, sizeof(struct iwreq)))
10501050
return -EFAULT;
10511051

10521052
return ret;

0 commit comments

Comments
 (0)