| From 3d5fdff46c4b2b9534fa2f9fc78e90a48e0ff724 Mon Sep 17 00:00:00 2001 |
| From: Prasun Maiti <prasunmaiti87@gmail.com> |
| Date: Mon, 6 Jun 2016 20:04:19 +0530 |
| Subject: wext: Fix 32 bit iwpriv compatibility issue with 64 bit Kernel |
| |
| From: Prasun Maiti <prasunmaiti87@gmail.com> |
| |
| commit 3d5fdff46c4b2b9534fa2f9fc78e90a48e0ff724 upstream. |
| |
| iwpriv app uses iw_point structure to send data to Kernel. The iw_point |
| structure holds a pointer. For compatibility Kernel converts the pointer |
| as required for WEXT IOCTLs (SIOCIWFIRST to SIOCIWLAST). Some drivers |
| may use iw_handler_def.private_args to populate iwpriv commands instead |
| of iw_handler_def.private. For those case, the IOCTLs from |
| SIOCIWFIRSTPRIV to SIOCIWLASTPRIV will follow the path ndo_do_ioctl(). |
| Accordingly when the filled up iw_point structure comes from 32 bit |
| iwpriv to 64 bit Kernel, Kernel will not convert the pointer and sends |
| it to driver. So, the driver may get the invalid data. |
| |
| The pointer conversion for the IOCTLs (SIOCIWFIRSTPRIV to |
| SIOCIWLASTPRIV), which follow the path ndo_do_ioctl(), is mandatory. |
| This patch adds pointer conversion from 32 bit to 64 bit and vice versa, |
| if the ioctl comes from 32 bit iwpriv to 64 bit Kernel. |
| |
| Signed-off-by: Prasun Maiti <prasunmaiti87@gmail.com> |
| Signed-off-by: Ujjal Roy <royujjal@gmail.com> |
| Tested-by: Dibyajyoti Ghosh <dibyajyotig@gmail.com> |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| net/wireless/wext-core.c | 25 +++++++++++++++++++++++-- |
| 1 file changed, 23 insertions(+), 2 deletions(-) |
| |
| --- a/net/wireless/wext-core.c |
| +++ b/net/wireless/wext-core.c |
| @@ -955,8 +955,29 @@ static int wireless_process_ioctl(struct |
| 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); |
| + if (dev->netdev_ops->ndo_do_ioctl) { |
| +#ifdef CONFIG_COMPAT |
| + if (info->flags & IW_REQUEST_FLAG_COMPAT) { |
| + int ret = 0; |
| + struct iwreq iwr_lcl; |
| + struct compat_iw_point *iwp_compat = (void *) &iwr->u.data; |
| + |
| + memcpy(&iwr_lcl, iwr, sizeof(struct iwreq)); |
| + iwr_lcl.u.data.pointer = compat_ptr(iwp_compat->pointer); |
| + iwr_lcl.u.data.length = iwp_compat->length; |
| + iwr_lcl.u.data.flags = iwp_compat->flags; |
| + |
| + ret = dev->netdev_ops->ndo_do_ioctl(dev, (void *) &iwr_lcl, cmd); |
| + |
| + iwp_compat->pointer = ptr_to_compat(iwr_lcl.u.data.pointer); |
| + iwp_compat->length = iwr_lcl.u.data.length; |
| + iwp_compat->flags = iwr_lcl.u.data.flags; |
| + |
| + return ret; |
| + } else |
| +#endif |
| + return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); |
| + } |
| return -EOPNOTSUPP; |
| } |
| |