]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: usb: pegasus: enable basic endpoint checking
authorZiyi Guo <n7l8m4@u.northwestern.edu>
Sun, 22 Feb 2026 05:06:33 +0000 (05:06 +0000)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 24 Feb 2026 10:51:51 +0000 (11:51 +0100)
pegasus_probe() fills URBs with hardcoded endpoint pipes without
verifying the endpoint descriptors:

  - usb_rcvbulkpipe(dev, 1) for RX data
  - usb_sndbulkpipe(dev, 2) for TX data
  - usb_rcvintpipe(dev, 3)  for status interrupts

A malformed USB device can present these endpoints with transfer types
that differ from what the driver assumes.

Add a pegasus_usb_ep enum for endpoint numbers, replacing magic
constants throughout. Add usb_check_bulk_endpoints() and
usb_check_int_endpoints() calls before any resource allocation to
verify endpoint types before use, rejecting devices with mismatched
descriptors at probe time, and avoid triggering assertion.

Similar fix to
- commit 90b7f2961798 ("net: usb: rtl8150: enable basic endpoint checking")
- commit 9e7021d2aeae ("net: usb: catc: enable basic endpoint checking")

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Ziyi Guo <n7l8m4@u.northwestern.edu>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260222050633.410165-1-n7l8m4@u.northwestern.edu
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/usb/pegasus.c

index 7b6d6eb6070999dd7c600ed9d7296cb3c22566c2..b84968c5f074c8df6527c076b4f4137ea82ed658 100644 (file)
@@ -28,6 +28,17 @@ static const char driver_name[] = "pegasus";
                        BMSR_100FULL | BMSR_ANEGCAPABLE)
 #define CARRIER_CHECK_DELAY (2 * HZ)
 
+/*
+ * USB endpoints.
+ */
+
+enum pegasus_usb_ep {
+       PEGASUS_USB_EP_CONTROL  = 0,
+       PEGASUS_USB_EP_BULK_IN  = 1,
+       PEGASUS_USB_EP_BULK_OUT = 2,
+       PEGASUS_USB_EP_INT_IN   = 3,
+};
+
 static bool loopback;
 static bool mii_mode;
 static char *devid;
@@ -542,7 +553,7 @@ static void read_bulk_callback(struct urb *urb)
                goto tl_sched;
 goon:
        usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
-                         usb_rcvbulkpipe(pegasus->usb, 1),
+                         usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
                          pegasus->rx_skb->data, PEGASUS_MTU,
                          read_bulk_callback, pegasus);
        rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC);
@@ -582,7 +593,7 @@ static void rx_fixup(struct tasklet_struct *t)
                return;
        }
        usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
-                         usb_rcvbulkpipe(pegasus->usb, 1),
+                         usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
                          pegasus->rx_skb->data, PEGASUS_MTU,
                          read_bulk_callback, pegasus);
 try_again:
@@ -710,7 +721,7 @@ static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb,
        ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
        skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len);
        usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb,
-                         usb_sndbulkpipe(pegasus->usb, 2),
+                         usb_sndbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_OUT),
                          pegasus->tx_buff, count,
                          write_bulk_callback, pegasus);
        if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
@@ -837,7 +848,7 @@ static int pegasus_open(struct net_device *net)
        set_registers(pegasus, EthID, 6, net->dev_addr);
 
        usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
-                         usb_rcvbulkpipe(pegasus->usb, 1),
+                         usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
                          pegasus->rx_skb->data, PEGASUS_MTU,
                          read_bulk_callback, pegasus);
        if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) {
@@ -848,7 +859,7 @@ static int pegasus_open(struct net_device *net)
        }
 
        usb_fill_int_urb(pegasus->intr_urb, pegasus->usb,
-                        usb_rcvintpipe(pegasus->usb, 3),
+                        usb_rcvintpipe(pegasus->usb, PEGASUS_USB_EP_INT_IN),
                         pegasus->intr_buff, sizeof(pegasus->intr_buff),
                         intr_callback, pegasus, pegasus->intr_interval);
        if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
@@ -1133,10 +1144,24 @@ static int pegasus_probe(struct usb_interface *intf,
        pegasus_t *pegasus;
        int dev_index = id - pegasus_ids;
        int res = -ENOMEM;
+       static const u8 bulk_ep_addr[] = {
+               PEGASUS_USB_EP_BULK_IN | USB_DIR_IN,
+               PEGASUS_USB_EP_BULK_OUT | USB_DIR_OUT,
+               0};
+       static const u8 int_ep_addr[] = {
+               PEGASUS_USB_EP_INT_IN | USB_DIR_IN,
+               0};
 
        if (pegasus_blacklisted(dev))
                return -ENODEV;
 
+       /* Verify that all required endpoints are present */
+       if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
+           !usb_check_int_endpoints(intf, int_ep_addr)) {
+               dev_err(&intf->dev, "Missing or invalid endpoints\n");
+               return -ENODEV;
+       }
+
        net = alloc_etherdev(sizeof(struct pegasus));
        if (!net)
                goto out;