Commit 01ee7d70 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

USB: usb gadgets avoid le{16,32}_to_cpup()

It turns out that le16_to_cpup() and le32_to_cpup() aren't always safe
to call with pointers into packed structures, since those are inlined
functions and GCC may lose the "packed" attribute.  So those references
can become unaligned kernel accesses, which are evil on some hardware.

This patch updates uses of those routines in the gadget stack.  The
references into packed structures can just use leXX_to_cpu(*x), which
in most cases is more natural.  Some other uses in RNDIS, mostly in
debug code, were wrong in the first place; those use get_unaligned().
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 97cb95d1
...@@ -132,7 +132,7 @@ ep_matches ( ...@@ -132,7 +132,7 @@ ep_matches (
* where it's an output parameter representing the full speed limit. * where it's an output parameter representing the full speed limit.
* the usb spec fixes high speed bulk maxpacket at 512 bytes. * the usb spec fixes high speed bulk maxpacket at 512 bytes.
*/ */
max = 0x7ff & le16_to_cpup (&desc->wMaxPacketSize); max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
switch (type) { switch (type) {
case USB_ENDPOINT_XFER_INT: case USB_ENDPOINT_XFER_INT:
/* INT: limit 64 bytes full speed, 1024 high speed */ /* INT: limit 64 bytes full speed, 1024 high speed */
......
...@@ -1369,12 +1369,12 @@ config_buf (struct dev_data *dev, u8 type, unsigned index) ...@@ -1369,12 +1369,12 @@ config_buf (struct dev_data *dev, u8 type, unsigned index)
hs = !hs; hs = !hs;
if (hs) { if (hs) {
dev->req->buf = dev->hs_config; dev->req->buf = dev->hs_config;
len = le16_to_cpup (&dev->hs_config->wTotalLength); len = le16_to_cpu(dev->hs_config->wTotalLength);
} else } else
#endif #endif
{ {
dev->req->buf = dev->config; dev->req->buf = dev->config;
len = le16_to_cpup (&dev->config->wTotalLength); len = le16_to_cpu(dev->config->wTotalLength);
} }
((u8 *)dev->req->buf) [1] = type; ((u8 *)dev->req->buf) [1] = type;
return len; return len;
...@@ -1885,7 +1885,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) ...@@ -1885,7 +1885,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
/* full or low speed config */ /* full or low speed config */
dev->config = (void *) kbuf; dev->config = (void *) kbuf;
total = le16_to_cpup (&dev->config->wTotalLength); total = le16_to_cpu(dev->config->wTotalLength);
if (!is_valid_config (dev->config) || total >= length) if (!is_valid_config (dev->config) || total >= length)
goto fail; goto fail;
kbuf += total; kbuf += total;
...@@ -1894,7 +1894,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) ...@@ -1894,7 +1894,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
/* optional high speed config */ /* optional high speed config */
if (kbuf [1] == USB_DT_CONFIG) { if (kbuf [1] == USB_DT_CONFIG) {
dev->hs_config = (void *) kbuf; dev->hs_config = (void *) kbuf;
total = le16_to_cpup (&dev->hs_config->wTotalLength); total = le16_to_cpu(dev->hs_config->wTotalLength);
if (!is_valid_config (dev->hs_config) || total >= length) if (!is_valid_config (dev->hs_config) || total >= length)
goto fail; goto fail;
kbuf += total; kbuf += total;
......
...@@ -2440,9 +2440,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) ...@@ -2440,9 +2440,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
tmp = 0; tmp = 0;
#define w_value le16_to_cpup (&u.r.wValue) #define w_value le16_to_cpu(u.r.wValue)
#define w_index le16_to_cpup (&u.r.wIndex) #define w_index le16_to_cpu(u.r.wIndex)
#define w_length le16_to_cpup (&u.r.wLength) #define w_length le16_to_cpu(u.r.wLength)
/* ack the irq */ /* ack the irq */
writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
......
...@@ -1651,9 +1651,9 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) ...@@ -1651,9 +1651,9 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
UDC_EP_NUM_REG = 0; UDC_EP_NUM_REG = 0;
} while (UDC_IRQ_SRC_REG & UDC_SETUP); } while (UDC_IRQ_SRC_REG & UDC_SETUP);
#define w_value le16_to_cpup (&u.r.wValue) #define w_value le16_to_cpu(u.r.wValue)
#define w_index le16_to_cpup (&u.r.wIndex) #define w_index le16_to_cpu(u.r.wIndex)
#define w_length le16_to_cpup (&u.r.wLength) #define w_length le16_to_cpu(u.r.wLength)
/* Delegate almost all control requests to the gadget driver, /* Delegate almost all control requests to the gadget driver,
* except for a handful of ch9 status/feature requests that * except for a handful of ch9 status/feature requests that
......
...@@ -186,10 +186,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, ...@@ -186,10 +186,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
DEBUG("query OID %08x value, len %d:\n", OID, buf_len); DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) { for (i = 0; i < buf_len; i += 16) {
DEBUG ("%03d: %08x %08x %08x %08x\n", i, DEBUG ("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpup((__le32 *)&buf[i]), le32_to_cpu(get_unaligned((__le32 *)
le32_to_cpup((__le32 *)&buf[i + 4]), &buf[i])),
le32_to_cpup((__le32 *)&buf[i + 8]), le32_to_cpu(get_unaligned((__le32 *)
le32_to_cpup((__le32 *)&buf[i + 12])); &buf[i + 4])),
le32_to_cpu(get_unaligned((__le32 *)
&buf[i + 8])),
le32_to_cpu(get_unaligned((__le32 *)
&buf[i + 12])));
} }
} }
...@@ -665,7 +669,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, ...@@ -665,7 +669,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break; break;
case OID_PNP_QUERY_POWER: case OID_PNP_QUERY_POWER:
DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
le32_to_cpup((__le32 *) buf) - 1); le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
/* only suspend is a real power state, and /* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER... * it can't be entered by OID_PNP_SET_POWER...
*/ */
...@@ -704,10 +708,14 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, ...@@ -704,10 +708,14 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
DEBUG("set OID %08x value, len %d:\n", OID, buf_len); DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) { for (i = 0; i < buf_len; i += 16) {
DEBUG ("%03d: %08x %08x %08x %08x\n", i, DEBUG ("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpup((__le32 *)&buf[i]), le32_to_cpu(get_unaligned((__le32 *)
le32_to_cpup((__le32 *)&buf[i + 4]), &buf[i])),
le32_to_cpup((__le32 *)&buf[i + 8]), le32_to_cpu(get_unaligned((__le32 *)
le32_to_cpup((__le32 *)&buf[i + 12])); &buf[i + 4])),
le32_to_cpu(get_unaligned((__le32 *)
&buf[i + 8])),
le32_to_cpu(get_unaligned((__le32 *)
&buf[i + 12])));
} }
} }
...@@ -721,7 +729,8 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, ...@@ -721,7 +729,8 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
* PROMISCUOUS, DIRECTED, * PROMISCUOUS, DIRECTED,
* MULTICAST, ALL_MULTICAST, BROADCAST * MULTICAST, ALL_MULTICAST, BROADCAST
*/ */
*params->filter = (u16) le32_to_cpup((__le32 *)buf); *params->filter = (u16) le32_to_cpu(get_unaligned(
(__le32 *)buf));
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__FUNCTION__, *params->filter); __FUNCTION__, *params->filter);
...@@ -771,7 +780,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, ...@@ -771,7 +780,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
* resuming, Windows forces a reset, and then SET_POWER D0. * resuming, Windows forces a reset, and then SET_POWER D0.
* FIXME ... then things go batty; Windows wedges itself. * FIXME ... then things go batty; Windows wedges itself.
*/ */
i = le32_to_cpup((__force __le32 *)buf); i = le32_to_cpu(get_unaligned((__le32 *)buf));
DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
switch (i) { switch (i) {
case NdisDeviceStateD0: case NdisDeviceStateD0:
...@@ -1058,8 +1067,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf) ...@@ -1058,8 +1067,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
return -ENOMEM; return -ENOMEM;
tmp = (__le32 *) buf; tmp = (__le32 *) buf;
MsgType = le32_to_cpup(tmp++); MsgType = le32_to_cpu(get_unaligned(tmp++));
MsgLength = le32_to_cpup(tmp++); MsgLength = le32_to_cpu(get_unaligned(tmp++));
if (configNr >= RNDIS_MAX_CONFIGS) if (configNr >= RNDIS_MAX_CONFIGS)
return -ENOTSUPP; return -ENOTSUPP;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment