mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-11 03:31:00 -04:00
net: usb: pegasus: don't rely on id table pointer arithmetic
The current code is broken when dynamic ID is involved; in such cases usb_device_id parameter of probe lives on the heap and the pointer arithmetic will get an index that is wildly out of bound. Instead of keeping a side table for additional information, use driver_info field of the usb_device_id. The dynamic ID parsing code needs to be updated for this; convert it to just write to the reserved entry for dynamic ID and remove the weird loop. Signed-off-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260707-usb_dyn_id_uaf-v2-5-632dcf3adfba@garyguo.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
91a8c8c718
commit
ce8101c331
@@ -43,21 +43,12 @@ static bool loopback;
|
||||
static bool mii_mode;
|
||||
static char *devid;
|
||||
|
||||
static struct usb_eth_dev usb_dev_id[] = {
|
||||
#define PEGASUS_DEV(pn, vid, pid, flags) \
|
||||
{.name = pn, .vendor = vid, .device = pid, .private = flags},
|
||||
#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
|
||||
PEGASUS_DEV(pn, vid, pid, flags)
|
||||
#include "pegasus.h"
|
||||
#undef PEGASUS_DEV
|
||||
#undef PEGASUS_DEV_CLASS
|
||||
{NULL, 0, 0, 0},
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
static struct usb_eth_dev dynamic_id_info = {};
|
||||
|
||||
static struct usb_device_id pegasus_ids[] = {
|
||||
#define PEGASUS_DEV(pn, vid, pid, flags) \
|
||||
{.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid},
|
||||
{.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid, \
|
||||
.driver_info = (kernel_ulong_t)&(const struct usb_eth_dev) {.name = pn, .private = flags}},
|
||||
/*
|
||||
* The Belkin F8T012xx1 bluetooth adaptor has the same vendor and product
|
||||
* IDs as the Belkin F5D5050, so we need to teach the pegasus driver to
|
||||
@@ -66,7 +57,8 @@ static struct usb_device_id pegasus_ids[] = {
|
||||
*/
|
||||
#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
|
||||
{.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS), \
|
||||
.idVendor = vid, .idProduct = pid, .bDeviceClass = dclass},
|
||||
.idVendor = vid, .idProduct = pid, .bDeviceClass = dclass, \
|
||||
.driver_info = (kernel_ulong_t)&(const struct usb_eth_dev) {.name = pn, .private = flags}},
|
||||
#include "pegasus.h"
|
||||
#undef PEGASUS_DEV
|
||||
#undef PEGASUS_DEV_CLASS
|
||||
@@ -402,12 +394,12 @@ static inline int reset_mac(pegasus_t *pegasus)
|
||||
if (i == REG_TIMEOUT)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
|
||||
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
|
||||
if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS ||
|
||||
le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_DLINK) {
|
||||
set_register(pegasus, Gpio0, 0x24);
|
||||
set_register(pegasus, Gpio0, 0x26);
|
||||
}
|
||||
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
|
||||
if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_ELCON) {
|
||||
__u16 auxmode;
|
||||
ret = read_mii_word(pegasus, 3, 0x1b, &auxmode);
|
||||
if (ret < 0)
|
||||
@@ -445,9 +437,9 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
|
||||
memcpy(pegasus->eth_regs, data, sizeof(data));
|
||||
ret = set_registers(pegasus, EthCtrl0, 3, data);
|
||||
|
||||
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
|
||||
usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 ||
|
||||
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
|
||||
if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS ||
|
||||
le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS2 ||
|
||||
le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_DLINK) {
|
||||
u16 auxmode;
|
||||
ret = read_mii_word(pegasus, 0, 0x1b, &auxmode);
|
||||
if (ret < 0)
|
||||
@@ -1153,7 +1145,7 @@ static int pegasus_probe(struct usb_interface *intf,
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct net_device *net;
|
||||
pegasus_t *pegasus;
|
||||
int dev_index = id - pegasus_ids;
|
||||
const struct usb_eth_dev *info = (const struct usb_eth_dev *)id->driver_info;
|
||||
int res = -ENOMEM;
|
||||
static const u8 bulk_ep_addr[] = {
|
||||
PEGASUS_USB_EP_BULK_IN | USB_DIR_IN,
|
||||
@@ -1178,7 +1170,6 @@ static int pegasus_probe(struct usb_interface *intf,
|
||||
goto out;
|
||||
|
||||
pegasus = netdev_priv(net);
|
||||
pegasus->dev_index = dev_index;
|
||||
pegasus->intf = intf;
|
||||
|
||||
res = alloc_urbs(pegasus);
|
||||
@@ -1206,7 +1197,7 @@ static int pegasus_probe(struct usb_interface *intf,
|
||||
pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV
|
||||
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
|
||||
|
||||
pegasus->features = usb_dev_id[dev_index].private;
|
||||
pegasus->features = info ? info->private : DEFAULT_GPIO_RESET;
|
||||
res = get_interrupt_interval(pegasus);
|
||||
if (res)
|
||||
goto out2;
|
||||
@@ -1235,7 +1226,7 @@ static int pegasus_probe(struct usb_interface *intf,
|
||||
queue_delayed_work(system_long_wq, &pegasus->carrier_check,
|
||||
CARRIER_CHECK_DELAY);
|
||||
dev_info(&intf->dev, "%s, %s, %pM\n", net->name,
|
||||
usb_dev_id[dev_index].name, net->dev_addr);
|
||||
info ? info->name : "(unknown)", net->dev_addr);
|
||||
return 0;
|
||||
|
||||
out3:
|
||||
@@ -1325,8 +1316,9 @@ static struct usb_driver pegasus_driver = {
|
||||
|
||||
static void __init parse_id(char *id)
|
||||
{
|
||||
unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0;
|
||||
unsigned int vendor_id = 0, device_id = 0, flags = 0;
|
||||
char *token, *name = NULL;
|
||||
int dyn_id_index = ARRAY_SIZE(pegasus_ids) - 2;
|
||||
|
||||
token = strsep(&id, ":");
|
||||
if (token)
|
||||
@@ -1348,14 +1340,12 @@ static void __init parse_id(char *id)
|
||||
if (device_id > 0x10000 || device_id == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; usb_dev_id[i].name; i++);
|
||||
usb_dev_id[i].name = name;
|
||||
usb_dev_id[i].vendor = vendor_id;
|
||||
usb_dev_id[i].device = device_id;
|
||||
usb_dev_id[i].private = flags;
|
||||
pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
|
||||
pegasus_ids[i].idVendor = vendor_id;
|
||||
pegasus_ids[i].idProduct = device_id;
|
||||
dynamic_id_info.name = name;
|
||||
dynamic_id_info.private = flags;
|
||||
pegasus_ids[dyn_id_index].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
|
||||
pegasus_ids[dyn_id_index].idVendor = vendor_id;
|
||||
pegasus_ids[dyn_id_index].idProduct = device_id;
|
||||
pegasus_ids[dyn_id_index].driver_info = (kernel_ulong_t)&dynamic_id_info;
|
||||
}
|
||||
|
||||
static int __init pegasus_init(void)
|
||||
|
||||
@@ -85,7 +85,6 @@ typedef struct pegasus {
|
||||
unsigned features;
|
||||
u32 msg_enable;
|
||||
u32 wolopts;
|
||||
int dev_index;
|
||||
int intr_interval;
|
||||
struct tasklet_struct rx_tl;
|
||||
struct delayed_work carrier_check;
|
||||
@@ -102,8 +101,6 @@ typedef struct pegasus {
|
||||
|
||||
struct usb_eth_dev {
|
||||
char *name;
|
||||
__u16 vendor;
|
||||
__u16 device;
|
||||
__u32 private; /* LSB is gpio reset value */
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user