diff options
author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2010-03-04 11:27:02 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-03-10 17:44:24 -0500 |
commit | 80f8c5b434f94926c6489d7350d58aecb53ab70f (patch) | |
tree | beff456b9ec9724b75d122383513faea91eb3e00 /drivers/net/wireless/rndis_wlan.c | |
parent | eae44756d60c4e938259358090dba5df675dced0 (diff) |
rndis_wlan: copy only useful data from rndis_command respond
rndis_query_oid() uses full output buffer size to copy response buffer
from rndis_command()/device. This doesn't cause problems as response buffer
is sized based on output buffer but does copy extra unset bytes.
So change rndis_query_oid() so that only meaningful bytes are being copied.
Also in case of malfunctioning device/cable/etc returned data offset from
device might be wrong so bound check memory access correctly, so add
checks for this.
v2: fixed to use new netdev_dbg/warn/etc instead of old devdbg/warn/etc
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9f6d6bf06b8e..a4f70de99cdd 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -704,6 +704,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) | |||
704 | struct rndis_query_c *get_c; | 704 | struct rndis_query_c *get_c; |
705 | } u; | 705 | } u; |
706 | int ret, buflen; | 706 | int ret, buflen; |
707 | int resplen, respoffs, copylen; | ||
707 | 708 | ||
708 | buflen = *len + sizeof(*u.get); | 709 | buflen = *len + sizeof(*u.get); |
709 | if (buflen < CONTROL_BUFFER_SIZE) | 710 | if (buflen < CONTROL_BUFFER_SIZE) |
@@ -733,11 +734,34 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) | |||
733 | le32_to_cpu(u.get_c->status)); | 734 | le32_to_cpu(u.get_c->status)); |
734 | 735 | ||
735 | if (ret == 0) { | 736 | if (ret == 0) { |
736 | memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); | 737 | resplen = le32_to_cpu(u.get_c->len); |
738 | respoffs = le32_to_cpu(u.get_c->offset) + 8; | ||
737 | 739 | ||
738 | ret = le32_to_cpu(u.get_c->len); | 740 | if (respoffs > buflen) { |
739 | if (ret > *len) | 741 | /* Device returned data offset outside buffer, error. */ |
740 | *len = ret; | 742 | netdev_dbg(dev->net, "%s(%s): received invalid " |
743 | "data offset: %d > %d\n", __func__, | ||
744 | oid_to_string(oid), respoffs, buflen); | ||
745 | |||
746 | ret = -EINVAL; | ||
747 | goto exit_unlock; | ||
748 | } | ||
749 | |||
750 | if ((resplen + respoffs) > buflen) { | ||
751 | /* Device would have returned more data if buffer would | ||
752 | * have been big enough. Copy just the bits that we got. | ||
753 | */ | ||
754 | copylen = buflen - respoffs; | ||
755 | } else { | ||
756 | copylen = resplen; | ||
757 | } | ||
758 | |||
759 | if (copylen > *len) | ||
760 | copylen = *len; | ||
761 | |||
762 | memcpy(data, u.buf + respoffs, copylen); | ||
763 | |||
764 | *len = resplen; | ||
741 | 765 | ||
742 | ret = rndis_error_status(u.get_c->status); | 766 | ret = rndis_error_status(u.get_c->status); |
743 | if (ret < 0) | 767 | if (ret < 0) |
@@ -746,6 +770,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) | |||
746 | le32_to_cpu(u.get_c->status), ret); | 770 | le32_to_cpu(u.get_c->status), ret); |
747 | } | 771 | } |
748 | 772 | ||
773 | exit_unlock: | ||
749 | mutex_unlock(&priv->command_lock); | 774 | mutex_unlock(&priv->command_lock); |
750 | 775 | ||
751 | if (u.buf != priv->command_buffer) | 776 | if (u.buf != priv->command_buffer) |