lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CALU+5Vb8kFrR_HMOrBDktxEEQE4d4qBTijVpSdSQz4d3qXsfJQ@mail.gmail.com>
Date: Fri, 25 Jul 2025 23:09:26 +0200
From: Olivier Tuchon <tcn@...gle.com>
To: Greg KH <gregkh@...uxfoundation.org>, Alan Stern <stern@...land.harvard.edu>
Cc: linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH v2] usb: gadget: Address review comments and include missing files

This patch addresses feedback on v1 from greg k-h and Alan Stern. It
also includes files that were missing from the initial submission.

The following changes have been made:
  - correct initial coding style issue (spaces for tabs)
  - add missing file required for the feature to build and run
  - improve FIFO full handling by truncating event data instead of
    dropping the event entirely
  - avoid capturing redundant data for IN submissions

Signed-off-by: Olivier Tuchon <tcn@...gle.com>
---
 drivers/usb/Kconfig                     |  2 +
 drivers/usb/Makefile                    |  1 +
 drivers/usb/gadget/udc/core.c           | 78 +++++++++++++++++++++++++
 drivers/usb/gadget_mon/Kconfig          | 20 +++----
 drivers/usb/gadget_mon/gadgetmon_main.c | 41 ++++++++-----
 include/linux/usb/gadget.h              | 23 ++++++++
 6 files changed, 141 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index abf8c6cdea9e..b615035cc7c6 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -107,6 +107,8 @@ source "drivers/usb/core/Kconfig"

 source "drivers/usb/mon/Kconfig"

+source "drivers/usb/gadget_mon/Kconfig"
+
 source "drivers/usb/host/Kconfig"

 source "drivers/usb/renesas_usbhs/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 949eca0adebe..2539151a5366 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb/
 obj-$(CONFIG_USB_CHIPIDEA) += chipidea/
 obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
 obj-$(CONFIG_USB_GADGET) += gadget/
+obj-$(CONFIG_USB_GADGET_MON) += gadget_mon/

 obj-$(CONFIG_USBIP_CORE) += usbip/

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index d709e24c1fd4..a7d22ef3ad74 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -28,6 +28,16 @@ static DEFINE_IDA(gadget_id_numbers);

 static const struct bus_type gadget_bus_type;

+/* ------------------------------------------------------------------------- */
+
+/* USB Gadget monitoring */
+#if IS_ENABLED(CONFIG_USB_GADGET_MON)
+static DEFINE_MUTEX(gadget_mon_lock);
+static const struct usb_gadget_mon_operations *gadget_mon_ops;
+#endif
+
+/* ------------------------------------------------------------------------- */
+
 /**
  * struct usb_udc - describes one usb device controller
  * @driver: the gadget driver pointer. For use by the class code
@@ -302,6 +312,18 @@ int usb_ep_queue(struct usb_ep *ep,
 out:
  trace_usb_ep_queue(ep, req, ret);

+#if IS_ENABLED(CONFIG_USB_GADGET_MON)
+ if (unlikely(rcu_access_pointer(gadget_mon_ops))) {
+ const struct usb_gadget_mon_operations *ops;
+
+ rcu_read_lock();
+ ops = rcu_dereference(gadget_mon_ops);
+ if (ops)
+ ops->request_queue(ep, req, ret);
+ rcu_read_unlock();
+ }
+#endif /* CONFIG_USB_GADGET_MON */
+
  return ret;
 }
 EXPORT_SYMBOL_GPL(usb_ep_queue);
@@ -996,6 +1018,18 @@ void usb_gadget_giveback_request(struct usb_ep *ep,

  trace_usb_gadget_giveback_request(ep, req, 0);

+#if IS_ENABLED(CONFIG_USB_GADGET_MON)
+ if (unlikely(rcu_access_pointer(gadget_mon_ops))) {
+ const struct usb_gadget_mon_operations *ops;
+
+ rcu_read_lock();
+ ops = rcu_dereference(gadget_mon_ops);
+ if (ops)
+ ops->request_giveback(ep, req);
+ rcu_read_unlock();
+ }
+#endif /* CONFIG_USB_GADGET_MON */
+
  req->complete(ep, req);
 }
 EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
@@ -1925,6 +1959,50 @@ static void __exit usb_udc_exit(void)
 }
 module_exit(usb_udc_exit);

+/* ------------------------------------------------------------------------- */
+
+/* USB Gadget monitoring */
+#if IS_ENABLED(CONFIG_USB_GADGET_MON)
+/*
+ * register_gadget_monitor - Register a monitoring module.
+ * @ops: the monitoring operations to register
+ *
+ * Allows a monitoring module to register its callbacks. Returns -EBUSY
+ * if a monitor is already registered
+ */
+int register_gadget_monitor(const struct usb_gadget_mon_operations *ops)
+{
+ int ret = 0;
+
+ mutex_lock(&gadget_mon_lock);
+ if (gadget_mon_ops)
+ ret = -EBUSY;
+ else
+ rcu_assign_pointer(gadget_mon_ops, ops);
+ mutex_unlock(&gadget_mon_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_gadget_monitor);
+
+/*
+ * unregister_gadget_monitor - Unregister a monitoring module.
+ * @ops: the monitoring operations to unregister
+ *
+ * A module must call this to unregister its callbacks before exiting
+ */
+void unregister_gadget_monitor(const struct usb_gadget_mon_operations *ops)
+{
+ mutex_lock(&gadget_mon_lock);
+ if (gadget_mon_ops == ops)
+ rcu_assign_pointer(gadget_mon_ops, NULL);
+ mutex_unlock(&gadget_mon_lock);
+
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(unregister_gadget_monitor);
+#endif
+
 MODULE_DESCRIPTION("UDC Framework");
 MODULE_AUTHOR("Felipe Balbi <balbi@...com>");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget_mon/Kconfig b/drivers/usb/gadget_mon/Kconfig
index 113423a2a96f..bfda5c006909 100644
--- a/drivers/usb/gadget_mon/Kconfig
+++ b/drivers/usb/gadget_mon/Kconfig
@@ -4,18 +4,18 @@
 #

 config USB_GADGET_MON
-  tristate "Gadget-side USB monitor"
-  depends on USB_GADGET
-  help
-    This option enables a low-level monitor for the USB gadget
-    subsystem, similar to what usbmon provides for the host side.
+ tristate "Gadget-side USB monitor"
+ depends on USB_GADGET
+ help
+   This option enables a low-level monitor for the USB gadget
+   subsystem, similar to what usbmon provides for the host side.

-    It creates a character device (/dev/gadgetmon0) that outputs a
-    stream of all USB request submissions and completions, allowing
-    for detailed debugging and performance analysis of gadget drivers.
+   It creates a character device (/dev/gadgetmon0) that outputs a
+   stream of all USB request submissions and completions, allowing
+   for detailed debugging and performance analysis of gadget drivers.

-    This is primarily a tool for developers. If you are not developing
-    or debugging a USB gadget function driver, say N.
+   This is primarily a tool for developers. If you are not developing
+   or debugging a USB gadget function driver, say N.

 config GADGETMON_BUFFER_SIZE_MB
  int "Buffer size for gadget monitor (in MiB)"
diff --git a/drivers/usb/gadget_mon/gadgetmon_main.c
b/drivers/usb/gadget_mon/gadgetmon_main.c
index 9017f91808ae..4597f10abc5e 100644
--- a/drivers/usb/gadget_mon/gadgetmon_main.c
+++ b/drivers/usb/gadget_mon/gadgetmon_main.c
@@ -50,7 +50,8 @@ static void gadgetmon_event(enum
gadgetmon_event_type event_type,
  unsigned long flags;
  struct gadgetmon_hdr hdr;
  u32 payload_len;
- u32 total_len;
+ u32 available_space;
+ u32 payload_to_copy;
  struct timespec64 ts;

  if (!req || !ep)
@@ -78,28 +79,32 @@ static void gadgetmon_event(enum
gadgetmon_event_type event_type,
  if (payload_len > GADGETMON_DATA_MAX)
  payload_len = GADGETMON_DATA_MAX;
  /*
- * optimization: for an OUT submission (host-to-device), the data
- * has not yet arrived from the host. The buffer is an empty
- * placeholder, so its content is not captured to save space.
+ * optimization: for all submission, the buffer data is not yet
+ * relevant. Capture no payload to save significant buffer space.
  */
- if (event_type == GADGETMON_EVENT_SUBMIT && hdr.dir == USB_DIR_OUT)
+ if (event_type == GADGETMON_EVENT_SUBMIT)
  payload_len = 0;

  hdr.data_len = payload_len;
- total_len = sizeof(hdr) + payload_len;

  /* lock and queue the event into the FIFO */
  spin_lock_irqsave(&mon_lock, flags);

- if (kfifo_avail(&mon_fifo) < total_len) {
- /* not enough space, drop the event silently */
+ available_space = kfifo_avail(&mon_fifo);
+
+ /* if the header itself doesn't fit, we must drop the even */
+ if (available_space < sizeof(hdr)) {
  spin_unlock_irqrestore(&mon_lock, flags);
  return;
  }

+ payload_to_copy = min(payload_len, available_space - sizeof(hdr));
+ if (payload_to_copy != payload_len)
+ hdr.data_len = payload_to_copy;
+
  kfifo_in(&mon_fifo, &hdr, sizeof(hdr));
- if (payload_len > 0)
- kfifo_in(&mon_fifo, req->buf, payload_len);
+ if (payload_to_copy > 0)
+ kfifo_in(&mon_fifo, req->buf, payload_to_copy);

  spin_unlock_irqrestore(&mon_lock, flags);

@@ -251,13 +256,20 @@ static int __init gadgetmon_init(void)
  goto err_del_cdev;
  }

- /* Atomically publish our monitoring functions to the UDC core */
- rcu_assign_pointer(gadget_mon_ops, &gadget_mon_ops_impl);
+ /* register our monitoring functions with the UDC core */
+ ret = register_gadget_monitor(&gadget_mon_ops_impl);
+ if (ret) {
+ pr_err("gadgetmon: Failed to register monitor, is another one loaded? (%d)\n",
+        ret);
+ goto err_destroy_device;
+ }

  pr_info("gadgetmon: Gadget Monitoring driver loaded\n");

  return 0;

+err_destroy_device:
+ device_destroy(mon_class, mon_dev_t);
 err_del_cdev:
  cdev_del(&mon_cdev);
 err_destroy_class:
@@ -278,8 +290,9 @@ static int __init gadgetmon_init(void)
  */
 static void __exit gadgetmon_exit(void)
 {
- rcu_assign_pointer(gadget_mon_ops, NULL);
- synchronize_rcu();
+ pr_info("Gadget Monitoring driver unloading\n");
+
+ unregister_gadget_monitor(&gadget_mon_ops_impl);

  device_destroy(mon_class, mon_dev_t);
  cdev_del(&mon_cdev);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index df33333650a0..a263b8ea968f 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -971,4 +971,27 @@ extern void usb_ep_autoconfig_release(struct usb_ep *);

 extern void usb_ep_autoconfig_reset(struct usb_gadget *);

+/*-------------------------------------------------------------------------*/
+
+/* USB Gadget monitoring */
+#if IS_ENABLED(CONFIG_USB_GADGET_MON)
+/**
+ * struct usb_gadget_mon_operations - operations for gadget monitoring
+ * @request_queue: Called when a gadget driver queues a request.
+ * @request_giveback: Called just before a request is given back.
+ */
+struct usb_gadget_mon_operations {
+ void (*request_queue)(struct usb_ep *ep, const struct usb_request *req,
+ int status);
+ void (*request_giveback)(struct usb_ep *ep,
+ const struct usb_request *req);
+};
+
+int register_gadget_monitor(const struct usb_gadget_mon_operations *ops);
+void unregister_gadget_monitor(const struct usb_gadget_mon_operations *ops);
+#else
+static inline int register_gadget_monitor(const void *ops) { return 0; }
+static inline void unregister_gadget_monitor(const void *ops) { }
+#endif /* CONFIG_USB_GADGET_MON */
+
 #endif /* __LINUX_USB_GADGET_H */
-- 
2.50.1.487.gc89ff58d15-goog

Changes in v2:
  - Add optimization to skip capturing IN submissions
  - Truncate event payload on FIFO full instead of dropping (as
    suggested)
  - Added forgotten files (include/linux/usb/gadget.h,
    drivers/usb/core/Kconfig, drivers/usb/Makefile,
    drivers/usb/gadget/udc/core.c)
  - Fixed initial indentation issues

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ