Hello,
We are reporting the following crash (reproducer and a proposed patch attached):
Linux version 7.3.0-rc2 50d05c7c76c96b90462f24debacca971d2e86713
Build Config: UpstreamAppArmorKASAN (KASAN + UBSAN, panic_on_warn=1)
[ 50.563179][ T987] usb 3-1: new high-speed USB device number 2
using dummy_hcd
[ 50.724668][ T987] usb 3-1: New USB device found, idVendor=a257,
idProduct=2013, bcdDevice= 1.00
[ 50.728082][ T987] usb 3-1: New USB device strings: Mfr=0,
Product=0, SerialNumber=0
[ 50.757406][ T987] dln2 3-1:1.0: Diolan DLN2 serial 0
[ 50.763502][ T987] gpiochip_add_data_with_key: GPIOs 0..-1 (dln2)
failed to register, -22
[ 50.763517][ T987] dln2-gpio dln2-gpio.2.auto: failed to add gpio chip: -22
[ 50.763525][ T987] dln2-gpio dln2-gpio.2.auto: probe with driver
dln2-gpio failed with error -22
[ 50.789064][ T987] ------------[ cut here ]------------
[ 50.789071][ T987] UBSAN: shift-out-of-bounds in
drivers/spi/spi-dln2.c:179:15
[ 50.789083][ T987] shift exponent 18446744073709543487 is too
large for 64-bit type 'typeof(unsigned long)' (aka 'unsigned long')
[ 50.789098][ T987] CPU: 1 UID: 0 PID: 987 Comm: kworker/1:3 Not
tainted 7.3.0-rc2-00099-g50d05c7c76c9 #1 PREEMPT(full)
[ 50.789108][ T987] Hardware name: QEMU Standard PC (Q35 + ICH9,
2009), BIOS 1.17.0-debian-1.17.0-1ubuntu1 04/01/2014
[ 50.789114][ T987] Workqueue: usb_hub_wq hub_event
[ 50.791092][ T987] Call Trace:
[ 50.791098][ T987] <TASK>
[ 50.791106][ T987] dump_stack_lvl+0xe8/0x150
[ 50.791118][ T987] ubsan_epilogue+0xa/0x30
[ 50.791129][ T987] __ubsan_handle_shift_out_of_bounds+0x385/0x410
[
** replaying previous printk message **
[ 50.791149][ T987] dln2_spi_probe+0x104d/0x13c0
[ 50.791165][ T987] ? __pfx_dln2_spi_probe+0x10/0x10
[ 50.791178][ T987] ? up_write+0x1a5/0x4a0
[ 50.791189][ T987] ? kernfs_put+0x77b/0x7e0
[ 50.791200][ T987] ? acpi_has_method+0x20/0xe0
[ 50.791211][ T987] ? dev_pm_domain_attach+0xbd/0xf0
[ 50.791222][ T987] ? __pfx_dln2_spi_probe+0x10/0x10
[ 50.791232][ T987] platform_probe+0xf9/0x190
[ 50.791241][ T987] ? __pfx_platform_probe+0x10/0x10
[ 50.791248][ T987] really_probe+0x267/0xaf0
[ 50.791259][ T987] __driver_probe_device+0x1e2/0x350
[ 50.791269][ T987] driver_probe_device+0x4f/0x240
[ 50.791279][ T987] __device_attach_driver+0x270/0x410
[ 50.791290][ T987] bus_for_each_drv+0x258/0x2f0
[ 50.791301][ T987] ? __pfx___device_attach_driver+0x10/0x10
[ 50.791310][ T987] ? __pfx_bus_for_each_drv+0x10/0x10
[ 50.791321][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.792223][ T987] __device_attach+0x2c5/0x450
[ 50.792233][ T987] ? __pfx___device_attach+0x10/0x10
[ 50.792243][ T987] ? _raw_spin_unlock+0x28/0x50
[ 50.792254][ T987] device_initial_probe+0xa1/0xd0
[ 50.792263][ T987] bus_probe_device+0x12a/0x220
[ 50.792275][ T987] device_add+0x7ec/0xb90
[ 50.792285][ T987] platform_device_add+0x46a/0x800
[ 50.792296][ T987] ? __asan_memcpy+0x40/0x70
[ 50.792311][ T987] mfd_add_devices+0x125c/0x17c0
[ 50.792322][ T987] ? __dev_printk+0x131/0x190
[ 50.792339][ T987] ? __pfx_mfd_add_devices+0x10/0x10
[ 50.792353][ T987] ? dln2_hw_init+0x25c/0x270
[ 50.792362][ T987] ? __pfx_dln2_hw_init+0x10/0x10
[ 50.792374][ T987] dln2_probe+0xef9/0xfd0
[ 50.792383][ T987] ? __pfx_do_raw_spin_lock+0x10/0x10
[ 50.792398][ T987] ? __pfx_dln2_probe+0x10/0x10
[ 50.792406][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.792416][ T987] ? __pm_runtime_set_status+0x9d4/0xcd0
[ 50.792428][ T987] usb_probe_interface+0x71f/0xe00
[ 50.792443][ T987] ? __pfx_usb_probe_interface+0x10/0x10
[ 50.792457][ T987] ? driver_sysfs_add+0x1fe/0x210
[ 50.792466][ T987] ? __pfx_usb_probe_interface+0x10/0x10
[ 50.792475][ T987] really_probe+0x267/0xaf0
[ 50.792486][ T987] __driver_probe_device+0x1e2/0x350
[ 50.792496][ T987] driver_probe_device+0x4f/0x240
[ 50.792506][ T987] __device_attach_driver+0x270/0x410
[ 50.792517][ T987] bus_for_each_drv+0x258/0x2f0
[ 50.792527][ T987] ? __pfx___device_attach_driver+0x10/0x10
[ 50.792536][ T987] ? __pfx_bus_for_each_drv+0x10/0x10
[ 50.792548][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.792560][ T987] __device_attach+0x2c5/0x450
[ 50.792569][ T987] ? __pfx___device_attach+0x10/0x10
[ 50.792579][ T987] ? _raw_spin_unlock+0x28/0x50
[ 50.792590][ T987] device_initial_probe+0xa1/0xd0
[ 50.792599][ T987] bus_probe_device+0x12a/0x220
[ 50.792611][ T987] device_add+0x7ec/0xb90
[ 50.792621][ T987] usb_set_configuration+0x1a87/0x2110
[ 50.792642][ T987] usb_generic_driver_probe+0x8d/0x150
[ 50.792652][ T987] usb_probe_device+0x1c4/0x3b0
[ 50.792664][ T987] ? __pfx_usb_probe_device+0x10/0x10
[ 50.792673][ T987] really_probe+0x267/0xaf0
[ 50.792684][ T987] __driver_probe_device+0x1e2/0x350
[ 50.792694][ T987] driver_probe_device+0x4f/0x240
[ 50.792704][ T987] __device_attach_driver+0x270/0x410
[ 50.792714][ T987] bus_for_each_drv+0x258/0x2f0
[ 50.792724][ T987] ? __pfx___device_attach_driver+0x10/0x10
[ 50.792733][ T987] ? __pfx_bus_for_each_drv+0x10/0x10
[ 50.792745][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.792756][ T987] __device_attach+0x2c5/0x450
[ 50.792766][ T987] ? __pfx___device_attach+0x10/0x10
[ 50.792776][ T987] ? _raw_spin_unlock+0x28/0x50
[ 50.792786][ T987] device_initial_probe+0xa1/0xd0
[ 50.792796][ T987] bus_probe_device+0x12a/0x220
[ 50.792807][ T987] device_add+0x7ec/0xb90
[ 50.792817][ T987] usb_new_device+0xa14/0x1720
[ 50.792830][ T987] ? __pfx_usb_new_device+0x10/0x10
[ 50.792840][ T987] ? _raw_spin_unlock_irq+0x23/0x50
[ 50.792851][ T987] hub_event+0x2a1c/0x4f30
[ 50.792860][ T987] ? do_raw_spin_unlock+0xf5/0x200
[ 50.792888][ T987] ? __pfx_hub_event+0x10/0x10
[ 50.792901][ T987] ? process_scheduled_works+0x94e/0x1900
[ 50.792913][ T987] ? process_scheduled_works+0x94e/0x1900
[ 50.792923][ T987] ? process_scheduled_works+0x94e/0x1900
[ 50.792935][ T987] process_scheduled_works+0xc99/0x1900
[ 50.792959][ T987] ? __pfx_process_scheduled_works+0x10/0x10
[ 50.792973][ T987] ? assign_work+0x3d5/0x5e0
[ 50.792987][ T987] worker_thread+0xa53/0xfc0
[ 50.793006][ T987] kthread+0x38b/0x480
[ 50.793015][ T987] ? __pfx_worker_thread+0x10/0x10
[ 50.793022][ T987] ? __pfx_kthread+0x10/0x10
[ 50.793031][ T987] ret_from_fork+0x514/0xb70
[ 50.793042][ T987] ? __pfx_ret_from_fork+0x10/0x10
[ 50.793086][ T987] ? __switch_to+0xc79/0x1410
[ 50.793096][ T987] ? __pfx_kthread+0x10/0x10
[ 50.793106][ T987] ret_from_fork_asm+0x1a/0x30
[ 50.793123][ T987] </TASK>
[ 50.800603][ T987] ---[ end trace ]---
[ 50.800625][ T987] Kernel panic - not syncing: UBSAN: panic_on_warn set ...
[ 50.853815][ T987] CPU: 1 UID: 0 PID: 987 Comm: kworker/1:3 Not
tainted 7.3.0-rc2-00099-g50d05c7c76c9 #1 PREEMPT(full)
[ 50.854873][ T987] Hardware name: QEMU Standard PC (Q35 + ICH9,
2009), BIOS 1.17.0-debian-1.17.0-1ubuntu1 04/01/2014
[ 50.855914][ T987] Workqueue: usb_hub_wq hub_event
[ 50.856422][ T987] Call Trace:
[ 50.856764][ T987] <TASK>
[ 50.857132][ T987] vpanic+0x56d/0xa60
[ 50.857549][ T987] ? __pfx_vpanic+0x10/0x10
[ 50.858014][ T987] ? irqentry_exit+0x218/0x760
[ 50.858498][ T987] panic+0xc5/0xd0
[ 50.858872][ T987] ? __pfx_panic+0x10/0x10
[ 50.859323][ T987] ? __pfx__printk+0x10/0x10
[ 50.859785][ T987] check_panic_on_warn+0x89/0xb0
[ 50.860298][ T987] __ubsan_handle_shift_out_of_bounds+0x385/0x410
[ 50.860938][ T987] dln2_spi_probe+0x104d/0x13c0
[ 50.861434][ T987] ? __pfx_dln2_spi_probe+0x10/0x10
[ 50.861950][ T987] ? up_write+0x1a5/0x4a0
[ 50.862387][ T987] ? kernfs_put+0x77b/0x7e0
[ 50.862841][ T987] ? acpi_has_method+0x20/0xe0
[ 50.863325][ T987] ? dev_pm_domain_attach+0xbd/0xf0
[ 50.863841][ T987] ? __pfx_dln2_spi_probe+0x10/0x10
[ 50.864370][ T987] platform_probe+0xf9/0x190
[ 50.864838][ T987] ? __pfx_platform_probe+0x10/0x10
[ 50.865355][ T987] really_probe+0x267/0xaf0
[ 50.865868][ T987] __driver_probe_device+0x1e2/0x350
[ 50.866498][ T987] driver_probe_device+0x4f/0x240
[ 50.867121][ T987] __device_attach_driver+0x270/0x410
[ 50.867757][ T987] bus_for_each_drv+0x258/0x2f0
[ 50.868376][ T987] ? __pfx___device_attach_driver+0x10/0x10
[ 50.868990][ T987] ? __pfx_bus_for_each_drv+0x10/0x10
[ 50.869559][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.870253][ T987] __device_attach+0x2c5/0x450
[ 50.870822][ T987] ? __pfx___device_attach+0x10/0x10
[ 50.871465][ T987] ? _raw_spin_unlock+0x28/0x50
[ 50.872043][ T987] device_initial_probe+0xa1/0xd0
[ 50.872619][ T987] bus_probe_device+0x12a/0x220
[ 50.873137][ T987] device_add+0x7ec/0xb90
[ 50.873595][ T987] platform_device_add+0x46a/0x800
[ 50.874110][ T987] ? __asan_memcpy+0x40/0x70
[ 50.874573][ T987] mfd_add_devices+0x125c/0x17c0
[ 50.875072][ T987] ? __dev_printk+0x131/0x190
[ 50.875546][ T987] ? __pfx_mfd_add_devices+0x10/0x10
[ 50.876076][ T987] ? dln2_hw_init+0x25c/0x270
[ 50.876543][ T987] ? __pfx_dln2_hw_init+0x10/0x10
[ 50.877172][ T987] dln2_probe+0xef9/0xfd0
[ 50.877622][ T987] ? __pfx_do_raw_spin_lock+0x10/0x10
[ 50.878200][ T987] ? __pfx_dln2_probe+0x10/0x10
[ 50.878718][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.879294][ T987] ? __pm_runtime_set_status+0x9d4/0xcd0
[ 50.879850][ T987] usb_probe_interface+0x71f/0xe00
[ 50.880399][ T987] ? __pfx_usb_probe_interface+0x10/0x10
[ 50.880986][ T987] ? driver_sysfs_add+0x1fe/0x210
[ 50.881526][ T987] ? __pfx_usb_probe_interface+0x10/0x10
[ 50.882095][ T987] really_probe+0x267/0xaf0
[ 50.882548][ T987] __driver_probe_device+0x1e2/0x350
[ 50.883073][ T987] driver_probe_device+0x4f/0x240
[ 50.883573][ T987] __device_attach_driver+0x270/0x410
[ 50.884141][ T987] bus_for_each_drv+0x258/0x2f0
[ 50.884656][ T987] ? __pfx___device_attach_driver+0x10/0x10
[ 50.885280][ T987] ? __pfx_bus_for_each_drv+0x10/0x10
[ 50.885833][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.886446][ T987] __device_attach+0x2c5/0x450
[ 50.886950][ T987] ? __pfx___device_attach+0x10/0x10
[ 50.887564][ T987] ? _raw_spin_unlock+0x28/0x50
[ 50.888047][ T987] device_initial_probe+0xa1/0xd0
[ 50.888568][ T987] bus_probe_device+0x12a/0x220
[ 50.889062][ T987] device_add+0x7ec/0xb90
[ 50.889499][ T987] usb_set_configuration+0x1a87/0x2110
[ 50.890070][ T987] usb_generic_driver_probe+0x8d/0x150
[ 50.890610][ T987] usb_probe_device+0x1c4/0x3b0
[ 50.891161][ T987] ? __pfx_usb_probe_device+0x10/0x10
[ 50.891711][ T987] really_probe+0x267/0xaf0
[ 50.892200][ T987] __driver_probe_device+0x1e2/0x350
[ 50.892750][ T987] driver_probe_device+0x4f/0x240
[ 50.893307][ T987] __device_attach_driver+0x270/0x410
[ 50.893839][ T987] bus_for_each_drv+0x258/0x2f0
[ 50.894328][ T987] ? __pfx___device_attach_driver+0x10/0x10
[ 50.894910][ T987] ? __pfx_bus_for_each_drv+0x10/0x10
[ 50.895450][ T987] ? _raw_spin_unlock_irqrestore+0x4c/0x80
[ 50.896027][ T987] __device_attach+0x2c5/0x450
[ 50.896514][ T987] ? __pfx___device_attach+0x10/0x10
[ 50.897117][ T987] ? _raw_spin_unlock+0x28/0x50
[ 50.897603][ T987] device_initial_probe+0xa1/0xd0
[ 50.898107][ T987] bus_probe_device+0x12a/0x220
[ 50.898591][ T987] device_add+0x7ec/0xb90
[ 50.899061][ T987] usb_new_device+0xa14/0x1720
[ 50.899569][ T987] ? __pfx_usb_new_device+0x10/0x10
[ 50.900123][ T987] ? _raw_spin_unlock_irq+0x23/0x50
[ 50.900638][ T987] hub_event+0x2a1c/0x4f30
[ 50.901089][ T987] ? do_raw_spin_unlock+0xf5/0x200
[ 50.901613][ T987] ? __pfx_hub_event+0x10/0x10
[ 50.902109][ T987] ? process_scheduled_works+0x94e/0x1900
[ 50.902674][ T987] ? process_scheduled_works+0x94e/0x1900
[ 50.903247][ T987] ? process_scheduled_works+0x94e/0x1900
[ 50.903810][ T987] process_scheduled_works+0xc99/0x1900
[ 50.904376][ T987] ? __pfx_process_scheduled_works+0x10/0x10
[ 50.904968][ T987] ? assign_work+0x3d5/0x5e0
[ 50.905442][ T987] worker_thread+0xa53/0xfc0
[ 50.905917][ T987] kthread+0x38b/0x480
[ 50.906331][ T987] ? __pfx_worker_thread+0x10/0x10
[ 50.906838][ T987] ? __pfx_kthread+0x10/0x10
[ 50.907416][ T987] ret_from_fork+0x514/0xb70
[ 50.907877][ T987] ? __pfx_ret_from_fork+0x10/0x10
[ 50.908401][ T987] ? __switch_to+0xc79/0x1410
[ 50.908858][ T987] ? __pfx_kthread+0x10/0x10
[ 50.909334][ T987] ret_from_fork_asm+0x1a/0x30
[ 50.909818][ T987] </TASK>
[ 50.910402][ T987] Kernel Offset: disabled
[ 50.910950][ T987] Rebooting in 86400 seconds..
Regards,
SEFCOM Lab @ ASU
--- a/drivers/spi/spi-dln2.c
+++ b/drivers/spi/spi-dln2.c
@@ -70,7 +70,9 @@
#define DLN2_SPI_GET_MIN_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4B)
#define DLN2_SPI_GET_MAX_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4C)
#define DLN2_SPI_MAX_XFER_SIZE 256
+/* The CS bitmask is carried in a u8 on the wire, so 8 lines is the ceiling. */
+#define DLN2_SPI_MAX_CS 8
#define DLN2_SPI_BUF_SIZE (DLN2_SPI_MAX_XFER_SIZE + 16)
#define DLN2_SPI_ATTR_LEAVE_SS_LOW BIT(0)
#define DLN2_TRANSFERS_WAIT_COMPLETE 1
@@ -200,7 +202,9 @@ static int dln2_spi_get_cs_num(struct dln2_spi *dln2, u16 *cs_num)
if (rx_len < sizeof(rx))
return -EPROTO;
*cs_num = le16_to_cpu(rx.cs_count);
+ if (*cs_num == 0 || *cs_num > DLN2_SPI_MAX_CS)
+ return -EPROTO;
dev_dbg(&dln2->pdev->dev, "cs_num = %d\n", *cs_num);
/*
* Reproducer for 213-ubsan-shift-out-of-bounds-in-dln2-spi-probe
*/
#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/usb/ch9.h>
#include <linux/usb/raw_gadget.h>
#define EP0_MAX_TRANSFER 4096
#define BULK_MAX_TRANSFER 512
/* DLN2 protocol, drivers/mfd/dln2.c */
#define DLN2_HANDLE_CTRL 1
#define DLN2_HANDLE_SPI 4
#define DLN2_RESPONSE_HEADER_LEN 10 /* dln2_header{size,id,echo,handle} + __le16 result */
#define CMD_GET_DEVICE_VER 0x0030
#define DLN2_HW_ID 0x200 /* dln2_check_hw() rejects any other id */
#define SPI_GET_SS_COUNT 0x0244
/*
* The chip-select count we report as the device. dln2_spi_cs_enable_all()
* (drivers/spi/spi-dln2.c:179) does GENMASK(num_chipselect - 1, 0), which
* expands to ~0UL >> (BITS_PER_LONG - 1 - 8192). That shift count is
* 64 - 1 - 8192 = -8129, i.e. 18446744073709543487 as an unsigned long,
* which is the exponent UBSAN reports. Nothing in the driver bounds this
* against BITS_PER_LONG.
*/
#define BAD_CHIPSELECT_COUNT 8193
static int raw_gadget_fd = -1;
static int bulk_in_ep_handle = -1, bulk_out_ep_handle = -1;
static volatile int response_thread_started;
static void put_le16(__u8 *p, unsigned v) { p[0] = v; p[1] = v >> 8; }
static void put_le32(__u8 *p, unsigned v)
{
p[0] = v; p[1] = v >> 8; p[2] = v >> 16; p[3] = v >> 24;
}
/* descriptors of the emulated Diolan DLN-2 */
static struct usb_device_descriptor device_descriptor = {
.bLength = sizeof(struct usb_device_descriptor),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
.bMaxPacketSize0 = 64,
.idVendor = 0xa257, /* the dln2 usb_device_id: Diolan */
.idProduct = 0x2013, /* DLN-2 */
.bcdDevice = 0x0100,
.bNumConfigurations = 1,
};
#define LE16(v) ((v) & 0xff), (((v) >> 8) & 0xff)
static const __u8 configuration_descriptor[] = {
9, USB_DT_CONFIG, LE16(9 + 9 + 7 + 7), 1, 1, 0, 0x80, 0x32,
/* interface 0, vendor specific, 2 endpoints */
9, USB_DT_INTERFACE, 0, 0, 2, 0xff, 0x00, 0x00, 0,
/* EP 0x81 bulk IN */
7, USB_DT_ENDPOINT, 0x81, USB_ENDPOINT_XFER_BULK, LE16(BULK_MAX_TRANSFER), 0,
/* EP 0x02 bulk OUT */
7, USB_DT_ENDPOINT, 0x02, USB_ENDPOINT_XFER_BULK, LE16(BULK_MAX_TRANSFER), 0,
};
static struct usb_endpoint_descriptor bulk_in_ep_descriptor = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = BULK_MAX_TRANSFER,
};
static struct usb_endpoint_descriptor bulk_out_ep_descriptor = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x02,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = BULK_MAX_TRANSFER,
};
/*
* Answer the two dln2 requests that gate probe: the hardware id, and the
* chip-select count that carries the poisoned value. Everything else gets a
* zero payload, which every remaining dln2 cell treats as a benign answer.
*/
static void *dln2_response_thread(void *unused)
{
__u8 request_buffer[sizeof(struct usb_raw_ep_io) + BULK_MAX_TRANSFER];
__u8 response_buffer[sizeof(struct usb_raw_ep_io) + BULK_MAX_TRANSFER];
struct usb_raw_ep_io *request = (void *)request_buffer;
struct usb_raw_ep_io *response = (void *)response_buffer;
const unsigned payload_len = 64;
for (;;) {
unsigned id, echo, handle;
__u8 *payload;
int n;
request->ep = bulk_out_ep_handle;
request->flags = 0;
request->length = BULK_MAX_TRANSFER;
n = ioctl(raw_gadget_fd, USB_RAW_IOCTL_EP_READ, request);
if (n < 0) {
if (errno == EINTR || errno == EBUSY)
continue;
return unused;
}
if (n < 8)
continue;
id = request->data[2] | (request->data[3] << 8);
echo = request->data[4] | (request->data[5] << 8);
handle = request->data[6] | (request->data[7] << 8);
memset(response_buffer, 0, sizeof(response_buffer));
payload = response->data + DLN2_RESPONSE_HEADER_LEN;
if (handle == DLN2_HANDLE_CTRL && id == CMD_GET_DEVICE_VER)
put_le32(payload, DLN2_HW_ID);
else if (handle == DLN2_HANDLE_SPI && id == SPI_GET_SS_COUNT)
put_le16(payload, BAD_CHIPSELECT_COUNT);
/* dln2_rx() drops the response unless hdr.size == actual_length. */
put_le16(response->data + 0, DLN2_RESPONSE_HEADER_LEN + payload_len);
put_le16(response->data + 2, id);
put_le16(response->data + 4, echo);
put_le16(response->data + 6, handle);
/* response->data + 8 is __le16 result, already 0 == success */
response->ep = bulk_in_ep_handle;
response->flags = 0;
response->length = DLN2_RESPONSE_HEADER_LEN + payload_len;
ioctl(raw_gadget_fd, USB_RAW_IOCTL_EP_WRITE, response);
}
return unused;
}
static void handle_ep0_control(const struct usb_ctrlrequest *ctrl)
{
__u8 buffer[sizeof(struct usb_raw_ep_io) + EP0_MAX_TRANSFER];
struct usb_raw_ep_io *io = (void *)buffer;
int len = -1;
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
if ((ctrl->wValue >> 8) == USB_DT_DEVICE) {
len = sizeof(device_descriptor);
memcpy(io->data, &device_descriptor, len);
} else if ((ctrl->wValue >> 8) == USB_DT_CONFIG) {
len = sizeof(configuration_descriptor);
memcpy(io->data, configuration_descriptor, len);
}
break;
case USB_REQ_SET_CONFIGURATION: {
pthread_t response_thread;
ioctl(raw_gadget_fd, USB_RAW_IOCTL_CONFIGURE, 0);
bulk_in_ep_handle = ioctl(raw_gadget_fd,
USB_RAW_IOCTL_EP_ENABLE,
&bulk_in_ep_descriptor);
bulk_out_ep_handle = ioctl(raw_gadget_fd,
USB_RAW_IOCTL_EP_ENABLE,
&bulk_out_ep_descriptor);
if (bulk_in_ep_handle >= 0 && bulk_out_ep_handle >= 0 &&
!response_thread_started) {
response_thread_started = 1;
pthread_create(&response_thread, NULL,
dln2_response_thread, NULL);
}
len = 0;
break;
}
}
}
if (len < 0) {
ioctl(raw_gadget_fd, USB_RAW_IOCTL_EP0_STALL, 0);
return;
}
io->ep = 0;
io->flags = 0;
io->length = len < ctrl->wLength ? len : ctrl->wLength;
/* raw-gadget latches the direction per setup packet: a zero-length
* request is an OUT no matter what bRequestType says, and the opposite
* ioctl returns EBUSY. */
if (ctrl->bRequestType & USB_DIR_IN && ctrl->wLength)
ioctl(raw_gadget_fd, USB_RAW_IOCTL_EP0_WRITE, io);
else
ioctl(raw_gadget_fd, USB_RAW_IOCTL_EP0_READ, io);
}
int main(void)
{
__u8 event_buffer[sizeof(struct usb_raw_event) + EP0_MAX_TRANSFER];
struct usb_raw_event *event = (void *)event_buffer;
struct usb_raw_init init;
struct dirent *udc_entry;
DIR *udc_dir;
char *udc_index;
/* dummy_hcd numbers its UDCs, so the name must be discovered:
* device "dummy_udc.2" belongs to driver "dummy_udc". */
udc_dir = opendir("/sys/class/udc");
while (udc_dir && (udc_entry = readdir(udc_dir)) && udc_entry->d_name[0] == '.')
;
if (!udc_dir || !udc_entry) {
fprintf(stderr, "no UDC in /sys/class/udc\n");
return 1;
}
memset(&init, 0, sizeof(init));
snprintf((char *)init.device_name, UDC_NAME_LENGTH_MAX, "%s", udc_entry->d_name);
snprintf((char *)init.driver_name, UDC_NAME_LENGTH_MAX, "%s", udc_entry->d_name);
closedir(udc_dir);
udc_index = strrchr((char *)init.driver_name, '.');
if (udc_index)
*udc_index = 0;
init.speed = USB_SPEED_HIGH;
raw_gadget_fd = open("/dev/raw-gadget", O_RDWR);
if (raw_gadget_fd < 0) {
perror("/dev/raw-gadget");
return 1;
}
if (ioctl(raw_gadget_fd, USB_RAW_IOCTL_INIT, &init) < 0) {
perror("USB_RAW_IOCTL_INIT");
return 1;
}
/* RUN must precede EVENT_FETCH: the device has to be in
* STATE_DEV_RUNNING or the fetch returns -EINVAL. */
if (ioctl(raw_gadget_fd, USB_RAW_IOCTL_RUN, 0) < 0) {
perror("USB_RAW_IOCTL_RUN");
return 1;
}
for (;;) {
event->type = 0;
event->length = EP0_MAX_TRANSFER;
if (ioctl(raw_gadget_fd, USB_RAW_IOCTL_EVENT_FETCH, event) < 0) {
if (errno == EINTR)
continue;
perror("USB_RAW_IOCTL_EVENT_FETCH");
return 1;
}
if (event->type == USB_RAW_EVENT_CONTROL)
handle_ep0_control((struct usb_ctrlrequest *)event->data);
}
return 0;
}
On Wed, Sep 09, 2026 at 05:33:20PM -0700, Farhad Alemi wrote: > We are reporting the following crash (reproducer and a proposed patch attached): Thank you. Please, submit the patch as a formal fix. You can find the necessary steps in the Submitting Patches documentation. > Linux version 7.3.0-rc2 50d05c7c76c96b90462f24debacca971d2e86713 > Build Config: UpstreamAppArmorKASAN (KASAN + UBSAN, panic_on_warn=1) -- With Best Regards, Andy Shevchenko
© 2016 - 2026 Red Hat, Inc.