[PATCH v8 02/13] mfd: nct6694: Validate the USB endpoints
From: a0282524688
Date: Wed Oct 07 2026 - 06:22:58 EST
From: Ming Yu <a0282524688@xxxxxxxxx>
The probe reads endpoint[0] of the current altsetting without checking
that the interface describes any endpoint, and the bulk endpoints used
for the command transfers are never validated. A malformed device can
make the driver read past the endpoint array or submit URBs to
endpoints of the wrong type.
The interface exposes several interrupt and bulk endpoints, of which
only EP1 IN, EP2 IN and EP3 OUT carry the command interface, so the
endpoints cannot be looked up by type. Check that the expected
endpoints are present with usb_check_{bulk,int}_endpoints(), and take
the polling interval from the interrupt endpoint actually used.
Define the interrupt endpoint by its number, like the bulk endpoints,
as the pipe macros expect an endpoint number rather than an address.
Fixes: 51dad33ede63 ("mfd: Add core driver for Nuvoton NCT6694")
Signed-off-by: Ming Yu <a0282524688@xxxxxxxxx>
---
Changes in v8:
- Also validate the bulk endpoints. Keep the fixed endpoint numbers and
check them with usb_check_{bulk,int}_endpoints() instead of looking
up the first endpoint of each type, as the interface exposes several
interrupt and bulk endpoints.
- Take the polling interval from the interrupt endpoint actually used,
and define it by its number like the bulk endpoints.
Changes in v7:
- New patch.
drivers/mfd/nct6694.c | 29 +++++++++++++++++------------
include/linux/mfd/nct6694.h | 2 +-
2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c
index 308b2fda3055..b9526b22754c 100644
--- a/drivers/mfd/nct6694.c
+++ b/drivers/mfd/nct6694.c
@@ -273,13 +273,25 @@ static const struct irq_domain_ops nct6694_irq_domain_ops = {
static int nct6694_usb_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
+ static const u8 bulk_ep_addr[] = {
+ USB_DIR_IN | NCT6694_BULK_IN_EP,
+ USB_DIR_OUT | NCT6694_BULK_OUT_EP,
+ 0
+ };
+ static const u8 int_ep_addr[] = {
+ USB_DIR_IN | NCT6694_INT_IN_EP,
+ 0
+ };
struct usb_device *udev = interface_to_usbdev(iface);
- struct usb_endpoint_descriptor *int_endpoint;
- struct usb_host_interface *interface;
struct device *dev = &iface->dev;
struct nct6694 *nct6694;
+ unsigned int int_pipe;
int ret;
+ if (!usb_check_bulk_endpoints(iface, bulk_ep_addr) ||
+ !usb_check_int_endpoints(iface, int_ep_addr))
+ return -ENODEV;
+
nct6694 = devm_kzalloc(dev, sizeof(*nct6694), GFP_KERNEL);
if (!nct6694)
return -ENOMEM;
@@ -318,17 +330,10 @@ static int nct6694_usb_probe(struct usb_interface *iface,
if (ret)
goto err_ida;
- interface = iface->cur_altsetting;
-
- int_endpoint = &interface->endpoint[0].desc;
- if (!usb_endpoint_is_int_in(int_endpoint)) {
- ret = -ENODEV;
- goto err_ida;
- }
-
- usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
+ int_pipe = usb_rcvintpipe(udev, NCT6694_INT_IN_EP);
+ usb_fill_int_urb(nct6694->int_in_urb, udev, int_pipe,
nct6694->int_buffer, sizeof(*nct6694->int_buffer), usb_int_callback,
- nct6694, int_endpoint->bInterval);
+ nct6694, usb_pipe_endpoint(udev, int_pipe)->desc.bInterval);
ret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL);
if (ret)
diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h
index 6eb9be2cd4a0..a5ad7be47bf9 100644
--- a/include/linux/mfd/nct6694.h
+++ b/include/linux/mfd/nct6694.h
@@ -10,7 +10,7 @@
#define NCT6694_VENDOR_ID 0x0416
#define NCT6694_PRODUCT_ID 0x200B
-#define NCT6694_INT_IN_EP 0x81
+#define NCT6694_INT_IN_EP 0x01
#define NCT6694_BULK_IN_EP 0x02
#define NCT6694_BULK_OUT_EP 0x03
--
2.34.1