summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorManikanta <mmaddireddy@nvidia.com>2014-02-26 15:44:23 +0530
committerVenu Byravarasu <vbyravarasu@nvidia.com>2014-04-07 22:10:20 -0700
commit8e9e49fa9a96116f44a86cdba2e084d09827641a (patch)
tree18f07bdef044c107a5e5991bc10f4c71aa02abb4 /drivers/net
parent170259ffaad85f0fe8c51cbbdacea3b48dbfaaf1 (diff)
net: wireless: bcmdhd: fix 64-bit safeness issues
If a structure has pointer as a field and used in copy_from_user, it causes issues in case of 32-bit userspace and 64-bit kernel as structure size varies in kernel and userspace. To handle this case define new structure without a pointer and use in case of compat task. bug 1466409 Change-Id: I1dfb511b2683d93ba66626877885a4ad0ea37470 Signed-off-by: Manikanta <mmaddireddy@nvidia.com> Reviewed-on: http://git-master/r/374795 Reviewed-by: Nagarjuna Kristam <nkristam@nvidia.com> Tested-by: Nagarjuna Kristam <nkristam@nvidia.com> Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
Diffstat (limited to 'drivers/net')
-rwxr-xr-xdrivers/net/wireless/bcmdhd/dhd_linux.c35
-rwxr-xr-xdrivers/net/wireless/bcmdhd/include/dhdioctl.h12
-rwxr-xr-xdrivers/net/wireless/bcmdhd/wl_android.c33
3 files changed, 76 insertions, 4 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 534c272cdd53..4f8dde7453c8 100755
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -43,6 +43,7 @@
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/ip.h>
+#include <linux/compat.h>
#include <net/addrconf.h>
#include <linux/cpufreq.h>
@@ -2768,6 +2769,9 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
dhd_ioctl_t ioc;
+#ifdef CONFIG_COMPAT
+ dhd_ioctl_compat_t ioc_compat;
+#endif
int bcmerror = 0;
int ifidx;
int ret;
@@ -2824,7 +2828,37 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
}
memset(&ioc, 0, sizeof(ioc));
+#ifdef CONFIG_COMPAT
+ memset(&ioc_compat, 0, sizeof(ioc_compat));
+ if (is_compat_task()) {
+ /* Copy the ioc control structure part of ioctl request */
+ if (copy_from_user(&ioc_compat, ifr->ifr_data, sizeof(dhd_ioctl_compat_t))) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+ ioc.cmd = ioc_compat.cmd;
+ ioc.buf = (void *)(uintptr_t) ioc_compat.buf;
+ ioc.len = ioc_compat.len;
+ ioc.set = ioc_compat.set;
+ ioc.used = ioc_compat.used;
+ ioc.needed = ioc_compat.needed;
+ ioc.driver = ioc_compat.driver;
+ } else {
+ /* Copy the ioc control structure part of ioctl request */
+ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+
+ /* To differentiate between wl and dhd read 4 more byes */
+ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
+ sizeof(uint)) != 0)) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+ }
+#else
/* Copy the ioc control structure part of ioctl request */
if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
bcmerror = BCME_BADADDR;
@@ -2837,6 +2871,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
bcmerror = BCME_BADADDR;
goto done;
}
+#endif
if (!capable(CAP_NET_ADMIN)) {
bcmerror = BCME_EPERM;
diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
index 187fd07b0e61..efca0146b156 100755
--- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
@@ -40,6 +40,18 @@
/* Linux network driver ioctl encoding */
+#ifdef CONFIG_COMPAT
+typedef struct dhd_ioctl_compat {
+ uint cmd; /* common ioctl definition */
+ u32 buf; /* pointer to user buffer */
+ uint len; /* length of user buffer */
+ bool set; /* get or set request (optional) */
+ uint used; /* bytes read or written (optional) */
+ uint needed; /* bytes needed (optional) */
+ uint driver; /* to identify target driver */
+} dhd_ioctl_compat_t;
+#endif
+
typedef struct dhd_ioctl {
uint cmd; /* common ioctl definition */
void *buf; /* pointer to user buffer */
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 14e81efa8ded..a94e6ef13622 100755
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/compat.h>
#include <net/netlink.h>
#include <wl_android.h>
@@ -150,12 +151,16 @@ struct io_cfg {
struct list_head list;
};
+#ifdef CONFIG_COMPAT
+typedef struct android_wifi_priv_cmd_compat {
+ u32 bufaddr;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd_compat;
+#endif
+
typedef struct android_wifi_priv_cmd {
-#ifdef CONFIG_64BIT
- u64 bufaddr;
-#else
char *bufaddr;
-#endif
int used_len;
int total_len;
} android_wifi_priv_cmd;
@@ -1278,6 +1283,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
char *buf = NULL;
int bytes_written = 0;
android_wifi_priv_cmd priv_cmd;
+#ifdef CONFIG_COMPAT
+ android_wifi_priv_cmd_compat priv_cmd_compat;
+#endif
net_os_wake_lock(net);
@@ -1285,10 +1293,27 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
ret = -EINVAL;
goto exit;
}
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ if (copy_from_user(&priv_cmd_compat, ifr->ifr_data, sizeof(android_wifi_priv_cmd_compat))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ priv_cmd.bufaddr = (char *)(uintptr_t) priv_cmd_compat.bufaddr;
+ priv_cmd.used_len = priv_cmd_compat.used_len;
+ priv_cmd.total_len = priv_cmd_compat.total_len;
+ } else {
+ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ }
+#else
if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
ret = -EFAULT;
goto exit;
}
+#endif
if (priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN)
{
DHD_ERROR(("%s: too long priavte command\n", __FUNCTION__));