Commit 3d7e6ce3 authored by Ziyi Guo's avatar Ziyi Guo Committed by Paolo Abeni
Browse files

net: usb: pegasus: enable basic endpoint checking



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 90b7f296 ("net: usb: rtl8150: enable basic endpoint checking")
- commit 9e7021d2 ("net: usb: catc: enable basic endpoint checking")

Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: default avatarZiyi Guo <n7l8m4@u.northwestern.edu>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260222050633.410165-1-n7l8m4@u.northwestern.edu


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 983512f3
Loading
Loading
Loading
Loading
+30 −5
Original line number Diff line number Diff line
@@ -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;