| 0/0 |
2026/05/21 09:23 |
flow |
assessment-security |
55m
Results: map[DenialOfService:true Explanation:Based on the analysis of the bug report and the kernel source code, here is the
assessment of the vulnerability:
### Bug Mechanism
The bug is a race condition in the `cm109` USB driver (for C-Media CM109/CM119
USB phones) that leads to a double submission of the same USB Request Block
(URB), causing a double `list_add` and subsequent list corruption in the USB
core.
When a CM109 USB device is plugged in, the kernel registers it as an input
device. The VT keyboard handler (`kbd_connect`) automatically opens the device,
invoking the driver's `cm109_input_open()` callback. This function initializes
the device and submits the control URB (`dev->urb_ctl`) to the USB core.
Crucially, it does so **without** holding the driver's `dev->ctl_submit_lock`.
Concurrently, if a terminal bell event is triggered (e.g., an unprivileged user
printing a `\a` bell character to a virtual terminal like `/dev/tty1`),
`kd_mksound()` injects a sound event into the input subsystem. This invokes the
driver's `cm109_input_ev()` callback, which calls `cm109_toggle_buzzer_async()`.
This function takes the `dev->ctl_submit_lock`, checks if the control URB is
already pending, and if not, submits `dev->urb_ctl`.
Because `cm109_input_open()` does not hold the lock, both functions can execute
concurrently. They can both observe the URB as not pending and call
`usb_submit_urb(dev->urb_ctl)` simultaneously. The USB core's `usb_submit_urb()`
checks if the URB is already active by verifying `urb->hcpriv == NULL` without
any locks. Both threads can pass this check before the Host Controller Driver
(HCD) has a chance to set `urb->hcpriv`. Consequently, both threads proceed to
enqueue the URB, leading to a double `list_add` in the HCD's endpoint queue
(`usb_hcd_link_urb_to_ep`).
### Security Impact
* **Exploitable & Denial of Service:** Yes. A double `list_add` corrupts the
kernel's internal linked lists. While `CONFIG_DEBUG_LIST` (if enabled) will
catch this and safely crash the kernel (Denial of Service), production kernels
typically disable list debugging for performance. In such cases, the list
corruption can be manipulated to achieve arbitrary memory read/write or
use-after-free, which is a classic vector for privilege escalation.
* **Peripheral Trigger:** Yes. The bug requires the attacker to plug in a
malicious or standard CM109 USB device to trigger the `cm109_input_open()` path
while simultaneously triggering a terminal bell.
* **VM Host Trigger:** Yes. A malicious hypervisor can hotplug a virtual CM109
USB device into a Confidential Computing guest to trigger the vulnerability and
compromise the guest kernel.
* **Accessible From Unprivileged Processes:** No. While an unprivileged user can
trigger the terminal bell, they cannot trigger the `cm109_input_open()` path
without physical access to plug in the USB device, as unprivileged users do not
have the permissions to open `/dev/input/eventX` devices directly or emulate USB
devices via `/dev/raw-gadget`. Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:true]
|
| 1/1 |
2026/05/21 09:23 |
action |
syz-repro-to-c-repro |
0m
Results: map[SimplifiedCRepro:// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/usb/ch9.h>
static unsigned long long procid;
static void sleep_ms(uint64_t ms)
{
usleep(ms * 1000);
}
#define MAX_FDS 30
#define USB_MAX_IFACE_NUM 4
#define USB_MAX_EP_NUM 32
#define USB_MAX_FDS 6
struct usb_endpoint_index {
struct usb_endpoint_descriptor desc;
int handle;
};
struct usb_iface_index {
struct usb_interface_descriptor* iface;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bInterfaceClass;
struct usb_endpoint_index eps[USB_MAX_EP_NUM];
int eps_num;
};
struct usb_device_index {
struct usb_device_descriptor* dev;
struct usb_config_descriptor* config;
uint8_t bDeviceClass;
uint8_t bMaxPower;
int config_length;
struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
int ifaces_num;
int iface_cur;
};
struct usb_info {
int fd;
struct usb_device_index index;
};
static struct usb_info usb_devices[USB_MAX_FDS];
static struct usb_device_index* lookup_usb_index(int fd)
{
for (int i = 0; i < USB_MAX_FDS; i++) {
if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd)
return &usb_devices[i].index;
}
return NULL;
}
static int usb_devices_num;
static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index)
{
if (length < sizeof(*index->dev) + sizeof(*index->config))
return false;
memset(index, 0, sizeof(*index));
index->dev = (struct usb_device_descriptor*)buffer;
index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
index->bDeviceClass = index->dev->bDeviceClass;
index->bMaxPower = index->config->bMaxPower;
index->config_length = length - sizeof(*index->dev);
index->iface_cur = -1;
size_t offset = 0;
while (true) {
if (offset + 1 >= length)
break;
uint8_t desc_length = buffer[offset];
uint8_t desc_type = buffer[offset + 1];
if (desc_length <= 2)
break;
if (offset + desc_length > length)
break;
if (desc_type == USB_DT_INTERFACE && index->ifaces_num < USB_MAX_IFACE_NUM) {
struct usb_interface_descriptor* iface = (struct usb_interface_descriptor*)(buffer + offset);
index->ifaces[index->ifaces_num].iface = iface;
index->ifaces[index->ifaces_num].bInterfaceNumber = iface->bInterfaceNumber;
index->ifaces[index->ifaces_num].bAlternateSetting = iface->bAlternateSetting;
index->ifaces[index->ifaces_num].bInterfaceClass = iface->bInterfaceClass;
index->ifaces_num++;
}
if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
if (iface->eps_num < USB_MAX_EP_NUM) {
memcpy(&iface->eps[iface->eps_num].desc, buffer + offset, sizeof(iface->eps[iface->eps_num].desc));
iface->eps_num++;
}
}
offset += desc_length;
}
return true;
}
static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t dev_len)
{
int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED);
if (i >= USB_MAX_FDS)
return NULL;
if (!parse_usb_descriptor(dev, dev_len, &usb_devices[i].index))
return NULL;
__atomic_store_n(&usb_devices[i].fd, fd, __ATOMIC_RELEASE);
return &usb_devices[i].index;
}
struct vusb_connect_string_descriptor {
uint32_t len;
char* str;
} __attribute__((packed));
struct vusb_connect_descriptors {
uint32_t qual_len;
char* qual;
uint32_t bos_len;
char* bos;
uint32_t strs_len;
struct vusb_connect_string_descriptor strs[0];
} __attribute__((packed));
static const char default_string[] = {
8, USB_DT_STRING,
's', 0, 'y', 0, 'z', 0
};
static const char default_lang_id[] = {
4, USB_DT_STRING,
0x09, 0x04
};
static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl,
struct usb_qualifier_descriptor* qual,
char** response_data, uint32_t* response_length)
{
struct usb_device_index* index = lookup_usb_index(fd);
uint8_t str_idx;
if (!index)
return false;
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
switch (ctrl->wValue >> 8) {
case USB_DT_DEVICE:
*response_data = (char*)index->dev;
*response_length = sizeof(*index->dev);
return true;
case USB_DT_CONFIG:
*response_data = (char*)index->config;
*response_length = index->config_length;
return true;
case USB_DT_STRING:
str_idx = (uint8_t)ctrl->wValue;
if (descs && str_idx < descs->strs_len) {
*response_data = descs->strs[str_idx].str;
*response_length = descs->strs[str_idx].len;
return true;
}
if (str_idx == 0) {
*response_data = (char*)&default_lang_id[0];
*response_length = default_lang_id[0];
return true;
}
*response_data = (char*)&default_string[0];
*response_length = default_string[0];
return true;
case USB_DT_BOS:
*response_data = descs->bos;
*response_length = descs->bos_len;
return true;
case USB_DT_DEVICE_QUALIFIER:
if (!descs->qual) {
qual->bLength = sizeof(*qual);
qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
qual->bcdUSB = index->dev->bcdUSB;
qual->bDeviceClass = index->dev->bDeviceClass;
qual->bDeviceSubClass = index->dev->bDeviceSubClass;
qual->bDeviceProtocol = index->dev->bDeviceProtocol;
qual->bMaxPacketSize0 = index->dev->bMaxPacketSize0;
qual->bNumConfigurations = index->dev->bNumConfigurations;
qual->bRESERVED = 0;
*response_data = (char*)qual;
*response_length = sizeof(*qual);
return true;
}
*response_data = descs->qual;
*response_length = descs->qual_len;
return true;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
return false;
}
typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl, bool* done);
static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl, bool* done)
{
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
switch (ctrl->bRequest) {
case USB_REQ_SET_CONFIGURATION:
*done = true;
return true;
default:
break;
}
break;
}
return false;
}
#define UDC_NAME_LENGTH_MAX 128
struct usb_raw_init {
__u8 driver_name[UDC_NAME_LENGTH_MAX];
__u8 device_name[UDC_NAME_LENGTH_MAX];
__u8 speed;
};
enum usb_raw_event_type {
USB_RAW_EVENT_INVALID = 0,
USB_RAW_EVENT_CONNECT = 1,
USB_RAW_EVENT_CONTROL = 2,
};
struct usb_raw_event {
__u32 type;
__u32 length;
__u8 data[0];
};
struct usb_raw_ep_io {
__u16 ep;
__u16 flags;
__u32 length;
__u8 data[0];
};
#define USB_RAW_EPS_NUM_MAX 30
#define USB_RAW_EP_NAME_MAX 16
#define USB_RAW_EP_ADDR_ANY 0xff
struct usb_raw_ep_caps {
__u32 type_control : 1;
__u32 type_iso : 1;
__u32 type_bulk : 1;
__u32 type_int : 1;
__u32 dir_in : 1;
__u32 dir_out : 1;
};
struct usb_raw_ep_limits {
__u16 maxpacket_limit;
__u16 max_streams;
__u32 reserved;
};
struct usb_raw_ep_info {
__u8 name[USB_RAW_EP_NAME_MAX];
__u32 addr;
struct usb_raw_ep_caps caps;
struct usb_raw_ep_limits limits;
};
struct usb_raw_eps_info {
struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX];
};
#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init)
#define USB_RAW_IOCTL_RUN _IO('U', 1)
#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event)
#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32)
#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9)
#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32)
#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info)
#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12)
#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32)
#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32)
#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32)
static int usb_raw_open()
{
return open("/dev/raw-gadget", O_RDWR);
}
static int usb_raw_init(int fd, uint32_t speed, const char* driver, const char* device)
{
struct usb_raw_init arg;
strncpy((char*)&arg.driver_name[0], driver, sizeof(arg.driver_name));
strncpy((char*)&arg.device_name[0], device, sizeof(arg.device_name));
arg.speed = speed;
return ioctl(fd, USB_RAW_IOCTL_INIT, &arg);
}
static int usb_raw_run(int fd)
{
return ioctl(fd, USB_RAW_IOCTL_RUN, 0);
}
static int usb_raw_configure(int fd)
{
return ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0);
}
static int usb_raw_vbus_draw(int fd, uint32_t power)
{
return ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power);
}
static int usb_raw_ep0_write(int fd, struct usb_raw_ep_io* io)
{
return ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io);
}
static int usb_raw_ep0_read(int fd, struct usb_raw_ep_io* io)
{
return ioctl(fd, USB_RAW_IOCTL_EP0_READ, io);
}
static int usb_raw_event_fetch(int fd, struct usb_raw_event* event)
{
return ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event);
}
static int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
{
return ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc);
}
static int usb_raw_ep_disable(int fd, int ep)
{
return ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, ep);
}
static int usb_raw_ep0_stall(int fd)
{
return ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0);
}
#define USB_MAX_PACKET_SIZE 4096
struct usb_raw_control_event {
struct usb_raw_event inner;
struct usb_ctrlrequest ctrl;
char data[USB_MAX_PACKET_SIZE];
};
struct usb_raw_ep_io_data {
struct usb_raw_ep_io inner;
char data[USB_MAX_PACKET_SIZE];
};
static void set_interface(int fd, int n)
{
struct usb_device_index* index = lookup_usb_index(fd);
if (!index)
return;
if (index->iface_cur >= 0 && index->iface_cur < index->ifaces_num) {
for (int ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++) {
int rv = usb_raw_ep_disable(fd, index->ifaces[index->iface_cur].eps[ep].handle);
if (rv < 0) {
} else {
}
}
}
if (n >= 0 && n < index->ifaces_num) {
for (int ep = 0; ep < index->ifaces[n].eps_num; ep++) {
int rv = usb_raw_ep_enable(fd, &index->ifaces[n].eps[ep].desc);
if (rv < 0) {
} else {
index->ifaces[n].eps[ep].handle = rv;
}
}
index->iface_cur = n;
}
}
static int configure_device(int fd)
{
struct usb_device_index* index = lookup_usb_index(fd);
if (!index)
return -1;
int rv = usb_raw_vbus_draw(fd, index->bMaxPower);
if (rv < 0) {
return rv;
}
rv = usb_raw_configure(fd);
if (rv < 0) {
return rv;
}
set_interface(fd, 0);
return 0;
}
static volatile long syz_usb_connect_impl(uint64_t speed, uint64_t dev_len, const char* dev,
const struct vusb_connect_descriptors* descs,
lookup_connect_out_response_t lookup_connect_response_out)
{
if (!dev) {
return -1;
}
int fd = usb_raw_open();
if (fd < 0) {
return fd;
}
if (fd >= MAX_FDS) {
close(fd);
return -1;
}
struct usb_device_index* index = add_usb_index(fd, dev, dev_len);
if (!index) {
return -1;
}
char device[32];
sprintf(&device[0], "dummy_udc.%llu", procid);
int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]);
if (rv < 0) {
return rv;
}
rv = usb_raw_run(fd);
if (rv < 0) {
return rv;
}
bool done = false;
while (!done) {
struct usb_raw_control_event event;
event.inner.type = 0;
event.inner.length = sizeof(event.ctrl);
rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
if (rv < 0) {
return rv;
}
if (event.inner.type != USB_RAW_EVENT_CONTROL)
continue;
char* response_data = NULL;
uint32_t response_length = 0;
struct usb_qualifier_descriptor qual;
if (event.ctrl.bRequestType & USB_DIR_IN) {
if (!lookup_connect_response_in(fd, descs, &event.ctrl, &qual, &response_data, &response_length)) {
usb_raw_ep0_stall(fd);
continue;
}
} else {
if (!lookup_connect_response_out(fd, descs, &event.ctrl, &done)) {
usb_raw_ep0_stall(fd);
continue;
}
response_data = NULL;
response_length = event.ctrl.wLength;
}
if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
event.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
rv = configure_device(fd);
if (rv < 0) {
return rv;
}
}
struct usb_raw_ep_io_data response;
response.inner.ep = 0;
response.inner.flags = 0;
if (response_length > sizeof(response.data))
response_length = 0;
if (event.ctrl.wLength < response_length)
response_length = event.ctrl.wLength;
response.inner.length = response_length;
if (response_data)
memcpy(&response.data[0], response_data, response_length);
else
memset(&response.data[0], 0, response_length);
if (event.ctrl.bRequestType & USB_DIR_IN) {
rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
} else {
rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
}
if (rv < 0) {
return rv;
}
}
sleep_ms(200);
return fd;
}
static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
uint64_t speed = a0;
uint64_t dev_len = a1;
const char* dev = (const char*)a2;
const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;
return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_generic);
}
static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
{
if (a0 == 0xc || a0 == 0xb) {
char buf[128];
sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1, (uint8_t)a2);
return open(buf, O_RDWR, 0);
} else {
unsigned long nb = a1;
char buf[1024];
char* hash;
strncpy(buf, (char*)a0, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;
while ((hash = strchr(buf, '#'))) {
*hash = '0' + (char)(nb % 10);
nb /= 10;
}
return open(buf, a2 & ~O_CREAT, 0);
}
}
uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
intptr_t res = 0;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
// syz_usb_connect arguments: [
// speed: usb_device_speed = 0x0 (8 bytes)
// dev_len: len = 0x2d (8 bytes)
// dev: ptr[inout, array[ANYUNION]] {
// array[ANYUNION] {
// union ANYUNION {
// ANYBLOB: buffer: {12 01 00 00 75 16 b7 10 8c 0d 0e 00 8f 8e 00 18 03 01 09 02 1b 00 01 00 00 00 00 09 04 08 00 01 03 00 00 00 09 05} (length 0x26)
// }
// union ANYUNION {
// ANYBLOB: buffer: {8f cf} (length 0x2)
// }
// }
// }
// conn_descs: nil
// ]
// returns fd_usb
memcpy((void*)0x200000000000, "... [truncated large byte array] ...", 38);
memcpy((void*)0x200000000026, "\x8f\xcf", 2);
syz_usb_connect(/*speed=*/0, /*dev_len=*/0x2d, /*dev=*/0x200000000000, /*conn_descs=*/0);
// syz_open_dev$tty1 arguments: [
// dev: const = 0xc (8 bytes)
// major: const = 0x4 (8 bytes)
// minor: intptr = 0x1 (8 bytes)
// ]
// returns fd_tty
res = -1;
res = syz_open_dev(/*dev=*/0xc, /*major=*/4, /*minor=*/1);
if (res != -1)
r[0] = res;
// dup arguments: [
// oldfd: fd (resource)
// ]
// returns fd
res = syscall(__NR_dup, /*oldfd=*/r[0]);
if (res != -1)
r[1] = res;
// write$UHID_INPUT arguments: [
// fd: fd_uhid (resource)
// data: ptr[in, uhid_req[UHID_INPUT, uhid_input_req]] {
// uhid_req[UHID_INPUT, uhid_input_req] {
// type: const = 0x9 (4 bytes)
// data: uhid_input_req {
// data: buffer: {a2 e3 ad 21 4f c7 52 f9 1b 29 09 09 4b f7 0e 0d d0 38 e7 ff 7f c6 e5 53 9b 32 4c 07 8b 08 9b 07 33 3b 6c 1a 08 90 e0 87 8f 0e 1a c6 e7 04 9b 07 6d 95 9b 66 9a 24 0d 5b 67 f3 98 8f 7e f3 19 52 01 00 ff e8 d1 78 70 8c 52 3c 92 1b 1b 5b 31 30 0d 07 6d 09 36 cd 3b 78 13 0d aa 61 d8 e8 09 ea 88 9b 58 02 b7 7f 07 22 72 27 b7 ba 67 e0 e7 86 69 a6 f5 c2 a8 74 e6 2a 9c cd c0 d3 1a 0c 9f 31 8c 0d a1 99 3b d1 60 e2 33 df 4a 62 17 9c 6f 30 e0 65 cd 5b 91 cd 0a e1 93 97 d6 96 d0 d7 58 f2 dc 7d 1c 00 30 5d 3f 46 63 5e b0 16 d5 b1 dd a9 8e 2d 74 9b e7 bd 1d f1 fb 3b 23 1f dc db 50 75 a9 aa a1 b4 69 c3 09 00 00 00 00 02 33 58 75 27 1b 28 63 29 d1 69 93 42 88 fd 78 9a a3 7d 6e 98 b2 24 fd 44 b6 5b 31 33 4f fc 55 cc 82 cd 3a c3 2e cd b0 8c ed 6f 90 81 b4 dd 0d 8b 38 f3 cd 44 98 be e8 00 49 08 41 bd b1 14 f6 b7 63 83 70 9d 8f 5c 55 43 2a 90 9f da 03 9a ec 54 a1 23 6e 80 f6 a8 ab ad ea 76 62 49 6b dd bb 42 be 6b fb 2f 17 95 9d 1f e9 0a 56 c7 1b 19 31 87 02 62 f5 e8 01 11 92 42 ca 02 6b fc 82 1e 7e 7d af 24 51 13 8e 64 5b b8 0c 61 76 01 00 00 00 be 70 de 98 ec 76 a9 e4 0d ad 47 f3 6f d9 f7 d0 d4 2a 4b 5f 11 85 cc dc f1 6f f4 62 95 d8 a0 fa 17 71 3c 58 02 63 09 33 a9 a3 4a f6 74 f3 f3 9f e2 34 91 23 7c 08 82 2d ec 11 09 11 e8 93 d0 a8 c4 f6 77 74 7a bc 36 09 34 b8 29 10 ff 85 bf d9 95 08 3b ba 29 87 a6 73 99 ea c4 27 d1 45 d5 95 a4 0b 9f 6f f1 4a c4 88 ec 13 0f b3 85 0a 27 af 95 44 ae 15 a7 e4 54 de a0 59 18 b4 12 43 51 3f 00 00 00 00 00 00 00 0a 36 21 c5 6c ea 8d 20 fa 91 1a 0c 41 db 6e be 8c ac 64 f1 76 79 14 1d 54 b3 4b bc 99 80 00 00 00 b3 30 96 03 f1 d4 ab 96 62 03 86 1b 5b 15 a8 41 f2 b5 75 a8 bd 0d 78 24 8e be 4d 9a 80 00 26 95 10 4f 67 4c 24 31 dc a1 41 fa e2 69 ca b7 0e 9a 66 f3 c3 a9 a6 3e 96 39 e1 f5 9c 0e de 26 c6 b5 d7 4b 07 8a 5e 15 c3 16 34 e5 ae 09 8c e9 ee 70 77 1a aa 18 11 9a 86 7e 10 88 33 49 75 e9 f7 34 83 b6 c8 2f a6 78 ca 14 ff d9 f9 db 2a 78 69 d8 58 64 05 65 26 f8 89 af 43 a6 05 60 80 57 22 86 52 24 49 df 46 6c 63 2b 35 70 24 3f 98 9c ce 38 03 f4 65 e4 1e 61 0c 20 21 d6 53 a5 52 00 00 00 82 13 b7 04 a5 00 00 00 00 00 00 00 8e f9 f1 90 ba e9 79 09 50 70 41 d8 60 42 0c 56 64 b2 79 21 b1 4d c1 db 88 92 fd 32 d0 ad 7b c9 46 81 35 9b ad 8d ef f4 b0 5f 60 ce a0 da 77 10 a8 00 00 00 00 00 00 80 00 be a3 7c e0 d0 d4 aa 20 2f 92 8f 28 38 1a ab 14 4a 5d 42 9a 04 a6 a2 b8 3c 70 68 ae 94 9e d0 6e 28 8e 81 0b ac 9c 76 60 00 25 e1 9c 90 7f 8e a2 e2 01 00 00 00 82 71 a1 f5 f8 52 8f 22 7e 79 c1 38 9d bd ff fe 49 2f 21 57 9d 2c 15 b8 c7 0c db 1c 33 2d 86 d8 73 41 43 27 50 86 1e c2 bc 34 51 ed ca 19 4b 22 1c fe c4 60 3d 27 6b ba a1 df a6 d4 e3 8a 48 a7 6e af c9 a9 a0 27 0e 4c 10 d6 4c d5 a6 24 27 26 4f 23 77 fe 76 3c 43 47 08 33 ac 96 c4 5f 35 7c bb ab a8 f1 b1 fd cc 7c bb 61 a7 cd b9 74 4e d7 f9 12 9a ed e2 be 21 cc fd c4 e9 13 4f 86 84 b3 a4 f3 54 da 9a 79 5e 96 33 4e 20 7d ff 70 f1 98 80 37 b2 ed 3a af 57 5c 0b 88 d8 f1 46 68 40 78 41 6d 59 fd ee 53 25 92 89 74 d1 2d ad 99 da c4 4c 3f 00 08 04 70 96 a4 40 02 be bc 24 20 ae d9 2f a9 b6 57 8b 47 79 41 5d 97 b9 a6 d6 d5 49 5c 11 80 45 65 1c f4 1c 2f c4 8b 77 8e fa 5e a5 67 77 47 43 0a f4 16 2b 98 7b 80 c3 e0 01 cd 34 e5 c9 2f 76 cc 4c 24 ee b8 bc 4e 9a c2 be d9 e5 38 03 ed f1 a4 ae 3a 97 37 d2 14 06 00 05 ea 6f 17 83 e2 87 b3 be e9 6e 3a 72 6e af e2 fd fa a7 8d 1f 48 c1 3b 64 df 07 84 77 54 b8 40 0d aa a6 9b f5 c8 f4 ce b3 60 c7 e6 58 82 85 63 e2 d2 5c 4a a3 48 56 1f 92 7e 88 f6 3a a7 0e 73 a5 e6 9b 3d f3 49 59 03 f0 65 72 e1 e0 07 fa 55 a2 99 9f 59 6d 06 73 12 f5 77 9e 8d bf dc f3 42 71 38 f3 d4 44 d2 63 9a 10 47 7f 9b ec 4b 4b bb 6e 3c 04 be 68 98 1f 39 22 03 dd 0e e3 ef 47 8e 16 da cf c5 e3 e0 3c f7 ab 8e 39 02 f1 b0 ff 03 4e 00 00 00 00 ca 50 93 83 81 5b 1b 6f c6 52 2d 4e 4f dc 11 a4 8c f4 2d 48 60 46 75 fd e2 b9 4c f0 05 00 a2 69 08 91 ab f8 ab 9c 01 50 73 01 4d 9e 08 d4 33 8b 87 80 bd ec d4 36 cf 05 41 35 9b af ff a4 52 37 f1 04 b9 62 10 40 3b 2d e9 ef ed 49 6f 42 35 5b c7 87 2c 82 74 67 cf a5 c4 78 b0 95 b6 84 41 a3 4c b5 16 82 a8 ae 4d 24 ad 92 f2 43 94 1e d2 74 54 9b 79 a7 96 2f b3 85 a8 82 e8 02 0f 06 c4 c2 ba 1d d5 ca c7 c1 88 76 da 86 5d 25 87 34 dd 73 58 3d f2 92 89 24 48 03 9e f7 99 cf 06 30 be cd be 6c 45 79 b5 56 1d c8 25 ab 82 98 27 94 5e 02 0c 1f 67 ee 61 5f eb 62 43 37 8e 06 10 06 0f 02 cc a4 e9 1b 2f 00 1e db 3d 78 fb 4b 55 66 8d da 93 ae 62 fc cf cb b2 b7 5a 21 83 c4 6e b6 5c a8 12 4e 1b 4d a7 fb b7 7a b2 fc 04 3a ea d8 7c 32 ab 87 5e e7 c2 e7 b7 01 9c 98 2c d3 b4 3e 4f b1 a5 fb 13 5c 0c 7d ce e8 fe 65 16 a3 28 03 2f 88 c0 42 89 18 24 65 9e 9e 01 fe ff ff ff ff ff ff 83 a2 b2 10 52 01 06 b8 a3 58 b5 0a b7 a1 fa 89 af 9c 25 1f e5 29 4b 3d 18 02 d5 67 6d 95 f1 60 ec 97 b1 ad 94 87 2c b2 04 46 42 c3 7b 4a 6c c6 c0 4e ff c1 67 2d b7 e4 b6 8d 78 7d 9a 7a 50 8a e5 4b 3c d7 36 9d 75 f2 e8 c7 7d 95 a3 d3 61 c0 40 ba bb 17 16 07 ca ac 2a 35 59 ad 4f 75 46 5f 49 c0 d0 ae 37 16 db 6e 00 cb 11 db 4a 5f ad e2 a5 7c 10 23 8e 20 4a 67 73 7c 3b 42 aa 01 b2 0f 76 94 a0 0f 16 e2 d0 17 40 35 a2 c2 26 56 dc 00 88 0a ce bd be 8d db d7 5c 2f 99 8d 8a c2 df ad 2b a3 a5 02 00 00 00 45 a4 59 57 f2 4d 75 8e d0 24 b3 84 9c 11 d4 12 a2 a0 3b 40 47 49 70 22 d9 c3 0e 23 ef 4d f5 c8 96 44 f4 8b b5 36 f7 94 5b 59 d7 bc dd ff 75 44 13 d1 35 27 3e a8 e7 5f 22 f2 16 c6 b9 99 0a e7 18 06 f2 c0 0b 40 25 c4 8b 75 c0 f7 3c db 9a 7b 8f a3 67 b5 00 28 06 7e 7f 16 f4 dd 56 9d 46 2f 4f 19 ea cd b3 ed 70 ee eb b4 48 3f 8f d7 77 d4 43 e8 b4 04 26 db 6f e2 90 7a c0 ca 3d 24 14 44 2e 8f 3a 15 47 04 b0 e5 1b c6 64 a1 37 b2 6b e7 19 f4 f7 c9 a5 67 8a 67 4d fc 95 df 80 b9 ce 37 5d d6 49 c8 c7 04 e5 09 bd 88 c8 e6 3d 8c 7d d6 70 71 11 5c 89 82 ba 46 af 4d 6a dc c9 f6 8a 75 b9 39 7b 03 51 53 fa f4 63 66 1c 95 3f ca d6 f3 75 25 c1 a0 e9 46 10 dd 94 32 3f 6c 15 d0 85 19 71 49 bf d6 65 55 48 cf d9 c5 2c 97 11 93 7f 79 ab b1 a1 24 f1 21 04 65 48 3c d3 b2 d7 83 78 cf b8 5e d8 2e 7d a0 f6 eb 6d 27 9f 2a e4 55 92 5d 0f 6f 1b a5 71 eb a2 81 f2 a6 54 fb 39 dd ff 3b 48 44 39 ff 15 8e 7c d4 19 e0 37 f3 e3 ad 03 8f 22 11 f1 03 31 95 56 3c 7f 93 cd 54 b9 09 4f 22 6e 78 32 71 e1 e5 a2 a2 c1 07 12 ea b6 25 d6 49 31 cd 4f fe 67 38 d9 7b 9b 5e f8 28 ee 9f b0 59 fc 01 af 0e 79 c1 e1 4b 1d 25 98 8c 69 a3 99 56 7c 1d 93 76 8f 79 71 d3 14 88 b8 65 8a 20 87 8b 7c 1d d7 ba 02 fc 42 93 9d de 3d 4a 33 39 a6 5d 50 7d c5 9c 51 09 7b 40 51 77 05 da 56 e9 eb f0 af a5 32 82 bf 86 db b5 8c 54 80 69 ff 6e b9 5a ad e7 cc 66 d7 bb ef 72 47 79 ca 1f 73 1b 33 46 ff 17 70 50 37 3d 79 ff 7b 3e 7f 9b c0 c1 b4 b2 66 a8 87 8b 90 ba aa 03 9d 3e 3b 63 97 9a c3 df 6e 6f 48 59 af d5 02 38 c7 54 7a 39 b6 08 10 93 80 44 ae 18 5d 2b a3 e0 0a 4e 73 67 68 64 ae 09 0d 81 ea ee cf 1d 0a b3 78 dd 4d d8 91 e9 37 c2 ea 54 10 e0 51 30 05 00 00 00 00 00 00 00 39 11 fa b9 64 c2 71 55 00 27 69 7b 52 16 06 87 46 16 02 f8 8d f1 65 d8 84 b3 6e c2 b6 c2 5a 2f 33 c7 15 68 7e 9d 4a fb 96 d6 86 1a ca 47 da 73 d6 f3 dd 01 4e 5c 5a d8 fe 99 57 54 bd 9c f3 2f ce 1e 31 91 9c 4b 20 82 fb 0a 30 b9 de ae 84 be d4 b2 80 45 63 40 73 c9 c5 8c 89 d9 e9 9c 81 76 91 77 c6 ea 94 f8 8a 4f ac fd 4c 73 5a 20 30 7c 73 7a fa e5 13 66 51 b1 b9 bd 52 2d cb 39 94 73 29 6b 83 1d bd 93 3d 93 99 4b a3 06 42 79 b1 0e a0 c5 83 3f 41 f1 57 ea 23 02 99 3d be 43 3b 1a a3 a3 76 84 f4 11 3c 48 85 94 65 c3 b4 15 c3 43 2f 81 db 87 19 53 9d 5b f3 72 aa ae a1 cc 43 a6 c5 cb e5 97 58 bf ee 29 16 58 0d ac 4b 00 8e 59 5f 43 74 91 d8 7a be d0 2c ef cd 9d b5 3d 94 d0 2d ae 17 b1 18 e5 d6 78 74 63 18 3b 4b 87 c1 05 00 00 00 30 2a 80 8d 7f 52 51 44 06 13 d1 7c a5 10 55 f2 f4 16 a4 4f e1 80 d2 d5 0c 31 2c ca 7c b1 4a 20 dc 33 1f 57 a9 81 71 39 a2 06 fc 76 95 72 27 ff ff 2d e2 0a 4b 8e 37 37 fb b4 01 00 00 00 06 37 6f 79 9e ba 36 7e 21 f9 4c a5 98 70 5f 5d cb 76 7d 6f 09 00 d6 b0 f6 09 5e 53 c4 c4 23 4d 0c 1f be 43 4f 6a b8 3c 00 13 ee 93 b8 39 46 ee 77 59 e8 9d 7b dd 1a 32 d7 b3 11 71 1b 75 7f e4 3c 06 d2 1a 35 81 0d 8f e9 8b 27 fa ea 8a a1 2b c8 71 6e ef c5 c9 7c 45 ac 33 ee ec 96 4c 52 14 bc 3a 93 59 bd ea 1c cc ab 94 f1 5e 36 31 9c b3 4e bc ac ed b8 2c 2e d3 de 5a 8a 8f 00 11 e8 f7 4e 82 d7 ce ec 7d c8 08 bf 65 36 39 d7 96 19 39 ad fd ee ea ff 19 d1 1e fc af b6 d5 46 fe f2 71 e8 9d 6c c2 38 9e 81 ff 58 ce fc ce 3f bf 46 25 a7 e7 de 40 e4 2e 07 b3 44 49 e1 5e 06 5c c7 34 86 63 a5 21 90 20 2c 7a f2 88 a4 51 0d e0 3d ab 19 d2 62 85 ed a8 91 56 d5 0d d3 85 a6 02 00 00 00 00 00 00 00 70 07 ad 15 19 ad 54 70 de 3d d6 d6 08 0c af cc f8 a9 74 06 bb 6b 68 a1 f0 c4 54 98 20 a7 3c 88 0f 47 5f 73 2a e0 03 03 00 00 00 00 00 00 00 7f b3 3b 72 68 5e c3 7a 2d 3f 76 64 13 a6 04 59 51 62 46 e5 a1 d9 98 a2 01 7a ef 09 48 a6 8c f2 55 31 5a b8 0d d3 49 e8 91 ae f5 95 dc 4d 47 0e 8a c3 2a 30 8e 15 fc 37 d0 6a ea c2 89 c0 52 3f 48 3e 1f f7 40 8c 60 87 f1 ab 65 2f 2e f9 1d 4f 2b 01 98 7b 0f 46 da 03 4e 5c 3f 74 5a 7e e8 10 1a 39 34 c5 4e 24 b4 8e c0 27 5e 2d 06 87 dc 74 6b 08 27 cb f6 52 90 06 c6 b9 5f 27 22 e5 8c 05 f7 52 ce 21 26 59 6e 1c d7 65 5b 90 48 01 78 4c 41 6b 22 f7 3d 32 46 78 e2 72 4f 43 f1 fe 68 7c 7e 8a 60 c2 8b 82 b6 52 2f b5 f6 ff cd d5 6f ed 88 93 5f cb 75 91 2d 5e cd 36 de a3 bc a0 b7 42 7d 83 92 c6 28 94 55 e8 f8 d2 ab 22 42 72 92 51 ae 23 3a 9e 02 21 0e 62 df 05 46 a7 4b 33 3a 1c 48 f9 5f d5 4a cb 57 41 25 9e 8c 54 88 ef ee e3 27 41 5c c1 94 51 43 2c 6f 14 c2 76 93 10 2a 5b d8 48 57 cd 65 86 fc 5c a9 a9 3e b0 14 5f ac 06 62 ff 86 10 7f 99 8a 8e f7 df 8a a1 40 46 c5 5b 03 d3 d4 7f 88 a8 d6 0f 77 74 a2 ee 08 00 88 97 fb 41 1a 94 b3 c2 fc 5d 5f 0d b4 2c 04 56 ec 01 5f 08 e5 24 7d 33 ae 2d 35 60 3f f8 45 4c 16 f8 34 28 56 93 51 25 10 2b b6 ce 43 1b 63 ee 35 6b 0c 78 5f 2f 47 b9 0e 29 38 9f 22 fc 5b 59 a7 0e fa ea 2b d4 01 95 af 44 86 22 0d 70 2e 30 bf c4 3c 10 ec 23 ea 62 83 99 4a 7d de 4d cb 61 fe a6 b6 51 fb 1d 62 45 8d 07 41 a1 28 30 05 2f cc 46 0d b0 43 af e5 25 62 9b 40 d7 ce e4 58 e4 cb 5e 93 0e d6 24 80 6c 43 a0 06 e3 93 36 d0 7c 2b 80 c1 c1 28 ad 27 06 f4 82 61 f7 89 74 84 c2 97 a1 a6 61 3b c1 8f 5a 38 d4 42 76 8a f3 80 41 ef e0 3d 15 2e f9 5f f5 69 e7 6d b2 39 1f 45 09 d7 f3 39 d9 2f db 4a 89 36 49 49 da 39 80 00 00 00 00 00 00 00 d8 0a 4f e6 54 57 83 76 e5 99 af f3 56 5b 1d 53 1f 30 91 2b 99 45 03 0b 81 ea 99 35 fd 46 ed b4 4a 78 f6 15 25 54 90 a4 b6 21 50 1f 2a 9e 4d 24 62 4c 4d ac 92 74 11 8c 67 58 4f 5d 37 47 55 53 4d 7f 68 f6 79 c4 ff 51 6a 9c 86 1a 0e 7e 65 86 8f cb 2b f1 cb 9a ea 4e 05 df 72 27 9f db 0d 2b 9e 93 5c 5a f3 cf 47 4b ed 79 df c2 48 c1 f5 ae a4 b8 b3 2c 5d 29 5e 57 fa 9c 0f e6 62 a4 6b 7f 71 cd 47 74 4d b8 6c 50 b7 04 c9 8a d9 02 95 c7 b2 c7 43 9a 2d 78 cc fa 79 b5 fc 2b ff 6b bf 84 02 62 bf 89 39 4b 3e 06 91 95 32 64 d2 70 0c 83 8f a2 c7 b3 42 52 60 f5 95 54 e5 02 dc ea 39 cb 31 3b 00 00 00 00 00 00 4c a7 c1 2f 45 85 8d 62 84 ca 62 70 d6 b2 f0 e5 8f de d8 a7 b4 a3 02 a9 7b c6 41 df 07 72 0b a2 b2 6b bf cc 80 7c a0 ab b1 b4 43 22 26 9c 21 c5 ec 68 cb 06 8e a8 80 67 d9 05 ea 91 7b b0 3e ef da eb de ab f2 d0 dc e8 09 97 c9 15 c8 94 9d e9 92 58 7c 2c b5 fe 36 05 00 00 00 00 00 00 00 b7 79 40 b5 f0 77 22 e4 7a 08 d3 67 95 07 00 00 00 00 00 00 93 4b 99 b3 10 9a f6 5d 77 e8 6a bd 68 59 cd df 4b ba e1 f0 93 04 62 df 15 fd db c4 85 62 ea 35 11 a8 06 5e f0 28 cf 12 f1 4d cf 6e be cd 8d 88 48 36 17 4f af 1a a6 09 e5 f1 ee 10 62 df a1 3b dc 1f a7 cf aa db a8 5c 72 e9 75 8f 03 a7 55 d0 be 53 f8 d2 a1 df 0d 07 b3 d5 bd 3b 01 fa ff d0 ad db ed 28 81 a9 70 0a f5 61 ac 8c 7e 36 bb 2f c4 c4 0e 9c 76 6c 06 81 7b b9 03 72 9a 7d b6 ff 95 76 97 c9 ed e7 88 5d 94 ff b0 75 9b e0 da f6 0a f9 31 09 eb 1d ee 72 e4 36 3f 51 af 62 af 6f b2 a6 df 3b ec 89 82 2a 7a 0b 67 80 58 fa 3f ef 86 fa ec 21 6e b6 99 21 62 f8 dc bf 71 9c 14 84 d2 f9 c5 5f 49 01 20 3a 9a 8a 2c 3e 90 f3 9c 3d bc 10 36 0a 1a 49 70 0d 1d fb f6 6d 69 f6 fb af 50 6c 8b cc e8 bb 0d 87 2a 02 23 89 26 40 7a 4e dd d5 d0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00} (length 0x1000)
// size: len = 0x1000 (2 bytes)
// }
// }
// }
// len: len = 0x1006 (8 bytes)
// ]
*(uint32_t*)0x200000001980 = 9;
memcpy((void*)0x200000001984, "... [truncated large byte array] ...", 4096);
*(uint16_t*)0x200000002984 = 0x1000;
syscall(__NR_write, /*fd=*/r[1], /*data=*/0x200000001980ul, /*len=*/0x1006ul);
return 0;
}
]
|
| 2/1 |
2026/05/21 09:23 |
action |
kernel-checkouter |
1m
Results: map[KernelSrc:/app/workdir/cache/src/ba6c573c9a6402afc2203db2262fbb67bcd5c7ff]
|
| 3/1 |
2026/05/21 09:25 |
action |
kernel-builder |
31m
Results: map[KernelObj:/app/workdir/cache/build/0ef15d275bfb6d25a395b3edf0279c6b9ee108fb]
|
| 4/1 |
2026/05/21 09:56 |
action |
codesearch-prepare |
14m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/05/21 10:11 |
agent |
expert |
7m
Model:
Results: map[DenialOfService:true Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:true]
Instruction:
You are an experienced Linux kernel security engineer. Your task is to analyze given kernel bug report
and determine its security impact based on the following dimensions.
Use the provided tools to examine the source code, check for capability checks (e.g., capable(), ns_capable()),
and understand the nature of the bug. Analyze the given kernel build and configuration.
You can check the kernel config by grepping ".config" file; you can check kernel cmdline by greeping
".config" file for "CONFIG_CMDLINE=". Assume sysctl parameters have default values.
But analyze for the corresponding production build w/o debugging tools enabled (like KASAN, KMSAN, UBSAN).
Don't make assumptions; verify them with source code access. Try different strategies when analyzing the bug:
- think of ways in which the vulnerable code is unreachable
- or the other way around: try to come up with different ideas of how an unprivileged user can reach the bug
If still unsure err on the side of the bug being non-exploitable/not-accessible.
In the final reply, provide a reasoning for your assessment.
Analysis dimensions:
* Exploitable:
Determine if the bug can result in memory corruption or elevated privileges.
Memory safety issues are almost always exploitable (KASAN or UBSAN reports for use-after-free, out-of-bounds;
refcounting issues, corrupted lists, etc). When kernel is crashing on a completly wild pointer access
(e.g. user-space address, or non-canonical address, but not on NULL or address corresponding to KASAN shadow
for NULL address), including both data accesses and control tranfers, that's also usually implies possibility
of exploitation. Such reports usually say "unable to handle kernel paging request".
Uses of uninitialized values detected by KMSAN may be exploitable b/c attacker frequently can affect uninit
values with spraying techniques. However, for these exploitabability depends on how exactly the uninit value
is used in the code, and what it affects.
Think of what happens after the bug is triggered. Some bugs cause kernel panic and halt execution,
they are harder to exploit. For example, BUG reports halts the kernel. However, WARNING reports don't halt
execution in production builds. Debug bug detection tools (like KASAN, KMSAN, KCSAN, UBSAN) are also not enabled
in production builds, so attacker can freely exploit these bugs w/o being detected by these tools.
If you see an integer overflow, think how the overflowed value used later (if it's used as allocation size,
or an array index). If you see an out-of-bounds read, think if it's followed by an out-of-bounds write as well.
Some KCSAN data-races may be exploitable by skilled attackers as well. Think what data structures got corrupted
as the result of data races and how. However, note that kernel has lots of "benign" data races that don't lead
to any runtime misbehavior at all.
* Denial Of Service:
Determine if the bug can result in denial-of-service. Most bugs can, since they cause system crash,
hangs, deadlocks, or resource leaks. This is mostly applicable to WARNING bugs that won't cause system crash
in production. For these think what will be consequences of the violation of the kernel assumptions flagged
by the WARNING. In some cases the unexpected condition is also properly handled by the normal control flow
(e.g. with "if (WARN_ON(...))"), these won't cause denial-of-service. If the condition is not handled,
then it may or may not cause denial-of-service.
* Accessible From Unprivileged Processes:
Determine if the bug can be reached from a typical (non-root) user process that does NOT have any special capabilities
(like CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON) or access to device nodes restricted to root.
Assume that unprivileged_bpf_disabled=1, that is eBPF loading is not accessible. However, cBPF (classical BPF)
is still accessible to non-root processes.
Assume that user namespaces are not accessible, that is, the process cannot get the mentioned capabilities even
within a new user namespace (checked by ns_capable() function in the kernel sources).
* Accessible From User Namespaces:
Determine if the bug can be reached within a user-namespace where the process has all capabilities
(including CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON). Such capabilities are checked with ns_capable()
function in the kernel sources.
* VM Guest Trigger:
Determine if the bug can be triggered from the context of a typical KVM guest (e.g., set up by a QEMU VMM).
Consider accesses to standard Linux host paravirtualized features (virtio-blk, virtio-net, etc.),
and handling of VM exits in the KVM code.
* VM Host Trigger in The Confidetial Computing Context:
Determine if the bug can be triggered in a confidential computing guest kernel from the context of a KVM host.
Consider access to standard Linux guest paravirtualized features (virtio-blk, virtio-net, etc.).
* Ethernet Network Trigger:
Determine if the bug can be triggered by processing ingress network Ethernet traffic, either directly (network stack)
or via drivers exposed to network data.
* Other Remote Trigger:
Determine if the bug can be triggered by processing remote traffic other than Ethernet (Wifi, Bluetooth, NFC, etc).
* Peripheral Trigger:
Determine if the bug can be triggered via an untrusted peripheral device that can be physically plugged
into a system, such as a USB device or a niche hardware driver handling external hardware inputs.
This is particularly important for mobile and desktop environments where users can plug in unknown devices.
* Malicious Filesystem Trigger:
Determine if the bug can be triggered by the kernel mounting and parsing a malicious filesystem image.
This is highly critical for Desktop and Mobile environments where external media or downloaded images
might be auto-mounted.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
The kernel bug report is:
list_add double add: new=ffff888028dc3118, prev=ffff888028dc3118, next=ffff8880761de078.
------------[ cut here ]------------
kernel BUG at lib/list_debug.c:35!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
CPU: 0 UID: 0 PID: 7322 Comm: syz.2.605 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025
RIP: 0010:__list_add_valid_or_report+0x143/0x190 lib/list_debug.c:35
Code: 89 f1 48 c7 c7 c0 b6 f2 8b 48 89 ee e8 d6 9a e7 fc 90 0f 0b 48 89 f2 48 89 e9 4c 89 e6 48 c7 c7 40 b7 f2 8b e8 be 9a e7 fc 90 <0f> 0b 48 89 f7 48 89 34 24 e8 cf db 73 fd 48 8b 34 24 e9 07 ff ff
RSP: 0018:ffffc90004ca7580 EFLAGS: 00010086
RAX: 0000000000000058 RBX: ffff888028dc3100 RCX: ffffffff819c8fa5
RDX: 0000000000000000 RSI: ffffffff819d0b89 RDI: 0000000000000005
RBP: ffff8880761de078 R08: 0000000000000005 R09: 0000000000000000
R10: 0000000080000004 R11: 0000000000000001 R12: ffff888028dc3118
R13: ffff8880761de080 R14: 0000000000000000 R15: ffff888028dc3118
FS: 00007fa72ab066c0(0000) GS:ffff8881248f5000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000200000002000 CR3: 000000007860f000 CR4: 00000000003526f0
Call Trace:
<TASK>
__list_add_valid include/linux/list.h:96 [inline]
__list_add include/linux/list.h:158 [inline]
list_add_tail include/linux/list.h:191 [inline]
usb_hcd_link_urb_to_ep+0x220/0x3a0 drivers/usb/core/hcd.c:1158
dummy_urb_enqueue+0x2a7/0x920 drivers/usb/gadget/udc/dummy_hcd.c:1288
usb_hcd_submit_urb+0x25b/0x1cf0 drivers/usb/core/hcd.c:1546
usb_submit_urb+0x899/0x1970 drivers/usb/core/urb.c:587
cm109_submit_buzz_toggle+0xd9/0x180 drivers/input/misc/cm109.c:351
cm109_toggle_buzzer_async drivers/input/misc/cm109.c:484 [inline]
cm109_input_ev+0x23d/0x280 drivers/input/misc/cm109.c:615
input_event_dispose drivers/input/input.c:322 [inline]
input_handle_event+0x151/0x14d0 drivers/input/input.c:370
input_inject_event+0x1e8/0x3b0 drivers/input/input.c:424
kd_sound_helper+0x17a/0x280 drivers/tty/vt/keyboard.c:256
input_handler_for_each_handle+0xd7/0x250 drivers/input/input.c:2520
kd_mksound+0x88/0x130 drivers/tty/vt/keyboard.c:280
handle_ascii drivers/tty/vt/vt.c:2327 [inline]
do_con_trol drivers/tty/vt/vt.c:2644 [inline]
do_con_write+0x3246/0x8280 drivers/tty/vt/vt.c:3228
con_write+0x23/0xb0 drivers/tty/vt/vt.c:3565
process_output_block drivers/tty/n_tty.c:557 [inline]
n_tty_write+0x434/0x1280 drivers/tty/n_tty.c:2366
iterate_tty_write drivers/tty/tty_io.c:1006 [inline]
file_tty_write.constprop.0+0x503/0x9b0 drivers/tty/tty_io.c:1081
new_sync_write fs/read_write.c:593 [inline]
vfs_write+0x7d3/0x11d0 fs/read_write.c:686
ksys_write+0x12a/0x250 fs/read_write.c:738
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fa729b8f749
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fa72ab06038 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00007fa729de5fa0 RCX: 00007fa729b8f749
RDX: 0000000000001006 RSI: 0000200000001980 RDI: 0000000000000005
RBP: 00007fa729c13f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fa729de6038 R14: 00007fa729de5fa0 R15: 00007ffdb843d7a8
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:__list_add_valid_or_report+0x143/0x190 lib/list_debug.c:35
Code: 89 f1 48 c7 c7 c0 b6 f2 8b 48 89 ee e8 d6 9a e7 fc 90 0f 0b 48 89 f2 48 89 e9 4c 89 e6 48 c7 c7 40 b7 f2 8b e8 be 9a e7 fc 90 <0f> 0b 48 89 f7 48 89 34 24 e8 cf db 73 fd 48 8b 34 24 e9 07 ff ff
RSP: 0018:ffffc90004ca7580 EFLAGS: 00010086
RAX: 0000000000000058 RBX: ffff888028dc3100 RCX: ffffffff819c8fa5
RDX: 0000000000000000 RSI: ffffffff819d0b89 RDI: 0000000000000005
RBP: ffff8880761de078 R08: 0000000000000005 R09: 0000000000000000
R10: 0000000080000004 R11: 0000000000000001 R12: ffff888028dc3118
R13: ffff8880761de080 R14: 0000000000000000 R15: ffff888028dc3118
FS: 00007fa72ab066c0(0000) GS:ffff8881248f5000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000200000002000 CR3: 000000007860f000 CR4: 00000000003526f0
It is reproducible with the followint program.
Keep in mind that it may lack the precise threading, sandboxing, and some arguments of a working reproducer.
But it should give an idea of the involved syscalls.
// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/usb/ch9.h>
static unsigned long long procid;
static void sleep_ms(uint64_t ms)
{
usleep(ms * 1000);
}
#define MAX_FDS 30
#define USB_MAX_IFACE_NUM 4
#define USB_MAX_EP_NUM 32
#define USB_MAX_FDS 6
struct usb_endpoint_index {
struct usb_endpoint_descriptor desc;
int handle;
};
struct usb_iface_index {
struct usb_interface_descriptor* iface;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bInterfaceClass;
struct usb_endpoint_index eps[USB_MAX_EP_NUM];
int eps_num;
};
struct usb_device_index {
struct usb_device_descriptor* dev;
struct usb_config_descriptor* config;
uint8_t bDeviceClass;
uint8_t bMaxPower;
int config_length;
struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
int ifaces_num;
int iface_cur;
};
struct usb_info {
int fd;
struct usb_device_index index;
};
static struct usb_info usb_devices[USB_MAX_FDS];
static struct usb_device_index* lookup_usb_index(int fd)
{
for (int i = 0; i < USB_MAX_FDS; i++) {
if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd)
return &usb_devices[i].index;
}
return NULL;
}
static int usb_devices_num;
static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index)
{
if (length < sizeof(*index->dev) + sizeof(*index->config))
return false;
memset(index, 0, sizeof(*index));
index->dev = (struct usb_device_descriptor*)buffer;
index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
index->bDeviceClass = index->dev->bDeviceClass;
index->bMaxPower = index->config->bMaxPower;
index->config_length = length - sizeof(*index->dev);
index->iface_cur = -1;
size_t offset = 0;
while (true) {
if (offset + 1 >= length)
break;
uint8_t desc_length = buffer[offset];
uint8_t desc_type = buffer[offset + 1];
if (desc_length <= 2)
break;
if (offset + desc_length > length)
break;
if (desc_type == USB_DT_INTERFACE && index->ifaces_num < USB_MAX_IFACE_NUM) {
struct usb_interface_descriptor* iface = (struct usb_interface_descriptor*)(buffer + offset);
index->ifaces[index->ifaces_num].iface = iface;
index->ifaces[index->ifaces_num].bInterfaceNumber = iface->bInterfaceNumber;
index->ifaces[index->ifaces_num].bAlternateSetting = iface->bAlternateSetting;
index->ifaces[index->ifaces_num].bInterfaceClass = iface->bInterfaceClass;
index->ifaces_num++;
}
if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
if (iface->eps_num < USB_MAX_EP_NUM) {
memcpy(&iface->eps[iface->eps_num].desc, buffer + offset, sizeof(iface->eps[iface->eps_num].desc));
iface->eps_num++;
}
}
offset += desc_length;
}
return true;
}
static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t dev_len)
{
int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED);
if (i >= USB_MAX_FDS)
return NULL;
if (!parse_usb_descriptor(dev, dev_len, &usb_devices[i].index))
return NULL;
__atomic_store_n(&usb_devices[i].fd, fd, __ATOMIC_RELEASE);
return &usb_devices[i].index;
}
struct vusb_connect_string_descriptor {
uint32_t len;
char* str;
} __attribute__((packed));
struct vusb_connect_descriptors {
uint32_t qual_len;
char* qual;
uint32_t bos_len;
char* bos;
uint32_t strs_len;
struct vusb_connect_string_descriptor strs[0];
} __attribute__((packed));
static const char default_string[] = {
8, USB_DT_STRING,
's', 0, 'y', 0, 'z', 0
};
static const char default_lang_id[] = {
4, USB_DT_STRING,
0x09, 0x04
};
static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl,
struct usb_qualifier_descriptor* qual,
char** response_data, uint32_t* response_length)
{
struct usb_device_index* index = lookup_usb_index(fd);
uint8_t str_idx;
if (!index)
return false;
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
switch (ctrl->wValue >> 8) {
case USB_DT_DEVICE:
*response_data = (char*)index->dev;
*response_length = sizeof(*index->dev);
return true;
case USB_DT_CONFIG:
*response_data = (char*)index->config;
*response_length = index->config_length;
return true;
case USB_DT_STRING:
str_idx = (uint8_t)ctrl->wValue;
if (descs && str_idx < descs->strs_len) {
*response_data = descs->strs[str_idx].str;
*response_length = descs->strs[str_idx].len;
return true;
}
if (str_idx == 0) {
*response_data = (char*)&default_lang_id[0];
*response_length = default_lang_id[0];
return true;
}
*response_data = (char*)&default_string[0];
*response_length = default_string[0];
return true;
case USB_DT_BOS:
*response_data = descs->bos;
*response_length = descs->bos_len;
return true;
case USB_DT_DEVICE_QUALIFIER:
if (!descs->qual) {
qual->bLength = sizeof(*qual);
qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
qual->bcdUSB = index->dev->bcdUSB;
qual->bDeviceClass = index->dev->bDeviceClass;
qual->bDeviceSubClass = index->dev->bDeviceSubClass;
qual->bDeviceProtocol = index->dev->bDeviceProtocol;
qual->bMaxPacketSize0 = index->dev->bMaxPacketSize0;
qual->bNumConfigurations = index->dev->bNumConfigurations;
qual->bRESERVED = 0;
*response_data = (char*)qual;
*response_length = sizeof(*qual);
return true;
}
*response_data = descs->qual;
*response_length = descs->qual_len;
return true;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
return false;
}
typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl, bool* done);
static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs,
const struct usb_ctrlrequest* ctrl, bool* done)
{
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
switch (ctrl->bRequest) {
case USB_REQ_SET_CONFIGURATION:
*done = true;
return true;
default:
break;
}
break;
}
return false;
}
#define UDC_NAME_LENGTH_MAX 128
struct usb_raw_init {
__u8 driver_name[UDC_NAME_LENGTH_MAX];
__u8 device_name[UDC_NAME_LENGTH_MAX];
__u8 speed;
};
enum usb_raw_event_type {
USB_RAW_EVENT_INVALID = 0,
USB_RAW_EVENT_CONNECT = 1,
USB_RAW_EVENT_CONTROL = 2,
};
struct usb_raw_event {
__u32 type;
__u32 length;
__u8 data[0];
};
struct usb_raw_ep_io {
__u16 ep;
__u16 flags;
__u32 length;
__u8 data[0];
};
#define USB_RAW_EPS_NUM_MAX 30
#define USB_RAW_EP_NAME_MAX 16
#define USB_RAW_EP_ADDR_ANY 0xff
struct usb_raw_ep_caps {
__u32 type_control : 1;
__u32 type_iso : 1;
__u32 type_bulk : 1;
__u32 type_int : 1;
__u32 dir_in : 1;
__u32 dir_out : 1;
};
struct usb_raw_ep_limits {
__u16 maxpacket_limit;
__u16 max_streams;
__u32 reserved;
};
struct usb_raw_ep_info {
__u8 name[USB_RAW_EP_NAME_MAX];
__u32 addr;
struct usb_raw_ep_caps caps;
struct usb_raw_ep_limits limits;
};
struct usb_raw_eps_info {
struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX];
};
#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init)
#define USB_RAW_IOCTL_RUN _IO('U', 1)
#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event)
#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32)
#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9)
#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32)
#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info)
#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12)
#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32)
#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32)
#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32)
static int usb_raw_open()
{
return open("/dev/raw-gadget", O_RDWR);
}
static int usb_raw_init(int fd, uint32_t speed, const char* driver, const char* device)
{
struct usb_raw_init arg;
strncpy((char*)&arg.driver_name[0], driver, sizeof(arg.driver_name));
strncpy((char*)&arg.device_name[0], device, sizeof(arg.device_name));
arg.speed = speed;
return ioctl(fd, USB_RAW_IOCTL_INIT, &arg);
}
static int usb_raw_run(int fd)
{
return ioctl(fd, USB_RAW_IOCTL_RUN, 0);
}
static int usb_raw_configure(int fd)
{
return ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0);
}
static int usb_raw_vbus_draw(int fd, uint32_t power)
{
return ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power);
}
static int usb_raw_ep0_write(int fd, struct usb_raw_ep_io* io)
{
return ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io);
}
static int usb_raw_ep0_read(int fd, struct usb_raw_ep_io* io)
{
return ioctl(fd, USB_RAW_IOCTL_EP0_READ, io);
}
static int usb_raw_event_fetch(int fd, struct usb_raw_event* event)
{
return ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event);
}
static int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
{
return ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc);
}
static int usb_raw_ep_disable(int fd, int ep)
{
return ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, ep);
}
static int usb_raw_ep0_stall(int fd)
{
return ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0);
}
#define USB_MAX_PACKET_SIZE 4096
struct usb_raw_control_event {
struct usb_raw_event inner;
struct usb_ctrlrequest ctrl;
char data[USB_MAX_PACKET_SIZE];
};
struct usb_raw_ep_io_data {
struct usb_raw_ep_io inner;
char data[USB_MAX_PACKET_SIZE];
};
static void set_interface(int fd, int n)
{
struct usb_device_index* index = lookup_usb_index(fd);
if (!index)
return;
if (index->iface_cur >= 0 && index->iface_cur < index->ifaces_num) {
for (int ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++) {
int rv = usb_raw_ep_disable(fd, index->ifaces[index->iface_cur].eps[ep].handle);
if (rv < 0) {
} else {
}
}
}
if (n >= 0 && n < index->ifaces_num) {
for (int ep = 0; ep < index->ifaces[n].eps_num; ep++) {
int rv = usb_raw_ep_enable(fd, &index->ifaces[n].eps[ep].desc);
if (rv < 0) {
} else {
index->ifaces[n].eps[ep].handle = rv;
}
}
index->iface_cur = n;
}
}
static int configure_device(int fd)
{
struct usb_device_index* index = lookup_usb_index(fd);
if (!index)
return -1;
int rv = usb_raw_vbus_draw(fd, index->bMaxPower);
if (rv < 0) {
return rv;
}
rv = usb_raw_configure(fd);
if (rv < 0) {
return rv;
}
set_interface(fd, 0);
return 0;
}
static volatile long syz_usb_connect_impl(uint64_t speed, uint64_t dev_len, const char* dev,
const struct vusb_connect_descriptors* descs,
lookup_connect_out_response_t lookup_connect_response_out)
{
if (!dev) {
return -1;
}
int fd = usb_raw_open();
if (fd < 0) {
return fd;
}
if (fd >= MAX_FDS) {
close(fd);
return -1;
}
struct usb_device_index* index = add_usb_index(fd, dev, dev_len);
if (!index) {
return -1;
}
char device[32];
sprintf(&device[0], "dummy_udc.%llu", procid);
int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]);
if (rv < 0) {
return rv;
}
rv = usb_raw_run(fd);
if (rv < 0) {
return rv;
}
bool done = false;
while (!done) {
struct usb_raw_control_event event;
event.inner.type = 0;
event.inner.length = sizeof(event.ctrl);
rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
if (rv < 0) {
return rv;
}
if (event.inner.type != USB_RAW_EVENT_CONTROL)
continue;
char* response_data = NULL;
uint32_t response_length = 0;
struct usb_qualifier_descriptor qual;
if (event.ctrl.bRequestType & USB_DIR_IN) {
if (!lookup_connect_response_in(fd, descs, &event.ctrl, &qual, &response_data, &response_length)) {
usb_raw_ep0_stall(fd);
continue;
}
} else {
if (!lookup_connect_response_out(fd, descs, &event.ctrl, &done)) {
usb_raw_ep0_stall(fd);
continue;
}
response_data = NULL;
response_length = event.ctrl.wLength;
}
if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
event.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
rv = configure_device(fd);
if (rv < 0) {
return rv;
}
}
struct usb_raw_ep_io_data response;
response.inner.ep = 0;
response.inner.flags = 0;
if (response_length > sizeof(response.data))
response_length = 0;
if (event.ctrl.wLength < response_length)
response_length = event.ctrl.wLength;
response.inner.length = response_length;
if (response_data)
memcpy(&response.data[0], response_data, response_length);
else
memset(&response.data[0], 0, response_length);
if (event.ctrl.bRequestType & USB_DIR_IN) {
rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
} else {
rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
}
if (rv < 0) {
return rv;
}
}
sleep_ms(200);
return fd;
}
static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
uint64_t speed = a0;
uint64_t dev_len = a1;
const char* dev = (const char*)a2;
const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;
return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_generic);
}
static long syz_open_dev(volatile long a0, volatile long a1, volatile long a2)
{
if (a0 == 0xc || a0 == 0xb) {
char buf[128];
sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1, (uint8_t)a2);
return open(buf, O_RDWR, 0);
} else {
unsigned long nb = a1;
char buf[1024];
char* hash;
strncpy(buf, (char*)a0, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;
while ((hash = strchr(buf, '#'))) {
*hash = '0' + (char)(nb % 10);
nb /= 10;
}
return open(buf, a2 & ~O_CREAT, 0);
}
}
uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
intptr_t res = 0;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
// syz_usb_connect arguments: [
// speed: usb_device_speed = 0x0 (8 bytes)
// dev_len: len = 0x2d (8 bytes)
// dev: ptr[inout, array[ANYUNION]] {
// array[ANYUNION] {
// union ANYUNION {
// ANYBLOB: buffer: {12 01 00 00 75 16 b7 10 8c 0d 0e 00 8f 8e 00 18 03 01 09 02 1b 00 01 00 00 00 00 09 04 08 00 01 03 00 00 00 09 05} (length 0x26)
// }
// union ANYUNION {
// ANYBLOB: buffer: {8f cf} (length 0x2)
// }
// }
// }
// conn_descs: nil
// ]
// returns fd_usb
memcpy((void*)0x200000000000, "... [truncated large byte array] ...", 38);
memcpy((void*)0x200000000026, "\x8f\xcf", 2);
syz_usb_connect(/*speed=*/0, /*dev_len=*/0x2d, /*dev=*/0x200000000000, /*conn_descs=*/0);
// syz_open_dev$tty1 arguments: [
// dev: const = 0xc (8 bytes)
// major: const = 0x4 (8 bytes)
// minor: intptr = 0x1 (8 bytes)
// ]
// returns fd_tty
res = -1;
res = syz_open_dev(/*dev=*/0xc, /*major=*/4, /*minor=*/1);
if (res != -1)
r[0] = res;
// dup arguments: [
// oldfd: fd (resource)
// ]
// returns fd
res = syscall(__NR_dup, /*oldfd=*/r[0]);
if (res != -1)
r[1] = res;
// write$UHID_INPUT arguments: [
// fd: fd_uhid (resource)
// data: ptr[in, uhid_req[UHID_INPUT, uhid_input_req]] {
// uhid_req[UHID_INPUT, uhid_input_req] {
// type: const = 0x9 (4 bytes)
// data: uhid_input_req {
// data: buffer: {a2 e3 ad 21 4f c7 52 f9 1b 29 09 09 4b f7 0e 0d d0 38 e7 ff 7f c6 e5 53 9b 32 4c 07 8b 08 9b 07 33 3b 6c 1a 08 90 e0 87 8f 0e 1a c6 e7 04 9b 07 6d 95 9b 66 9a 24 0d 5b 67 f3 98 8f 7e f3 19 52 01 00 ff e8 d1 78 70 8c 52 3c 92 1b 1b 5b 31 30 0d 07 6d 09 36 cd 3b 78 13 0d aa 61 d8 e8 09 ea 88 9b 58 02 b7 7f 07 22 72 27 b7 ba 67 e0 e7 86 69 a6 f5 c2 a8 74 e6 2a 9c cd c0 d3 1a 0c 9f 31 8c 0d a1 99 3b d1 60 e2 33 df 4a 62 17 9c 6f 30 e0 65 cd 5b 91 cd 0a e1 93 97 d6 96 d0 d7 58 f2 dc 7d 1c 00 30 5d 3f 46 63 5e b0 16 d5 b1 dd a9 8e 2d 74 9b e7 bd 1d f1 fb 3b 23 1f dc db 50 75 a9 aa a1 b4 69 c3 09 00 00 00 00 02 33 58 75 27 1b 28 63 29 d1 69 93 42 88 fd 78 9a a3 7d 6e 98 b2 24 fd 44 b6 5b 31 33 4f fc 55 cc 82 cd 3a c3 2e cd b0 8c ed 6f 90 81 b4 dd 0d 8b 38 f3 cd 44 98 be e8 00 49 08 41 bd b1 14 f6 b7 63 83 70 9d 8f 5c 55 43 2a 90 9f da 03 9a ec 54 a1 23 6e 80 f6 a8 ab ad ea 76 62 49 6b dd bb 42 be 6b fb 2f 17 95 9d 1f e9 0a 56 c7 1b 19 31 87 02 62 f5 e8 01 11 92 42 ca 02 6b fc 82 1e 7e 7d af 24 51 13 8e 64 5b b8 0c 61 76 01 00 00 00 be 70 de 98 ec 76 a9 e4 0d ad 47 f3 6f d9 f7 d0 d4 2a 4b 5f 11 85 cc dc f1 6f f4 62 95 d8 a0 fa 17 71 3c 58 02 63 09 33 a9 a3 4a f6 74 f3 f3 9f e2 34 91 23 7c 08 82 2d ec 11 09 11 e8 93 d0 a8 c4 f6 77 74 7a bc 36 09 34 b8 29 10 ff 85 bf d9 95 08 3b ba 29 87 a6 73 99 ea c4 27 d1 45 d5 95 a4 0b 9f 6f f1 4a c4 88 ec 13 0f b3 85 0a 27 af 95 44 ae 15 a7 e4 54 de a0 59 18 b4 12 43 51 3f 00 00 00 00 00 00 00 0a 36 21 c5 6c ea 8d 20 fa 91 1a 0c 41 db 6e be 8c ac 64 f1 76 79 14 1d 54 b3 4b bc 99 80 00 00 00 b3 30 96 03 f1 d4 ab 96 62 03 86 1b 5b 15 a8 41 f2 b5 75 a8 bd 0d 78 24 8e be 4d 9a 80 00 26 95 10 4f 67 4c 24 31 dc a1 41 fa e2 69 ca b7 0e 9a 66 f3 c3 a9 a6 3e 96 39 e1 f5 9c 0e de 26 c6 b5 d7 4b 07 8a 5e 15 c3 16 34 e5 ae 09 8c e9 ee 70 77 1a aa 18 11 9a 86 7e 10 88 33 49 75 e9 f7 34 83 b6 c8 2f a6 78 ca 14 ff d9 f9 db 2a 78 69 d8 58 64 05 65 26 f8 89 af 43 a6 05 60 80 57 22 86 52 24 49 df 46 6c 63 2b 35 70 24 3f 98 9c ce 38 03 f4 65 e4 1e 61 0c 20 21 d6 53 a5 52 00 00 00 82 13 b7 04 a5 00 00 00 00 00 00 00 8e f9 f1 90 ba e9 79 09 50 70 41 d8 60 42 0c 56 64 b2 79 21 b1 4d c1 db 88 92 fd 32 d0 ad 7b c9 46 81 35 9b ad 8d ef f4 b0 5f 60 ce a0 da 77 10 a8 00 00 00 00 00 00 80 00 be a3 7c e0 d0 d4 aa 20 2f 92 8f 28 38 1a ab 14 4a 5d 42 9a 04 a6 a2 b8 3c 70 68 ae 94 9e d0 6e 28 8e 81 0b ac 9c 76 60 00 25 e1 9c 90 7f 8e a2 e2 01 00 00 00 82 71 a1 f5 f8 52 8f 22 7e 79 c1 38 9d bd ff fe 49 2f 21 57 9d 2c 15 b8 c7 0c db 1c 33 2d 86 d8 73 41 43 27 50 86 1e c2 bc 34 51 ed ca 19 4b 22 1c fe c4 60 3d 27 6b ba a1 df a6 d4 e3 8a 48 a7 6e af c9 a9 a0 27 0e 4c 10 d6 4c d5 a6 24 27 26 4f 23 77 fe 76 3c 43 47 08 33 ac 96 c4 5f 35 7c bb ab a8 f1 b1 fd cc 7c bb 61 a7 cd b9 74 4e d7 f9 12 9a ed e2 be 21 cc fd c4 e9 13 4f 86 84 b3 a4 f3 54 da 9a 79 5e 96 33 4e 20 7d ff 70 f1 98 80 37 b2 ed 3a af 57 5c 0b 88 d8 f1 46 68 40 78 41 6d 59 fd ee 53 25 92 89 74 d1 2d ad 99 da c4 4c 3f 00 08 04 70 96 a4 40 02 be bc 24 20 ae d9 2f a9 b6 57 8b 47 79 41 5d 97 b9 a6 d6 d5 49 5c 11 80 45 65 1c f4 1c 2f c4 8b 77 8e fa 5e a5 67 77 47 43 0a f4 16 2b 98 7b 80 c3 e0 01 cd 34 e5 c9 2f 76 cc 4c 24 ee b8 bc 4e 9a c2 be d9 e5 38 03 ed f1 a4 ae 3a 97 37 d2 14 06 00 05 ea 6f 17 83 e2 87 b3 be e9 6e 3a 72 6e af e2 fd fa a7 8d 1f 48 c1 3b 64 df 07 84 77 54 b8 40 0d aa a6 9b f5 c8 f4 ce b3 60 c7 e6 58 82 85 63 e2 d2 5c 4a a3 48 56 1f 92 7e 88 f6 3a a7 0e 73 a5 e6 9b 3d f3 49 59 03 f0 65 72 e1 e0 07 fa 55 a2 99 9f 59 6d 06 73 12 f5 77 9e 8d bf dc f3 42 71 38 f3 d4 44 d2 63 9a 10 47 7f 9b ec 4b 4b bb 6e 3c 04 be 68 98 1f 39 22 03 dd 0e e3 ef 47 8e 16 da cf c5 e3 e0 3c f7 ab 8e 39 02 f1 b0 ff 03 4e 00 00 00 00 ca 50 93 83 81 5b 1b 6f c6 52 2d 4e 4f dc 11 a4 8c f4 2d 48 60 46 75 fd e2 b9 4c f0 05 00 a2 69 08 91 ab f8 ab 9c 01 50 73 01 4d 9e 08 d4 33 8b 87 80 bd ec d4 36 cf 05 41 35 9b af ff a4 52 37 f1 04 b9 62 10 40 3b 2d e9 ef ed 49 6f 42 35 5b c7 87 2c 82 74 67 cf a5 c4 78 b0 95 b6 84 41 a3 4c b5 16 82 a8 ae 4d 24 ad 92 f2 43 94 1e d2 74 54 9b 79 a7 96 2f b3 85 a8 82 e8 02 0f 06 c4 c2 ba 1d d5 ca c7 c1 88 76 da 86 5d 25 87 34 dd 73 58 3d f2 92 89 24 48 03 9e f7 99 cf 06 30 be cd be 6c 45 79 b5 56 1d c8 25 ab 82 98 27 94 5e 02 0c 1f 67 ee 61 5f eb 62 43 37 8e 06 10 06 0f 02 cc a4 e9 1b 2f 00 1e db 3d 78 fb 4b 55 66 8d da 93 ae 62 fc cf cb b2 b7 5a 21 83 c4 6e b6 5c a8 12 4e 1b 4d a7 fb b7 7a b2 fc 04 3a ea d8 7c 32 ab 87 5e e7 c2 e7 b7 01 9c 98 2c d3 b4 3e 4f b1 a5 fb 13 5c 0c 7d ce e8 fe 65 16 a3 28 03 2f 88 c0 42 89 18 24 65 9e 9e 01 fe ff ff ff ff ff ff 83 a2 b2 10 52 01 06 b8 a3 58 b5 0a b7 a1 fa 89 af 9c 25 1f e5 29 4b 3d 18 02 d5 67 6d 95 f1 60 ec 97 b1 ad 94 87 2c b2 04 46 42 c3 7b 4a 6c c6 c0 4e ff c1 67 2d b7 e4 b6 8d 78 7d 9a 7a 50 8a e5 4b 3c d7 36 9d 75 f2 e8 c7 7d 95 a3 d3 61 c0 40 ba bb 17 16 07 ca ac 2a 35 59 ad 4f 75 46 5f 49 c0 d0 ae 37 16 db 6e 00 cb 11 db 4a 5f ad e2 a5 7c 10 23 8e 20 4a 67 73 7c 3b 42 aa 01 b2 0f 76 94 a0 0f 16 e2 d0 17 40 35 a2 c2 26 56 dc 00 88 0a ce bd be 8d db d7 5c 2f 99 8d 8a c2 df ad 2b a3 a5 02 00 00 00 45 a4 59 57 f2 4d 75 8e d0 24 b3 84 9c 11 d4 12 a2 a0 3b 40 47 49 70 22 d9 c3 0e 23 ef 4d f5 c8 96 44 f4 8b b5 36 f7 94 5b 59 d7 bc dd ff 75 44 13 d1 35 27 3e a8 e7 5f 22 f2 16 c6 b9 99 0a e7 18 06 f2 c0 0b 40 25 c4 8b 75 c0 f7 3c db 9a 7b 8f a3 67 b5 00 28 06 7e 7f 16 f4 dd 56 9d 46 2f 4f 19 ea cd b3 ed 70 ee eb b4 48 3f 8f d7 77 d4 43 e8 b4 04 26 db 6f e2 90 7a c0 ca 3d 24 14 44 2e 8f 3a 15 47 04 b0 e5 1b c6 64 a1 37 b2 6b e7 19 f4 f7 c9 a5 67 8a 67 4d fc 95 df 80 b9 ce 37 5d d6 49 c8 c7 04 e5 09 bd 88 c8 e6 3d 8c 7d d6 70 71 11 5c 89 82 ba 46 af 4d 6a dc c9 f6 8a 75 b9 39 7b 03 51 53 fa f4 63 66 1c 95 3f ca d6 f3 75 25 c1 a0 e9 46 10 dd 94 32 3f 6c 15 d0 85 19 71 49 bf d6 65 55 48 cf d9 c5 2c 97 11 93 7f 79 ab b1 a1 24 f1 21 04 65 48 3c d3 b2 d7 83 78 cf b8 5e d8 2e 7d a0 f6 eb 6d 27 9f 2a e4 55 92 5d 0f 6f 1b a5 71 eb a2 81 f2 a6 54 fb 39 dd ff 3b 48 44 39 ff 15 8e 7c d4 19 e0 37 f3 e3 ad 03 8f 22 11 f1 03 31 95 56 3c 7f 93 cd 54 b9 09 4f 22 6e 78 32 71 e1 e5 a2 a2 c1 07 12 ea b6 25 d6 49 31 cd 4f fe 67 38 d9 7b 9b 5e f8 28 ee 9f b0 59 fc 01 af 0e 79 c1 e1 4b 1d 25 98 8c 69 a3 99 56 7c 1d 93 76 8f 79 71 d3 14 88 b8 65 8a 20 87 8b 7c 1d d7 ba 02 fc 42 93 9d de 3d 4a 33 39 a6 5d 50 7d c5 9c 51 09 7b 40 51 77 05 da 56 e9 eb f0 af a5 32 82 bf 86 db b5 8c 54 80 69 ff 6e b9 5a ad e7 cc 66 d7 bb ef 72 47 79 ca 1f 73 1b 33 46 ff 17 70 50 37 3d 79 ff 7b 3e 7f 9b c0 c1 b4 b2 66 a8 87 8b 90 ba aa 03 9d 3e 3b 63 97 9a c3 df 6e 6f 48 59 af d5 02 38 c7 54 7a 39 b6 08 10 93 80 44 ae 18 5d 2b a3 e0 0a 4e 73 67 68 64 ae 09 0d 81 ea ee cf 1d 0a b3 78 dd 4d d8 91 e9 37 c2 ea 54 10 e0 51 30 05 00 00 00 00 00 00 00 39 11 fa b9 64 c2 71 55 00 27 69 7b 52 16 06 87 46 16 02 f8 8d f1 65 d8 84 b3 6e c2 b6 c2 5a 2f 33 c7 15 68 7e 9d 4a fb 96 d6 86 1a ca 47 da 73 d6 f3 dd 01 4e 5c 5a d8 fe 99 57 54 bd 9c f3 2f ce 1e 31 91 9c 4b 20 82 fb 0a 30 b9 de ae 84 be d4 b2 80 45 63 40 73 c9 c5 8c 89 d9 e9 9c 81 76 91 77 c6 ea 94 f8 8a 4f ac fd 4c 73 5a 20 30 7c 73 7a fa e5 13 66 51 b1 b9 bd 52 2d cb 39 94 73 29 6b 83 1d bd 93 3d 93 99 4b a3 06 42 79 b1 0e a0 c5 83 3f 41 f1 57 ea 23 02 99 3d be 43 3b 1a a3 a3 76 84 f4 11 3c 48 85 94 65 c3 b4 15 c3 43 2f 81 db 87 19 53 9d 5b f3 72 aa ae a1 cc 43 a6 c5 cb e5 97 58 bf ee 29 16 58 0d ac 4b 00 8e 59 5f 43 74 91 d8 7a be d0 2c ef cd 9d b5 3d 94 d0 2d ae 17 b1 18 e5 d6 78 74 63 18 3b 4b 87 c1 05 00 00 00 30 2a 80 8d 7f 52 51 44 06 13 d1 7c a5 10 55 f2 f4 16 a4 4f e1 80 d2 d5 0c 31 2c ca 7c b1 4a 20 dc 33 1f 57 a9 81 71 39 a2 06 fc 76 95 72 27 ff ff 2d e2 0a 4b 8e 37 37 fb b4 01 00 00 00 06 37 6f 79 9e ba 36 7e 21 f9 4c a5 98 70 5f 5d cb 76 7d 6f 09 00 d6 b0 f6 09 5e 53 c4 c4 23 4d 0c 1f be 43 4f 6a b8 3c 00 13 ee 93 b8 39 46 ee 77 59 e8 9d 7b dd 1a 32 d7 b3 11 71 1b 75 7f e4 3c 06 d2 1a 35 81 0d 8f e9 8b 27 fa ea 8a a1 2b c8 71 6e ef c5 c9 7c 45 ac 33 ee ec 96 4c 52 14 bc 3a 93 59 bd ea 1c cc ab 94 f1 5e 36 31 9c b3 4e bc ac ed b8 2c 2e d3 de 5a 8a 8f 00 11 e8 f7 4e 82 d7 ce ec 7d c8 08 bf 65 36 39 d7 96 19 39 ad fd ee ea ff 19 d1 1e fc af b6 d5 46 fe f2 71 e8 9d 6c c2 38 9e 81 ff 58 ce fc ce 3f bf 46 25 a7 e7 de 40 e4 2e 07 b3 44 49 e1 5e 06 5c c7 34 86 63 a5 21 90 20 2c 7a f2 88 a4 51 0d e0 3d ab 19 d2 62 85 ed a8 91 56 d5 0d d3 85 a6 02 00 00 00 00 00 00 00 70 07 ad 15 19 ad 54 70 de 3d d6 d6 08 0c af cc f8 a9 74 06 bb 6b 68 a1 f0 c4 54 98 20 a7 3c 88 0f 47 5f 73 2a e0 03 03 00 00 00 00 00 00 00 7f b3 3b 72 68 5e c3 7a 2d 3f 76 64 13 a6 04 59 51 62 46 e5 a1 d9 98 a2 01 7a ef 09 48 a6 8c f2 55 31 5a b8 0d d3 49 e8 91 ae f5 95 dc 4d 47 0e 8a c3 2a 30 8e 15 fc 37 d0 6a ea c2 89 c0 52 3f 48 3e 1f f7 40 8c 60 87 f1 ab 65 2f 2e f9 1d 4f 2b 01 98 7b 0f 46 da 03 4e 5c 3f 74 5a 7e e8 10 1a 39 34 c5 4e 24 b4 8e c0 27 5e 2d 06 87 dc 74 6b 08 27 cb f6 52 90 06 c6 b9 5f 27 22 e5 8c 05 f7 52 ce 21 26 59 6e 1c d7 65 5b 90 48 01 78 4c 41 6b 22 f7 3d 32 46 78 e2 72 4f 43 f1 fe 68 7c 7e 8a 60 c2 8b 82 b6 52 2f b5 f6 ff cd d5 6f ed 88 93 5f cb 75 91 2d 5e cd 36 de a3 bc a0 b7 42 7d 83 92 c6 28 94 55 e8 f8 d2 ab 22 42 72 92 51 ae 23 3a 9e 02 21 0e 62 df 05 46 a7 4b 33 3a 1c 48 f9 5f d5 4a cb 57 41 25 9e 8c 54 88 ef ee e3 27 41 5c c1 94 51 43 2c 6f 14 c2 76 93 10 2a 5b d8 48 57 cd 65 86 fc 5c a9 a9 3e b0 14 5f ac 06 62 ff 86 10 7f 99 8a 8e f7 df 8a a1 40 46 c5 5b 03 d3 d4 7f 88 a8 d6 0f 77 74 a2 ee 08 00 88 97 fb 41 1a 94 b3 c2 fc 5d 5f 0d b4 2c 04 56 ec 01 5f 08 e5 24 7d 33 ae 2d 35 60 3f f8 45 4c 16 f8 34 28 56 93 51 25 10 2b b6 ce 43 1b 63 ee 35 6b 0c 78 5f 2f 47 b9 0e 29 38 9f 22 fc 5b 59 a7 0e fa ea 2b d4 01 95 af 44 86 22 0d 70 2e 30 bf c4 3c 10 ec 23 ea 62 83 99 4a 7d de 4d cb 61 fe a6 b6 51 fb 1d 62 45 8d 07 41 a1 28 30 05 2f cc 46 0d b0 43 af e5 25 62 9b 40 d7 ce e4 58 e4 cb 5e 93 0e d6 24 80 6c 43 a0 06 e3 93 36 d0 7c 2b 80 c1 c1 28 ad 27 06 f4 82 61 f7 89 74 84 c2 97 a1 a6 61 3b c1 8f 5a 38 d4 42 76 8a f3 80 41 ef e0 3d 15 2e f9 5f f5 69 e7 6d b2 39 1f 45 09 d7 f3 39 d9 2f db 4a 89 36 49 49 da 39 80 00 00 00 00 00 00 00 d8 0a 4f e6 54 57 83 76 e5 99 af f3 56 5b 1d 53 1f 30 91 2b 99 45 03 0b 81 ea 99 35 fd 46 ed b4 4a 78 f6 15 25 54 90 a4 b6 21 50 1f 2a 9e 4d 24 62 4c 4d ac 92 74 11 8c 67 58 4f 5d 37 47 55 53 4d 7f 68 f6 79 c4 ff 51 6a 9c 86 1a 0e 7e 65 86 8f cb 2b f1 cb 9a ea 4e 05 df 72 27 9f db 0d 2b 9e 93 5c 5a f3 cf 47 4b ed 79 df c2 48 c1 f5 ae a4 b8 b3 2c 5d 29 5e 57 fa 9c 0f e6 62 a4 6b 7f 71 cd 47 74 4d b8 6c 50 b7 04 c9 8a d9 02 95 c7 b2 c7 43 9a 2d 78 cc fa 79 b5 fc 2b ff 6b bf 84 02 62 bf 89 39 4b 3e 06 91 95 32 64 d2 70 0c 83 8f a2 c7 b3 42 52 60 f5 95 54 e5 02 dc ea 39 cb 31 3b 00 00 00 00 00 00 4c a7 c1 2f 45 85 8d 62 84 ca 62 70 d6 b2 f0 e5 8f de d8 a7 b4 a3 02 a9 7b c6 41 df 07 72 0b a2 b2 6b bf cc 80 7c a0 ab b1 b4 43 22 26 9c 21 c5 ec 68 cb 06 8e a8 80 67 d9 05 ea 91 7b b0 3e ef da eb de ab f2 d0 dc e8 09 97 c9 15 c8 94 9d e9 92 58 7c 2c b5 fe 36 05 00 00 00 00 00 00 00 b7 79 40 b5 f0 77 22 e4 7a 08 d3 67 95 07 00 00 00 00 00 00 93 4b 99 b3 10 9a f6 5d 77 e8 6a bd 68 59 cd df 4b ba e1 f0 93 04 62 df 15 fd db c4 85 62 ea 35 11 a8 06 5e f0 28 cf 12 f1 4d cf 6e be cd 8d 88 48 36 17 4f af 1a a6 09 e5 f1 ee 10 62 df a1 3b dc 1f a7 cf aa db a8 5c 72 e9 75 8f 03 a7 55 d0 be 53 f8 d2 a1 df 0d 07 b3 d5 bd 3b 01 fa ff d0 ad db ed 28 81 a9 70 0a f5 61 ac 8c 7e 36 bb 2f c4 c4 0e 9c 76 6c 06 81 7b b9 03 72 9a 7d b6 ff 95 76 97 c9 ed e7 88 5d 94 ff b0 75 9b e0 da f6 0a f9 31 09 eb 1d ee 72 e4 36 3f 51 af 62 af 6f b2 a6 df 3b ec 89 82 2a 7a 0b 67 80 58 fa 3f ef 86 fa ec 21 6e b6 99 21 62 f8 dc bf 71 9c 14 84 d2 f9 c5 5f 49 01 20 3a 9a 8a 2c 3e 90 f3 9c 3d bc 10 36 0a 1a 49 70 0d 1d fb f6 6d 69 f6 fb af 50 6c 8b cc e8 bb 0d 87 2a 02 23 89 26 40 7a 4e dd d5 d0 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00} (length 0x1000)
// size: len = 0x1000 (2 bytes)
// }
// }
// }
// len: len = 0x1006 (8 bytes)
// ]
*(uint32_t*)0x200000001980 = 9;
memcpy((void*)0x200000001984, "... [truncated large byte array] ...", 4096);
*(uint16_t*)0x200000002984 = 0x1000;
syscall(__NR_write, /*fd=*/r[1], /*data=*/0x200000001980ul, /*len=*/0x1006ul);
return 0;
}
Reply: Based on the analysis of the bug report and the kernel source code, here is the assessment of the vulnerability:
### Bug Mechanism
The bug is a race condition in the `cm109` USB driver (for C-Media CM109/CM119 USB phones) that leads to a double submission of the same USB Request Block (URB), causing a double `list_add` and subsequent list corruption in the USB core.
When a CM109 USB device is plugged in, the kernel registers it as an input device. The VT keyboard handler (`kbd_connect`) automatically opens the device, invoking the driver's `cm109_input_open()` callback. This function initializes the device and submits the control URB (`dev->urb_ctl`) to the USB core. Crucially, it does so **without** holding the driver's `dev->ctl_submit_lock`.
Concurrently, if a terminal bell event is triggered (e.g., an unprivileged user printing a `\a` bell character to a virtual terminal like `/dev/tty1`), `kd_mksound()` injects a sound event into the input subsystem. This invokes the driver's `cm109_input_ev()` callback, which calls `cm109_toggle_buzzer_async()`. This function takes the `dev->ctl_submit_lock`, checks if the control URB is already pending, and if not, submits `dev->urb_ctl`.
Because `cm109_input_open()` does not hold the lock, both functions can execute concurrently. They can both observe the URB as not pending and call `usb_submit_urb(dev->urb_ctl)` simultaneously. The USB core's `usb_submit_urb()` checks if the URB is already active by verifying `urb->hcpriv == NULL` without any locks. Both threads can pass this check before the Host Controller Driver (HCD) has a chance to set `urb->hcpriv`. Consequently, both threads proceed to enqueue the URB, leading to a double `list_add` in the HCD's endpoint queue (`usb_hcd_link_urb_to_ep`).
### Security Impact
* **Exploitable & Denial of Service:** Yes. A double `list_add` corrupts the kernel's internal linked lists. While `CONFIG_DEBUG_LIST` (if enabled) will catch this and safely crash the kernel (Denial of Service), production kernels typically disable list debugging for performance. In such cases, the list corruption can be manipulated to achieve arbitrary memory read/write or use-after-free, which is a classic vector for privilege escalation.
* **Peripheral Trigger:** Yes. The bug requires the attacker to plug in a malicious or standard CM109 USB device to trigger the `cm109_input_open()` path while simultaneously triggering a terminal bell.
* **VM Host Trigger:** Yes. A malicious hypervisor can hotplug a virtual CM109 USB device into a Confidential Computing guest to trigger the vulnerability and compromise the guest kernel.
* **Accessible From Unprivileged Processes:** No. While an unprivileged user can trigger the terminal bell, they cannot trigger the `cm109_input_open()` path without physical access to plug in the USB device, as unprivileged users do not have the permissions to open `/dev/input/eventX` devices directly or emulate USB devices via `/dev/raw-gadget`.
|
| 6/2 |
2026/05/21 10:11 |
llm |
expert |
0m
Model:
Tokens:
input: 24777
output: 51
thoughts: 956
Thoughts: **Analyzing a Kernel Bug: Double List Addition**
Okay, so I've got this bug report, and it's pretty clear what's happening: a double addition to a list, as the report indicates: `list_add double add: new=ffff888028dc3118, prev=ffff888028dc3118, next=ffff8880761de078.` The error is occurring in `lib/list_debug.c` at line 35, specifically in the `__list_add_valid_or_report` function. That gives me a direct line to the likely source, which is invaluable.
The stack trace is a good starting point to retrace the steps to find the root cause, and I need to start from the bottom. I can see the list manipulation happening in `__list_add`, which means the problem stems from incorrect usage of the list manipulation functions. Tracing back up the stack, `list_add_tail` is called by `usb_hcd_link_urb_to_ep`, and the trail leads us through the USB core, the dummy HCD, and ultimately into the `cm109` driver. This means there's some issue with how the `cm109` device is interacting with the USB subsystem and, ultimately, the list management functions.
The reproducer is using `syz_usb_connect`, emulating a USB device, and then writing to `/dev/tty4`. Okay, that gives me the context. The USB device in question seems to be a `cm109` device, which I can then cross-reference with the driver calls in the stack trace. This should help me understand the flow of events that leads to the double-add.
I need to dig deeper into the `cm109` driver, specifically the `cm109_submit_buzz_toggle` function, as that's where the stack trace goes through before hitting the USB core. It's likely within this function, or one of its callers, that the incorrect list manipulation is occurring. I will start by looking at how `cm109_submit_buzz_toggle` is using the list and how it is interacting with the USB subsystem. I'll need to pay close attention to the data structures involved, the locks in use, and potential race conditions.
|
| 7/2 |
2026/05/21 10:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_submit_buzz_toggle]
Results: map[SourceCode: 342: static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
343: {
344: int error;
345:
346: if (dev->buzzer_state)
347: dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
348: else
349: dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
350:
351: error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
352: if (error)
353: dev_err(&dev->intf->dev,
354: "%s: usb_submit_urb (urb_ctl) failed %d\n",
355: __func__, error);
356: }
SourceFile:drivers/input/misc/cm109.c]
|
| 8/2 |
2026/05/21 10:11 |
llm |
expert |
0m
Model:
Tokens:
input: 26573
output: 43
thoughts: 106
Thoughts: **Debugging a Double List Add**
Okay, so I'm tracking down this bug, and it looks like the problem centers around a double `list_add`. That's never good. The root cause appears to be the `cm109_submit_buzz_toggle` function submitting the `dev->urb_ctl` urb. Now, if `cm109_submit_buzz_toggle` gets called in quick succession, either concurrently or even just sequentially without waiting for the prior URB to finish, it appears we're ending up submitting that *same* URB more than once. That's a classic race condition and a recipe for all sorts of kernel woes.
Wait a second⦠shouldn't `usb_submit_urb` itself have a check to see if an URB is already pending? I feel like that would be a very common safety measure. I need to take a look at the code for `usb_submit_urb` and see what's actually going on in there. It's time to dig into the USB core and confirm my hypothesis.
|
| 9/2 |
2026/05/21 10:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/urb.c IncludeLines:true Name:usb_submit_urb]
Results: map[SourceCode: 231: /**
232: * usb_submit_urb - issue an asynchronous transfer request for an endpoint
233: * @urb: pointer to the urb describing the request
234: * @mem_flags: the type of memory to allocate, see kmalloc() for a list
235: * of valid options for this.
236: *
237: * This submits a transfer request, and transfers control of the URB
238: * describing that request to the USB subsystem. Request completion will
239: * be indicated later, asynchronously, by calling the completion handler.
240: * The three types of completion are success, error, and unlink
241: * (a software-induced fault, also called "request cancellation").
242: *
243: * URBs may be submitted in interrupt context.
244: *
245: * The caller must have correctly initialized the URB before submitting
246: * it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
247: * available to ensure that most fields are correctly initialized, for
248: * the particular kind of transfer, although they will not initialize
249: * any transfer flags.
250: *
251: * If the submission is successful, the complete() callback from the URB
252: * will be called exactly once, when the USB core and Host Controller Driver
253: * (HCD) are finished with the URB. When the completion function is called,
254: * control of the URB is returned to the device driver which issued the
255: * request. The completion handler may then immediately free or reuse that
256: * URB.
257: *
258: * With few exceptions, USB device drivers should never access URB fields
259: * provided by usbcore or the HCD until its complete() is called.
260: * The exceptions relate to periodic transfer scheduling. For both
261: * interrupt and isochronous urbs, as part of successful URB submission
262: * urb->interval is modified to reflect the actual transfer period used
263: * (normally some power of two units). And for isochronous urbs,
264: * urb->start_frame is modified to reflect when the URB's transfers were
265: * scheduled to start.
266: *
267: * Not all isochronous transfer scheduling policies will work, but most
268: * host controller drivers should easily handle ISO queues going from now
269: * until 10-200 msec into the future. Drivers should try to keep at
270: * least one or two msec of data in the queue; many controllers require
271: * that new transfers start at least 1 msec in the future when they are
272: * added. If the driver is unable to keep up and the queue empties out,
273: * the behavior for new submissions is governed by the URB_ISO_ASAP flag.
274: * If the flag is set, or if the queue is idle, then the URB is always
275: * assigned to the first available (and not yet expired) slot in the
276: * endpoint's schedule. If the flag is not set and the queue is active
277: * then the URB is always assigned to the next slot in the schedule
278: * following the end of the endpoint's previous URB, even if that slot is
279: * in the past. When a packet is assigned in this way to a slot that has
280: * already expired, the packet is not transmitted and the corresponding
281: * usb_iso_packet_descriptor's status field will return -EXDEV. If this
282: * would happen to all the packets in the URB, submission fails with a
283: * -EXDEV error code.
284: *
285: * For control endpoints, the synchronous usb_control_msg() call is
286: * often used (in non-interrupt context) instead of this call.
287: * That is often used through convenience wrappers, for the requests
288: * that are standardized in the USB 2.0 specification. For bulk
289: * endpoints, a synchronous usb_bulk_msg() call is available.
290: *
291: * Return:
292: * 0 on successful submissions. A negative error number otherwise.
293: *
294: * Request Queuing:
295: *
296: * URBs may be submitted to endpoints before previous ones complete, to
297: * minimize the impact of interrupt latencies and system overhead on data
298: * throughput. With that queuing policy, an endpoint's queue would never
299: * be empty. This is required for continuous isochronous data streams,
300: * and may also be required for some kinds of interrupt transfers. Such
301: * queuing also maximizes bandwidth utilization by letting USB controllers
302: * start work on later requests before driver software has finished the
303: * completion processing for earlier (successful) requests.
304: *
305: * As of Linux 2.6, all USB endpoint transfer queues support depths greater
306: * than one. This was previously a HCD-specific behavior, except for ISO
307: * transfers. Non-isochronous endpoint queues are inactive during cleanup
308: * after faults (transfer errors or cancellation).
309: *
310: * Reserved Bandwidth Transfers:
311: *
312: * Periodic transfers (interrupt or isochronous) are performed repeatedly,
313: * using the interval specified in the urb. Submitting the first urb to
314: * the endpoint reserves the bandwidth necessary to make those transfers.
315: * If the USB subsystem can't allocate sufficient bandwidth to perform
316: * the periodic request, submitting such a periodic request should fail.
317: *
318: * For devices under xHCI, the bandwidth is reserved at configuration time, or
319: * when the alt setting is selected. If there is not enough bus bandwidth, the
320: * configuration/alt setting request will fail. Therefore, submissions to
321: * periodic endpoints on devices under xHCI should never fail due to bandwidth
322: * constraints.
323: *
324: * Device drivers must explicitly request that repetition, by ensuring that
325: * some URB is always on the endpoint's queue (except possibly for short
326: * periods during completion callbacks). When there is no longer an urb
327: * queued, the endpoint's bandwidth reservation is canceled. This means
328: * drivers can use their completion handlers to ensure they keep bandwidth
329: * they need, by reinitializing and resubmitting the just-completed urb
330: * until the driver longer needs that periodic bandwidth.
331: *
332: * Memory Flags:
333: *
334: * The general rules for how to decide which mem_flags to use
335: * are the same as for kmalloc. There are four
336: * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
337: * GFP_ATOMIC.
338: *
339: * GFP_NOFS is not ever used, as it has not been implemented yet.
340: *
341: * GFP_ATOMIC is used when
342: * (a) you are inside a completion handler, an interrupt, bottom half,
343: * tasklet or timer, or
344: * (b) you are holding a spinlock or rwlock (does not apply to
345: * semaphores), or
346: * (c) current->state != TASK_RUNNING, this is the case only after
347: * you've changed it.
348: *
349: * GFP_NOIO is used in the block io path and error handling of storage
350: * devices.
351: *
352: * All other situations use GFP_KERNEL.
353: *
354: * Some more specific rules for mem_flags can be inferred, such as
355: * (1) start_xmit, timeout, and receive methods of network drivers must
356: * use GFP_ATOMIC (they are called with a spinlock held);
357: * (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
358: * called with a spinlock held);
359: * (3) If you use a kernel thread with a network driver you must use
360: * GFP_NOIO, unless (b) or (c) apply;
361: * (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
362: * apply or your are in a storage driver's block io path;
363: * (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
364: * (6) changing firmware on a running storage or net device uses
365: * GFP_NOIO, unless b) or c) apply
366: *
367: */
368: int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
369: {
370: int xfertype, max;
371: struct usb_device *dev;
372: struct usb_host_endpoint *ep;
373: int is_out;
374: unsigned int allowed;
375: bool is_eusb2_isoch_double;
376:
377: if (!urb || !urb->complete)
378: return -EINVAL;
379: if (urb->hcpriv) {
380: WARN_ONCE(1, "URB %p submitted while active\n", urb);
381: return -EBUSY;
382: }
383:
384: dev = urb->dev;
385: if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
386: return -ENODEV;
387:
388: /* For now, get the endpoint from the pipe. Eventually drivers
389: * will be required to set urb->ep directly and we will eliminate
390: * urb->pipe.
391: */
392: ep = usb_pipe_endpoint(dev, urb->pipe);
393: if (!ep)
394: return -ENOENT;
395:
396: urb->ep = ep;
397: urb->status = -EINPROGRESS;
398: urb->actual_length = 0;
399:
400: /* Lots of sanity checks, so HCDs can rely on clean data
401: * and don't need to duplicate tests
402: */
403: xfertype = usb_endpoint_type(&ep->desc);
404: if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
405: struct usb_ctrlrequest *setup =
406: (struct usb_ctrlrequest *) urb->setup_packet;
407:
408: if (!setup)
409: return -ENOEXEC;
410: is_out = !(setup->bRequestType & USB_DIR_IN) ||
411: !setup->wLength;
412: dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out),
413: "BOGUS control dir, pipe %x doesn't match bRequestType %x\n",
414: urb->pipe, setup->bRequestType);
415: if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) {
416: dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n",
417: le16_to_cpu(setup->wLength),
418: urb->transfer_buffer_length);
419: return -EBADR;
420: }
421: } else {
422: is_out = usb_endpoint_dir_out(&ep->desc);
423: }
424:
425: /* Clear the internal flags and cache the direction for later use */
426: urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
427: URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
428: URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
429: URB_DMA_SG_COMBINED);
430: urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
431: kmsan_handle_urb(urb, is_out);
432:
433: if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
434: dev->state < USB_STATE_CONFIGURED)
435: return -ENODEV;
436:
437: max = usb_endpoint_maxp(&ep->desc);
438: is_eusb2_isoch_double = usb_endpoint_is_hs_isoc_double(dev, ep);
439: if (!max && !is_eusb2_isoch_double) {
440: dev_dbg(&dev->dev,
441: "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
442: usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
443: __func__, max);
444: return -EMSGSIZE;
445: }
446:
447: /* periodic transfers limit size per frame/uframe,
448: * but drivers only control those sizes for ISO.
449: * while we're checking, initialize return status.
450: */
451: if (xfertype == USB_ENDPOINT_XFER_ISOC) {
452: int n, len;
453:
454: /* SuperSpeed isoc endpoints have up to 16 bursts of up to
455: * 3 packets each
456: */
457: if (dev->speed >= USB_SPEED_SUPER) {
458: int burst = 1 + ep->ss_ep_comp.bMaxBurst;
459: int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
460: max *= burst;
461: max *= mult;
462: }
463:
464: if (dev->speed == USB_SPEED_SUPER_PLUS &&
465: USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) {
466: struct usb_ssp_isoc_ep_comp_descriptor *isoc_ep_comp;
467:
468: isoc_ep_comp = &ep->ssp_isoc_ep_comp;
469: max = le32_to_cpu(isoc_ep_comp->dwBytesPerInterval);
470: }
471:
472: /* High speed, 1-3 packets/uframe, max 6 for eUSB2 double bw */
473: if (dev->speed == USB_SPEED_HIGH) {
474: if (is_eusb2_isoch_double)
475: max = le32_to_cpu(ep->eusb2_isoc_ep_comp.dwBytesPerInterval);
476: else
477: max *= usb_endpoint_maxp_mult(&ep->desc);
478: }
479:
480: if (urb->number_of_packets <= 0)
481: return -EINVAL;
482: for (n = 0; n < urb->number_of_packets; n++) {
483: len = urb->iso_frame_desc[n].length;
484: if (len < 0 || len > max)
485: return -EMSGSIZE;
486: urb->iso_frame_desc[n].status = -EXDEV;
487: urb->iso_frame_desc[n].actual_length = 0;
488: }
489: } else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint) {
490: struct scatterlist *sg;
491: int i;
492:
493: for_each_sg(urb->sg, sg, urb->num_sgs - 1, i)
494: if (sg->length % max)
495: return -EINVAL;
496: }
497:
498: /* the I/O buffer must be mapped/unmapped, except when length=0 */
499: if (urb->transfer_buffer_length > INT_MAX)
500: return -EMSGSIZE;
501:
502: /*
503: * stuff that drivers shouldn't do, but which shouldn't
504: * cause problems in HCDs if they get it wrong.
505: */
506:
507: /* Check that the pipe's type matches the endpoint's type */
508: if (usb_pipe_type_check(urb->dev, urb->pipe))
509: dev_warn_once(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
510: usb_pipetype(urb->pipe), pipetypes[xfertype]);
511:
512: /* Check against a simple/standard policy */
513: allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
514: URB_FREE_BUFFER);
515: switch (xfertype) {
516: case USB_ENDPOINT_XFER_BULK:
517: case USB_ENDPOINT_XFER_INT:
518: if (is_out)
519: allowed |= URB_ZERO_PACKET;
520: fallthrough;
521: default: /* all non-iso endpoints */
522: if (!is_out)
523: allowed |= URB_SHORT_NOT_OK;
524: break;
525: case USB_ENDPOINT_XFER_ISOC:
526: allowed |= URB_ISO_ASAP;
527: break;
528: }
529: allowed &= urb->transfer_flags;
530:
531: /* warn if submitter gave bogus flags */
532: if (allowed != urb->transfer_flags)
533: dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
534: urb->transfer_flags, allowed);
535:
536: /*
537: * Force periodic transfer intervals to be legal values that are
538: * a power of two (so HCDs don't need to).
539: *
540: * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
541: * supports different values... this uses EHCI/UHCI defaults (and
542: * EHCI can use smaller non-default values).
543: */
544: switch (xfertype) {
545: case USB_ENDPOINT_XFER_ISOC:
546: case USB_ENDPOINT_XFER_INT:
547: /* too small? */
548: if (urb->interval <= 0)
549: return -EINVAL;
550:
551: /* too big? */
552: switch (dev->speed) {
553: case USB_SPEED_SUPER_PLUS:
554: case USB_SPEED_SUPER: /* units are 125us */
555: /* Handle up to 2^(16-1) microframes */
556: if (urb->interval > (1 << 15))
557: return -EINVAL;
558: max = 1 << 15;
559: break;
560: case USB_SPEED_HIGH: /* units are microframes */
561: /* NOTE usb handles 2^15 */
562: if (urb->interval > (1024 * 8))
563: urb->interval = 1024 * 8;
564: max = 1024 * 8;
565: break;
566: case USB_SPEED_FULL: /* units are frames/msec */
567: case USB_SPEED_LOW:
568: if (xfertype == USB_ENDPOINT_XFER_INT) {
569: if (urb->interval > 255)
570: return -EINVAL;
571: /* NOTE ohci only handles up to 32 */
572: max = 128;
573: } else {
574: if (urb->interval > 1024)
575: urb->interval = 1024;
576: /* NOTE usb and ohci handle up to 2^15 */
577: max = 1024;
578: }
579: break;
580: default:
581: return -EINVAL;
582: }
583: /* Round down to a power of 2, no more than max */
584: urb->interval = min(max, 1 << ilog2(urb->interval));
585: }
586:
587: return usb_hcd_submit_urb(urb, mem_flags);
588: }
SourceFile:drivers/usb/core/urb.c]
|
| 10/2 |
2026/05/21 10:11 |
llm |
expert |
0m
Model:
Tokens:
input: 33184
output: 51
thoughts: 148
Thoughts: **Analyzing USB URB Submission in the cm109 Driver**
Okay, let's break this down. I'm looking at `usb_submit_urb` and I see this check: `if (urb->hcpriv) { WARN_ONCE(1, "URB %p submitted while active\n", urb); return -EBUSY; }`. Alright, so the code's designed to prevent submitting an already active URB β makes sense. The `urb->hcpriv` field, I recall from memory, indicates an active URB. It's probably a handle for the host controller's private data for this specific URB.
Now, I see the `cm109_submit_buzz_toggle` function. It seems this function is submitting `dev->urb_ctl`. Okay, I have a suspicion that's a control transfer URB used for, as the function name suggests, toggling something β probably an LED or some functionality related to the buzz feature.
The key question is, when is `urb->hcpriv` set, and when does it get cleared? If it's not set when the URB is submitted, weβll move on, but we have a problem. The important thing to consider here is that `usb_hcd_submit_urb` will eventually be called. And, I think this function is the source of truth, it calls `usb_hcd_link_urb_to_ep`, which *should* be the place where the `hcpriv` field gets set. If my understanding is correct, the issue is that in some cases `urb->hcpriv` might not be set before calling `usb_submit_urb`. This could result in an active URB being resubmitted, and that's precisely what the `WARN_ONCE` and `-EBUSY` are designed to avoid, so there's an inconsistency somewhere here. It needs further investigation to ensure proper URB state management within this driver.
|
| 11/2 |
2026/05/21 10:12 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/hcd.c IncludeLines:true Name:usb_hcd_link_urb_to_ep]
Results: map[SourceCode:1115: /**
1116: * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
1117: * @hcd: host controller to which @urb was submitted
1118: * @urb: URB being submitted
1119: *
1120: * Host controller drivers should call this routine in their enqueue()
1121: * method. The HCD's private spinlock must be held and interrupts must
1122: * be disabled. The actions carried out here are required for URB
1123: * submission, as well as for endpoint shutdown and for usb_kill_urb.
1124: *
1125: * Return: 0 for no error, otherwise a negative error code (in which case
1126: * the enqueue() method must fail). If no error occurs but enqueue() fails
1127: * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
1128: * the private spinlock and returning.
1129: */
1130: int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
1131: {
1132: int rc = 0;
1133:
1134: spin_lock(&hcd_urb_list_lock);
1135:
1136: /* Check that the URB isn't being killed */
1137: if (unlikely(atomic_read(&urb->reject))) {
1138: rc = -EPERM;
1139: goto done;
1140: }
1141:
1142: if (unlikely(!urb->ep->enabled)) {
1143: rc = -ENOENT;
1144: goto done;
1145: }
1146:
1147: if (unlikely(!urb->dev->can_submit)) {
1148: rc = -EHOSTUNREACH;
1149: goto done;
1150: }
1151:
1152: /*
1153: * Check the host controller's state and add the URB to the
1154: * endpoint's queue.
1155: */
1156: if (HCD_RH_RUNNING(hcd)) {
1157: urb->unlinked = 0;
1158: list_add_tail(&urb->urb_list, &urb->ep->urb_list);
1159: } else {
1160: rc = -ESHUTDOWN;
1161: goto done;
1162: }
1163: done:
1164: spin_unlock(&hcd_urb_list_lock);
1165: return rc;
1166: }
SourceFile:drivers/usb/core/hcd.c]
|
| 12/2 |
2026/05/21 10:12 |
llm |
expert |
0m
Model:
Tokens:
input: 34614
output: 47
thoughts: 210
Thoughts: **Debugging a USB URB Crash**
Okay, so the crash is definitely happening inside `list_add_tail(&urb->urb_list, &urb->ep->urb_list);`. That's the smoking gun. I immediately recognize that `list_add_tail` is a critical point. It calls `__list_add_valid_or_report`, and I know that function is all about checking list integrity. It looks for common list corruption scenarios: `new->next == LIST_POISON1`, `new->prev == LIST_POISON2`, that kind of thing, or if the list is already connected.
Wait a second... the line's adding `urb->urb_list` to `urb->ep->urb_list`. Right. If the `urb` has already been submitted, `urb->urb_list` *should* already be in `urb->ep->urb_list`. That's the likely root of the problem. But `usb_submit_urb` should protect against that, doesn't it? It has to!
Let me thinkβ¦ `usb_submit_urb` checks `urb->hcpriv`. If `urb->hcpriv` is NULL, it proceeds with submission. So, the question is *who* sets `urb->hcpriv`? That's the key. I need to trace this back. Let's dig into `usb_hcd_submit_urb` β that's where the hardware controller gets involved, so it's a likely candidate for modifying `urb->hcpriv`. I need to understand when and how `urb->hcpriv` is initialized and, vitally, *when* it's set to NULL. That's where the bug is, I feel.
|
| 13/2 |
2026/05/21 10:12 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/hcd.c IncludeLines:true Name:usb_hcd_submit_urb]
Results: map[SourceCode:1514: /* may be called in any context with a valid urb->dev usecount
1515: * caller surrenders "ownership" of urb
1516: * expects usb_submit_urb() to have sanity checked and conditioned all
1517: * inputs in the urb
1518: */
1519: int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
1520: {
1521: int status;
1522: struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
1523:
1524: /* increment urb's reference count as part of giving it to the HCD
1525: * (which will control it). HCD guarantees that it either returns
1526: * an error or calls giveback(), but not both.
1527: */
1528: usb_get_urb(urb);
1529: atomic_inc(&urb->use_count);
1530: atomic_inc(&urb->dev->urbnum);
1531: usbmon_urb_submit(&hcd->self, urb);
1532:
1533: /* NOTE requirements on root-hub callers (usbfs and the hub
1534: * driver, for now): URBs' urb->transfer_buffer must be
1535: * valid and usb_buffer_{sync,unmap}() not be needed, since
1536: * they could clobber root hub response data. Also, control
1537: * URBs must be submitted in process context with interrupts
1538: * enabled.
1539: */
1540:
1541: if (is_root_hub(urb->dev)) {
1542: status = rh_urb_enqueue(hcd, urb);
1543: } else {
1544: status = map_urb_for_dma(hcd, urb, mem_flags);
1545: if (likely(status == 0)) {
1546: status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
1547: if (unlikely(status))
1548: unmap_urb_for_dma(hcd, urb);
1549: }
1550: }
1551:
1552: if (unlikely(status)) {
1553: usbmon_urb_submit_error(&hcd->self, urb, status);
1554: urb->hcpriv = NULL;
1555: INIT_LIST_HEAD(&urb->urb_list);
1556: atomic_dec(&urb->use_count);
1557: /*
1558: * Order the write of urb->use_count above before the read
1559: * of urb->reject below. Pairs with the memory barriers in
1560: * usb_kill_urb() and usb_poison_urb().
1561: */
1562: smp_mb__after_atomic();
1563:
1564: atomic_dec(&urb->dev->urbnum);
1565: if (atomic_read(&urb->reject))
1566: wake_up(&usb_kill_urb_queue);
1567: usb_put_urb(urb);
1568: }
1569: return status;
1570: }
SourceFile:drivers/usb/core/hcd.c]
|
| 14/2 |
2026/05/21 10:12 |
llm |
expert |
0m
Model:
Tokens:
input: 36198
output: 50
thoughts: 41
Thoughts: Okay, here's my interpretation of that code snippet, delivered as if it's my own thought process:
**Enqueuing a USB Request: Let's Trace the Path**
Right, so I see `hcd->driver->urb_enqueue(hcd, urb, mem_flags);`. This is a classic USB host controller driver function call. The `hcd` is the host controller device itself, `urb` is the USB Request Block containing all the details of the transfer, and `mem_flags` specify how memory should be allocated. The critical piece here is the indirection: we're calling a function pointer (`urb_enqueue`) *through* the `hcd->driver` structure. Thatβs how we achieve the flexibility needed for different HCD implementations.
Now, because I am familiar with the code, I know that for `dummy_hcd`, the specific implementation resolves to `dummy_urb_enqueue`. That makes perfect sense. The dummy HCD is, well, *dummy*. Itβs probably a test or simulation harness. Its `urb_enqueue` implementation is likely very simple, maybe just logging the request, setting a status, or simulating some minimal transfer behavior, without actually interacting with any physical hardware. So, instead of a real hardware transfer, the `dummy_urb_enqueue` would simulate the enqueue process. It's a key detail to remember when debugging or analyzing the framework.
|
| 15/2 |
2026/05/21 10:12 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c IncludeLines:true Name:dummy_urb_enqueue]
Results: map[SourceCode:1263: static int dummy_urb_enqueue(
1264: struct usb_hcd *hcd,
1265: struct urb *urb,
1266: gfp_t mem_flags
1267: ) {
1268: struct dummy_hcd *dum_hcd;
1269: struct urbp *urbp;
1270: unsigned long flags;
1271: int rc;
1272:
1273: urbp = kmalloc(sizeof *urbp, mem_flags);
1274: if (!urbp)
1275: return -ENOMEM;
1276: urbp->urb = urb;
1277: urbp->miter_started = 0;
1278:
1279: dum_hcd = hcd_to_dummy_hcd(hcd);
1280: spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1281:
1282: rc = dummy_validate_stream(dum_hcd, urb);
1283: if (rc) {
1284: kfree(urbp);
1285: goto done;
1286: }
1287:
1288: rc = usb_hcd_link_urb_to_ep(hcd, urb);
1289: if (rc) {
1290: kfree(urbp);
1291: goto done;
1292: }
1293:
1294: if (!dum_hcd->udev) {
1295: dum_hcd->udev = urb->dev;
1296: usb_get_dev(dum_hcd->udev);
1297: } else if (unlikely(dum_hcd->udev != urb->dev))
1298: dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
1299:
1300: list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
1301: urb->hcpriv = urbp;
1302: if (!dum_hcd->next_frame_urbp)
1303: dum_hcd->next_frame_urbp = urbp;
1304: if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
1305: urb->error_count = 1; /* mark as a new urb */
1306:
1307: /* kick the scheduler, it'll do the rest */
1308: if (!dum_hcd->timer_pending) {
1309: dum_hcd->timer_pending = 1;
1310: hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
1311: HRTIMER_MODE_REL_SOFT);
1312: }
1313:
1314: done:
1315: spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1316: return rc;
1317: }
SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]
|
| 16/2 |
2026/05/21 10:12 |
llm |
expert |
0m
Model:
Tokens:
input: 37493
output: 49
thoughts: 374
Thoughts: **Analyzing a Potential Race Condition in USB URB Submission**
Okay, let's break this down. It seems there's a race condition lurking within the USB URB submission process, specifically concerning the handling of `urb->hcpriv` and its interaction with `usb_hcd_link_urb_to_ep`. The crux of the issue appears to stem from the sequence of operations within `dummy_urb_enqueue` where `urb->hcpriv` is set *after* the URB is linked to the endpoint.
My concern arises from a scenario where `cm109_submit_buzz_toggle` gets called concurrently β let's say, twice in rapid succession. The critical point is that `usb_submit_urb` will immediately check the `urb->hcpriv` field. Now, because `urb->hcpriv` is initialized *after* linking, the initial check by the first thread could pass, as `urb->hcpriv` would be NULL at that instant. If the timing is right (and it often is in concurrent systems), both threads could then proceed to call `usb_hcd_submit_urb`, which, in turn, calls `dummy_urb_enqueue`.
This is where the problem becomes more acute. Thread 1, in `usb_hcd_link_urb_to_ep`, successfully adds `urb->urb_list` to `urb->ep->urb_list`. But then, Thread 2, also in `usb_hcd_link_urb_to_ep`, tries to add `urb->urb_list` to the *same* `urb->ep->urb_list` again! This is an obvious double list_add that will cause corruption.
The next thing that jumps out is that `urb->hcpriv` is checked *without any locks* in `usb_submit_urb`. This is a big red flag, as it makes the check vulnerable to race conditions. The check itself is as follows:
```c
if (urb->hcpriv) {
WARN_ONCE(1, "URB %p submitted while active\n", urb);
return -EBUSY;
}
```
If two threads call `usb_submit_urb` concurrently on the same URB, they can both pass this check and cause a conflict. The key question now becomes, is it even *allowed* to submit the same URB concurrently? The code explicitly indicates it is *not* allowed. The code contains the following check:
```c
if (urb->hcpriv) {
WARN_ONCE(1, "URB %p submitted while active\n", urb);
return -EBUSY;
}
```
This is the only check the code makes to see if the URB is already submitted.
Now, where are these concurrent calls originating? It looks like `cm109_submit_buzz_toggle` is the culprit, and it's called from `cm109_toggle_buzzer_async`, which is, in turn, called from `cm109_input_ev`. Therefore, I need to check how `cm109_input_ev` handles concurrency. That's the likely root of this issue. It is a critical path to examine.
|
| 17/2 |
2026/05/21 10:12 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_input_ev]
Results: map[SourceCode: 599: static int cm109_input_ev(struct input_dev *idev, unsigned int type,
600: unsigned int code, int value)
601: {
602: struct cm109_dev *dev = input_get_drvdata(idev);
603:
604: dev_dbg(&dev->intf->dev,
605: "input_ev: type=%u code=%u value=%d\n", type, code, value);
606:
607: if (type != EV_SND)
608: return -EINVAL;
609:
610: switch (code) {
611: case SND_TONE:
612: case SND_BELL:
613: dev->buzzer_state = !!value;
614: if (!dev->resetting)
615: cm109_toggle_buzzer_async(dev);
616: return 0;
617:
618: default:
619: return -EINVAL;
620: }
621: }
SourceFile:drivers/input/misc/cm109.c]
|
| 18/2 |
2026/05/21 10:12 |
llm |
expert |
0m
Model:
Tokens:
input: 38982
output: 52
thoughts: 16
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm an expert in embedded systems or similar:
**Async Buzzer Toggle: Diving into the Details**
Alright, *cm109_toggle_buzzer_async* is being called. My immediate thought is, "Okay, let's break this down." This function name suggests a non-blocking operation, which is standard in a reactive or embedded system. I'm already mentally running through potential implications. Is this a critical interrupt path, or a background task? What specific system calls or hardware registers are likely getting touched?
The 'async' aspect is key. That tells me to expect concurrency concerns. I'm going to want to verify if there's any semaphore or mutex protection in place to prevent race conditions on the buzzer hardware. I'll need to remember any pre-emption considerations, given this is asynchronous.
The name suggests that this will toggle the buzzer. The next thing I'll consider is: What's the implementation? Is this a simple GPIO pin toggle? If so, what is the pin? How are delays being managed? Are interrupts involved in the buzzer control? Are we using a timer to manage the duration of the buzzer tone? Are we potentially using a PWM pin to control the duty cycle?
I'll be looking for potential sources of latency and how the asynchronous call handles potential errors or timeouts. Are there error states if the buzzer fails to toggle? Are errors explicitly handled or ignored? Are there any retry mechanisms? I'll also want to understand the typical timing of this function's execution as it relates to other parts of the system. I'm going to look for any clues about what could cause this function to fail (other higher priority tasks or external factors). And, of course, I'm checking for any potential for infinite loops or resource starvation due to a bug. Finally, I'll be asking, "Why asynchronous? Is it to prevent blocking a more critical task?" My deep dive into the code begins here.
|
| 19/2 |
2026/05/21 10:12 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_toggle_buzzer_async]
Results: map[SourceCode: 475: static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
476: {
477: guard(spinlock_irqsave)(&dev->ctl_submit_lock);
478:
479: if (dev->ctl_urb_pending) {
480: /* URB completion will resubmit */
481: dev->buzzer_pending = 1;
482: } else {
483: dev->ctl_urb_pending = 1;
484: cm109_submit_buzz_toggle(dev);
485: }
486: }
SourceFile:drivers/input/misc/cm109.c]
|
| 20/2 |
2026/05/21 10:12 |
llm |
expert |
0m
Model:
Tokens:
input: 39691
output: 51
thoughts: 178
Thoughts: **Analyzing the Buzzer Toggle Function**
Okay, let's break down this `cm109_toggle_buzzer_async` function. It looks like it's using `dev->ctl_submit_lock` to protect access to `dev->ctl_urb_pending`, which is good. That's the expected approach for handling potential race conditions on the USB control transfer. If `dev->ctl_urb_pending` is currently 0, the code sets it to 1 and immediately calls `cm109_submit_buzz_toggle(dev)`. Makes sense: initiate the toggle request if no other request is outstanding. If it *is* 1, meaning a request is pending, it sets `dev->buzzer_pending = 1`. This indicates that a request has been made but needs to wait. So far, so good. The design *should* prevent concurrent USB URB submissions to that control endpoint.
But wait a minute... what happens if `cm109_submit_buzz_toggle` *fails*? If the URB submission errors out for some reason β perhaps a USB bus issue or a device error β the code doesn't explicitly reset `dev->ctl_urb_pending` back to 0. Is that right? That's a potential bug. It would mean that `dev->ctl_urb_pending` would remain at 1, even though there's no active URB. Any subsequent call to the toggle function would then just set `dev->buzzer_pending` and we'd be stuck. We wouldn't be able to re-submit the URB. I need to go back and double-check how `cm109_submit_buzz_toggle` handles errors. We need to make sure that the `ctl_urb_pending` flag is reset if the submission fails. This could have real implications for reliability.
|
| 21/2 |
2026/05/21 10:12 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_submit_buzz_toggle]
Results: map[SourceCode: 342: static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
343: {
344: int error;
345:
346: if (dev->buzzer_state)
347: dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
348: else
349: dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
350:
351: error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
352: if (error)
353: dev_err(&dev->intf->dev,
354: "%s: usb_submit_urb (urb_ctl) failed %d\n",
355: __func__, error);
356: }
SourceFile:drivers/input/misc/cm109.c]
|
| 22/2 |
2026/05/21 10:12 |
llm |
expert |
0m
Model:
Tokens:
input: 40598
output: 51
thoughts: 107
Thoughts: **Debugging a USB Control Transfer Issue**
Okay, so I'm digging into this `usb_submit_urb` failure. The immediate concern is that if this function bails out, `dev->ctl_urb_pending` *isn't* getting cleared. That's a huge problem. It means that any subsequent calls to `cm109_toggle_buzzer_async` are going to behave incorrectly. It's only going to set `dev->buzzer_pending = 1` and bail! No submission. But wait a second...if `dev->ctl_urb_pending` is already set to 1, shouldn't that short-circuit any further submissions? How could it ever double-submit in this state? Something is amiss. Let me check how `cm109_urb_ctl_done` is handling it. I need to see if the completion routine is at fault.
|
| 23/2 |
2026/05/21 10:12 |
tool |
codesearch-definition-source |
0m
Error: requested entity does not exist
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_urb_ctl_done]
Results: map[SourceCode: SourceFile:]
|
| 24/2 |
2026/05/21 10:12 |
llm |
expert |
0m
Model:
Tokens:
input: 40971
output: 52
thoughts: 28
Thoughts: Okay, here's my take on those thoughts, framed as a first-person expert summary:
**Digging into the CM109 Driver's USB Control Transfer Completion**
Alright, I'm thinking I need to refresh my memory on how the `cm109` driver handles USB control transfers, specifically the completion of `urb_ctl` (USB Request Block for control transfers). I know I've worked with this driver before, and I recall some nuances in how it signals and processes completion events. To get a clear picture, I'll start by checking the source code, targeting the `drivers/input/misc/cm109.c` file. That's the logical place to start, given the device's function as a miscellaneous input device. I anticipate this file will contain the relevant `usb_submit_urb()` calls for the control transfers and, importantly, the associated completion callback function. From there, I'll trace how the callback processes status codes, handles errors, and potentially re-submits the URB if needed. I'm specifically interested in any synchronization primitives it uses around the URB's data and state. Iβm hoping to understand the edge cases and potential race conditions in this area. It's time to dive into the code and see what insights it reveals.
|
| 25/2 |
2026/05/21 10:13 |
tool |
codesearch-find-references |
0m
Error: requested entity does not exist
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeSnippetLines:0 Name:urb_ctl SourceTreePrefix:]
Results: map[References:<nil> TruncatedOutput:false]
|
| 26/2 |
2026/05/21 10:13 |
llm |
expert |
0m
Model:
Tokens:
input: 41349
output: 59
thoughts: 33
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of embedded systems:
**Deconstructing the `cm109_dev` Structure**
Alright, hang on a second. I'm looking at something β it appears to be a field or an instance related to the `struct cm109_dev`. Right, okay, that's what's in front of me. I immediately need to zero in on a specific member within that structure. Let me see... I need to check something related to `cm109_dev`. Given the context, my gut feeling is telling me to go straight for `cm109_dev::urb_ctl`. Let me verify and see if that's where I need to be. It's the most likely candidate for where I need to be.
|
| 27/2 |
2026/05/21 10:13 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeSnippetLines:0 Name:cm109_dev::urb_ctl SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_input_open SourceFile:drivers/input/misc/cm109.c SourceLine:566] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_stop_traffic SourceFile:drivers/input/misc/cm109.c SourceLine:518] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_submit_buzz_toggle SourceFile:drivers/input/misc/cm109.c SourceLine:351] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_submit_ctl SourceFile:drivers/input/misc/cm109.c SourceLine:380] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_cleanup SourceFile:drivers/input/misc/cm109.c SourceLine:664] map[ReferenceKind:writes ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:733] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:734] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:760] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:763] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:764] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:765]] TruncatedOutput:false]
|
| 28/2 |
2026/05/21 10:13 |
llm |
expert |
0m
Model:
Tokens:
input: 42269
output: 49
thoughts: 22
Thoughts: Okay, let's dive into this. Here's how I'd approach that snippet, considering my expertise:
**Checking the Completion Handler in `cm109_usb_probe`**
Alright, my first instinct is to zero in on the completion handler within `cm109_usb_probe`. Given my understanding of USB driver architecture, I know that completion handlers are absolutely critical. They're the callback functions that get executed after a USB transfer, interrupt, or other operation completes. Without knowing what this specific handler does, I'm flying blind, especially when debugging potential issues with this particular device. I need to understand what state changes, resource releases, or error handling occurs upon the completion of a request. The exact nature of the completion handler is going to be pivotal in diagnosing any problems. Let's see what that looks like.
|
| 29/2 |
2026/05/21 10:13 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_usb_probe]
Results: map[SourceCode: 677: static int cm109_usb_probe(struct usb_interface *intf,
678: const struct usb_device_id *id)
679: {
680: struct usb_device *udev = interface_to_usbdev(intf);
681: struct driver_info *nfo = (struct driver_info *)id->driver_info;
682: struct usb_host_interface *interface;
683: struct usb_endpoint_descriptor *endpoint;
684: struct cm109_dev *dev;
685: struct input_dev *input_dev = NULL;
686: int ret, pipe, i;
687: int error = -ENOMEM;
688:
689: interface = intf->cur_altsetting;
690:
691: if (interface->desc.bNumEndpoints < 1)
692: return -ENODEV;
693:
694: endpoint = &interface->endpoint[0].desc;
695:
696: if (!usb_endpoint_is_int_in(endpoint))
697: return -ENODEV;
698:
699: dev = kzalloc(sizeof(*dev), GFP_KERNEL);
700: if (!dev)
701: return -ENOMEM;
702:
703: spin_lock_init(&dev->ctl_submit_lock);
704: mutex_init(&dev->pm_mutex);
705:
706: dev->udev = udev;
707: dev->intf = intf;
708:
709: dev->idev = input_dev = input_allocate_device();
710: if (!input_dev)
711: goto err_out;
712:
713: /* allocate usb buffers */
714: dev->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
715: GFP_KERNEL, &dev->irq_dma);
716: if (!dev->irq_data)
717: goto err_out;
718:
719: dev->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
720: GFP_KERNEL, &dev->ctl_dma);
721: if (!dev->ctl_data)
722: goto err_out;
723:
724: dev->ctl_req = kmalloc(sizeof(*(dev->ctl_req)), GFP_KERNEL);
725: if (!dev->ctl_req)
726: goto err_out;
727:
728: /* allocate urb structures */
729: dev->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
730: if (!dev->urb_irq)
731: goto err_out;
732:
733: dev->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
734: if (!dev->urb_ctl)
735: goto err_out;
736:
737: /* get a handle to the interrupt data pipe */
738: pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
739: ret = usb_maxpacket(udev, pipe);
740: if (ret != USB_PKT_LEN)
741: dev_err(&intf->dev, "invalid payload size %d, expected %d\n",
742: ret, USB_PKT_LEN);
743:
744: /* initialise irq urb */
745: usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
746: USB_PKT_LEN,
747: cm109_urb_irq_callback, dev, endpoint->bInterval);
748: dev->urb_irq->transfer_dma = dev->irq_dma;
749: dev->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
750: dev->urb_irq->dev = udev;
751:
752: /* initialise ctl urb */
753: dev->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
754: USB_DIR_OUT;
755: dev->ctl_req->bRequest = USB_REQ_SET_CONFIGURATION;
756: dev->ctl_req->wValue = cpu_to_le16(0x200);
757: dev->ctl_req->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
758: dev->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN);
759:
760: usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
761: (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
762: cm109_urb_ctl_callback, dev);
763: dev->urb_ctl->transfer_dma = dev->ctl_dma;
764: dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
765: dev->urb_ctl->dev = udev;
766:
767: /* find out the physical bus location */
768: usb_make_path(udev, dev->phys, sizeof(dev->phys));
769: strlcat(dev->phys, "/input0", sizeof(dev->phys));
770:
771: /* register settings for the input device */
772: input_dev->name = nfo->name;
773: input_dev->phys = dev->phys;
774: usb_to_input_id(udev, &input_dev->id);
775: input_dev->dev.parent = &intf->dev;
776:
777: input_set_drvdata(input_dev, dev);
778: input_dev->open = cm109_input_open;
779: input_dev->close = cm109_input_close;
780: input_dev->event = cm109_input_ev;
781:
782: input_dev->keycode = dev->keymap;
783: input_dev->keycodesize = sizeof(unsigned char);
784: input_dev->keycodemax = ARRAY_SIZE(dev->keymap);
785:
786: input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_SND);
787: input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
788:
789: /* register available key events */
790: for (i = 0; i < KEYMAP_SIZE; i++) {
791: unsigned short k = keymap(i);
792: dev->keymap[i] = k;
793: __set_bit(k, input_dev->keybit);
794: }
795: __clear_bit(KEY_RESERVED, input_dev->keybit);
796:
797: error = input_register_device(dev->idev);
798: if (error)
799: goto err_out;
800:
801: usb_set_intfdata(intf, dev);
802:
803: return 0;
804:
805: err_out:
806: input_free_device(input_dev);
807: cm109_usb_cleanup(dev);
808: return error;
809: }
SourceFile:drivers/input/misc/cm109.c]
|
| 30/2 |
2026/05/21 10:13 |
llm |
expert |
0m
Model:
Tokens:
input: 44793
output: 51
thoughts: 21
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Analyzing the Callback Function**
Okay, so the callback in question is `cm109_urb_ctl_callback`. Right, let's dive into it. I need to understand its function, its interaction with the USB stack, and potentially, any error handling it's performing. My first question is, what is the context in which it's being invoked? Specifically, is this related to control transfers, bulk transfers, or something else? I also need to ascertain what the `cm109` prefix refers to. Is it device-specific, a vendor prefix, or a module identifier? Understanding the data structures passed to the callback, particularly the `urb` itself, is paramount. Iβll need to dissect the `urb` structure, examining the status field, actual length, and any associated buffers. Furthermore, I will need to understand the error handling approach taken within this function and how it informs the overall control flow of the USB driver. Is there a retry mechanism? Does it signal errors upstream, and how? This will dictate how I go about debugging issues that may be related to this callback.
|
| 31/2 |
2026/05/21 10:13 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_urb_ctl_callback]
Results: map[SourceCode: 434: static void cm109_urb_ctl_callback(struct urb *urb)
435: {
436: struct cm109_dev *dev = urb->context;
437: const int status = urb->status;
438: int error;
439:
440: dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
441: dev->ctl_data->byte[0],
442: dev->ctl_data->byte[1],
443: dev->ctl_data->byte[2],
444: dev->ctl_data->byte[3]);
445:
446: if (status) {
447: if (status == -ESHUTDOWN)
448: return;
449: dev_err_ratelimited(&dev->intf->dev, "%s: urb status %d\n",
450: __func__, status);
451: }
452:
453: guard(spinlock_irqsave)(&dev->ctl_submit_lock);
454:
455: dev->ctl_urb_pending = 0;
456:
457: if (unlikely(dev->shutdown))
458: return;
459:
460: if (dev->buzzer_pending || status) {
461: dev->buzzer_pending = 0;
462: dev->ctl_urb_pending = 1;
463: cm109_submit_buzz_toggle(dev);
464: } else if (likely(!dev->irq_urb_pending)) {
465: /* ask for key data */
466: dev->irq_urb_pending = 1;
467: error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
468: if (error)
469: dev_err(&dev->intf->dev,
470: "%s: usb_submit_urb (urb_irq) failed %d\n",
471: __func__, error);
472: }
473: }
SourceFile:drivers/input/misc/cm109.c]
|
| 32/2 |
2026/05/21 10:13 |
llm |
expert |
0m
Model:
Tokens:
input: 45793
output: 59
thoughts: 375
Thoughts: **Analyzing the cm109 Buzzer Control Logic**
Okay, let's break this down. My initial thought is that `cm109_urb_ctl_callback` seems to be the central point. It clears `dev->ctl_urb_pending`, then conditionally re-sets it to 1 and calls `cm109_submit_buzz_toggle` if `dev->buzzer_pending` is true. This entire process is guarded by `dev->ctl_submit_lock`, which is good. So, the intended behavior should be that `cm109_submit_buzz_toggle` is only ever called when `dev->ctl_urb_pending` is 0 (either initially or within the callback). This should prevent concurrent URB submissions.
However, a potential problem immediately arises: what happens if `usb_submit_urb` *fails* within `cm109_submit_buzz_toggle`? If `usb_submit_urb` fails, then `dev->ctl_urb_pending` remains at 1. Since `cm109_urb_ctl_callback` isn't called on failure, `dev->ctl_urb_pending` is stuck in this state, preventing further attempts. This means `cm109_toggle_buzzer_async` will just set `dev->buzzer_pending` and effectively do nothing on subsequent calls. It won't resubmit the URB, which is a significant issue.
Let me clarify my thoughts on the callback. If the USB submission fails, `cm109_urb_ctl_callback` is not called, so that is safe.
Now, a critical question is whether `cm109_submit_buzz_toggle` is called from *anywhere else* besides `cm109_urb_ctl_callback`. If so, that could introduce concurrency issues. I need to comprehensively audit all callers of `cm109_submit_buzz_toggle` to be absolutely certain of the control flow and avoid a race condition or incorrect state.
|
| 33/2 |
2026/05/21 10:13 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeSnippetLines:0 Name:cm109_submit_buzz_toggle SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cm109_toggle_buzzer_async SourceFile:drivers/input/misc/cm109.c SourceLine:484] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cm109_urb_ctl_callback SourceFile:drivers/input/misc/cm109.c SourceLine:463]] TruncatedOutput:false]
|
| 34/2 |
2026/05/21 10:13 |
llm |
expert |
0m
Model:
Tokens:
input: 46805
output: 49
thoughts: 1102
Thoughts: **Analyzing a Potential URB Double-Submission**
Okay, so I'm focusing on `cm109_toggle_buzzer_async` and `cm109_urb_ctl_callback`. My first thought is: what if `cm109_submit_buzz_toggle` is called and `usb_submit_urb` returns 0, but the URB is somehow already submitted? That seems impossible. Ah, wait, `cm109_urb_ctl_callback` is the completion handler. That's called by the USB core. Is there a race condition? Could `cm109_urb_ctl_callback` be called, clear `dev->ctl_urb_pending`, *then* call `cm109_submit_buzz_toggle`, but the URB somehow still be active? No, the completion handler signals the URB is *no longer* active.
Now I'm thinking, what if `cm109_urb_ctl_callback` submits the URB again, but `usb_submit_urb` fails? If `usb_submit_urb` fails, `dev->ctl_urb_pending` would remain at 1. Wait, what if `dev->buzzer_pending` is 0 but `status` is non-zero, triggering the resubmission? Okay, that's possible. If `status` is non-zero (like `-EPIPE`), it will indeed resubmit! But, if `status` is `-ESHUTDOWN`, it just returns early. If `status` is something like `-EPROTO`, it resubmits. If `usb_submit_urb` fails, it prints an error, and `dev->ctl_urb_pending` remains 1. Then `cm109_toggle_buzzer_async` would set `dev->buzzer_pending = 1`. But, if `usb_submit_urb` fails, the URB is *not* active. `dev->ctl_urb_pending` is still 1, but the URB isn't submitted. So `cm109_toggle_buzzer_async` then sets `dev->buzzer_pending = 1`, but doesn't submit. So this leads to a *hang*, not a double submission.
Alright, what if `cm109_urb_ctl_callback` *succeeds* in submitting the URB and then gets called again, trying to re-submit it? Where is the double submit? Let's check the stack trace... Ah-ha! The stack trace shows it's called from `cm109_toggle_buzzer_async`, not from the callback! So `cm109_toggle_buzzer_async` is calling `cm109_submit_buzz_toggle`. This indicates that `dev->ctl_urb_pending` was 0. But the URB is already in the list! Now, how can `dev->ctl_urb_pending` be 0, yet the URB is still in the list? I need to check `cm109_stop_traffic`.
|
| 35/2 |
2026/05/21 10:14 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_stop_traffic]
Results: map[SourceCode: 510: static void cm109_stop_traffic(struct cm109_dev *dev)
511: {
512: dev->shutdown = 1;
513: /*
514: * Make sure other CPUs see this
515: */
516: smp_wmb();
517:
518: usb_kill_urb(dev->urb_ctl);
519: usb_kill_urb(dev->urb_irq);
520:
521: cm109_toggle_buzzer_sync(dev, 0);
522:
523: dev->shutdown = 0;
524: smp_wmb();
525: }
SourceFile:drivers/input/misc/cm109.c]
|
| 36/2 |
2026/05/21 10:14 |
llm |
expert |
0m
Model:
Tokens:
input: 48876
output: 52
thoughts: 32
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Analyzing the Function Call within the Traffic Stop Procedure**
Right, let me see... I'm looking at `cm109_stop_traffic` and immediately I'm drawn to the fact that it makes a call to `cm109_toggle_buzzer_sync(dev, 0)`. Okay, that's interesting. The way I see it, this call is likely intended to immediately disable the buzzer, since `0` is likely to be a value for it. Which makes sense. It's a synchronized toggle, which likely prevents race conditions or other issues in a multi-threaded or interrupt-driven environment, ensuring that the buzzer is definitely silenced during this stage. I immediately note the implications, and my thoughts start to go down a list.
* `dev` will obviously be the device handle, given the naming convention. That's standard practice, but it's important to be clear on that.
* The `0` argument most probably will turn off the buzzer.
I'm starting to think about what is happening on this stop_traffic call, and what's connected to it. I want to see how this all fits into the broader traffic control logic and how it relates to other parts of the system. I'm noting this call is central to the process.
|
| 37/2 |
2026/05/21 10:14 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_toggle_buzzer_sync]
Results: map[SourceCode: 488: static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
489: {
490: int error;
491:
492: if (on)
493: dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
494: else
495: dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
496:
497: error = usb_control_msg(dev->udev,
498: usb_sndctrlpipe(dev->udev, 0),
499: dev->ctl_req->bRequest,
500: dev->ctl_req->bRequestType,
501: le16_to_cpu(dev->ctl_req->wValue),
502: le16_to_cpu(dev->ctl_req->wIndex),
503: dev->ctl_data,
504: USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
505: if (error < 0 && error != -EINTR)
506: dev_err(&dev->intf->dev, "%s: usb_control_msg() failed %d\n",
507: __func__, error);
508: }
SourceFile:drivers/input/misc/cm109.c]
|
| 38/2 |
2026/05/21 10:14 |
llm |
expert |
0m
Model:
Tokens:
input: 49665
output: 52
thoughts: 689
Thoughts: **Analyzing the Buzzer Toggle and Shutdown Sequence**
Okay, so I'm diving into this `cm109` driver code. First, I noticed `cm109_toggle_buzzer_sync` uses `usb_control_msg` instead of `usb_submit_urb`, which is fine, but I need to understand the implications for synchronization. Now, hang on, `dev->ctl_data` is used by both `urb_ctl` (presumably using `usb_submit_urb`) and the `usb_control_msg` call! But `usb_control_msg` *allocates its own URB*, so it bypasses `dev->urb_ctl`. Okay, that makes sense... but it leads to a potential race condition I'm concerned about.
What if `cm109_submit_buzz_toggle` is called and then `cm109_stop_traffic` is called? `cm109_stop_traffic` calls `usb_kill_urb(dev->urb_ctl)`. `usb_kill_urb` waits for the URB to complete, presumably that initiated with `usb_submit_urb` using `dev->urb_ctl`, correct? Then, *after* that kill completes, `cm109_toggle_buzzer_sync` is called. It then sets `dev->shutdown = 0;`. Okay.
Wait, here's a bigger concern: what if `cm109_input_ev` gets called while `dev->shutdown` is still 1? `cm109_input_ev` calls `cm109_toggle_buzzer_async`. This in turn checks `dev->ctl_urb_pending`. If it's zero, then it submits the URB. Wait a second, the `cm109_stop_traffic` function *doesn't* clear `dev->ctl_urb_pending`! This could be a problem.
Now, if `usb_kill_urb` *is* called, the callback `cm109_urb_ctl_callback` gets called with a status of `-ENOENT`. In that callback, I see:
```c
if (status) {
if (status == -ESHUTDOWN)
return;
```
Ah, but `-ENOENT` isn't `-ESHUTDOWN` from `usb_kill_urb`, so the callback will continue!
Now I see:
```c
guard(spinlock_irqsave)(&dev->ctl_submit_lock);
dev->ctl_urb_pending = 0;
if (unlikely(dev->shutdown))
return;
```
Excellent! If `dev->shutdown` is 1, it *returns*! And `dev->ctl_urb_pending` *is* cleared to 0. So, `cm109_stop_traffic` completes, and it *does* sets `dev->shutdown = 0`. So, if `cm109_input_ev` is called *after* `cm109_stop_traffic`, `dev->ctl_urb_pending` will be 0, and the URB will be submitted. This seems correct. I think I've got it.
But...wait... what if `cm109_input_ev` is called concurrently with `cm109_urb_ctl_callback`? `cm109_input_ev` calls `cm109_toggle_buzzer_async`, which takes `dev->ctl_submit_lock`. And `cm109_urb_ctl_callback` *also* takes `dev->ctl_submit_lock`. Okay, they are serialized by that spinlock, which resolves the potential race condition. Good. I think this code is safe. Now let's move on to checking the `cm109_urb_irq_callback`.
|
| 39/2 |
2026/05/21 10:14 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_urb_irq_callback]
Results: map[SourceCode: 387: /*
388: * IRQ handler
389: */
390: static void cm109_urb_irq_callback(struct urb *urb)
391: {
392: struct cm109_dev *dev = urb->context;
393: const int status = urb->status;
394:
395: dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
396: dev->irq_data->byte[0],
397: dev->irq_data->byte[1],
398: dev->irq_data->byte[2],
399: dev->irq_data->byte[3],
400: dev->keybit);
401:
402: if (status) {
403: if (status == -ESHUTDOWN)
404: return;
405: dev_err_ratelimited(&dev->intf->dev, "%s: urb status %d\n",
406: __func__, status);
407: goto out;
408: }
409:
410: /* Special keys */
411: cm109_report_special(dev);
412:
413: /* Scan key column */
414: if (dev->keybit == 0xf) {
415:
416: /* Any changes ? */
417: if ((dev->gpi & 0xf0) == (dev->irq_data->byte[HID_IR1] & 0xf0))
418: goto out;
419:
420: dev->gpi = dev->irq_data->byte[HID_IR1] & 0xf0;
421: dev->keybit = 0x1;
422: } else {
423: report_key(dev, dev->keymap[dev->irq_data->byte[HID_IR1]]);
424:
425: dev->keybit <<= 1;
426: if (dev->keybit > 0x8)
427: dev->keybit = 0xf;
428: }
429:
430: out:
431: cm109_submit_ctl(dev);
432: }
SourceFile:drivers/input/misc/cm109.c]
|
| 40/2 |
2026/05/21 10:14 |
llm |
expert |
0m
Model:
Tokens:
input: 52008
output: 49
thoughts: 44
Thoughts: Okay, here's my take on those thoughts, framed from my own perspective as someone in the field:
**Diving into the cm109 Driver: Interrupted Flow**
Alright, so the interrupt routine, `cm109_urb_irq_callback`, is triggering a call to `cm109_submit_ctl(dev)`. That's a good place to start digging into the data flow. My immediate thought is, let's trace exactly what happens within `cm109_submit_ctl`. The interrupt is firing, which means *something* has happened with the URB. Now, I need to understand what `cm109_submit_ctl` is *doing* with the data once it's triggered by the interrupt. This is likely the crucial point where control transfers between the hardware and the software, so it's critical to understanding the entire chain of events. Gotta see if it's submitting another URB, processing data, re-initializing, or something else entirely. Let's get to it!
|
| 41/2 |
2026/05/21 10:14 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_submit_ctl]
Results: map[SourceCode: 358: static void cm109_submit_ctl(struct cm109_dev *dev)
359: {
360: int error;
361:
362: guard(spinlock_irqsave)(&dev->ctl_submit_lock);
363:
364: dev->irq_urb_pending = 0;
365:
366: if (unlikely(dev->shutdown))
367: return;
368:
369: if (dev->buzzer_state)
370: dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
371: else
372: dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
373:
374: dev->ctl_data->byte[HID_OR1] = dev->keybit;
375: dev->ctl_data->byte[HID_OR2] = dev->keybit;
376:
377: dev->buzzer_pending = 0;
378: dev->ctl_urb_pending = 1;
379:
380: error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
381: if (error)
382: dev_err(&dev->intf->dev,
383: "%s: usb_submit_urb (urb_ctl) failed %d\n",
384: __func__, error);
385: }
SourceFile:drivers/input/misc/cm109.c]
|
| 42/2 |
2026/05/21 10:14 |
llm |
expert |
0m
Model:
Tokens:
input: 52789
output: 48
thoughts: 1714
Thoughts: **Double USB Submission in CM109 Driver**
Okay, so I've been digging into this CM109 driver, and I've found something fishy. The `cm109_submit_ctl` function is setting `dev->ctl_urb_pending = 1` and then blindly submitting `dev->urb_ctl` using `usb_submit_urb`. The problem is, it *doesn't* check if `dev->ctl_urb_pending` is *already* set before the submission. That's a huge red flag!
I started tracing how this could happen. It's triggered when `dev->urb_irq` completes and calls `cm109_urb_irq_callback`, which then calls `cm109_submit_ctl`. The kicker is, `cm109_toggle_buzzer_async` can also submit `dev->urb_ctl` at *any* time. So, imagine this sequence:
1. `dev->urb_irq` is submitted.
2. `cm109_toggle_buzzer_async` is called. It sets `dev->ctl_urb_pending = 1` and submits `dev->urb_ctl`.
3. *Before* `dev->urb_ctl` completes, `dev->urb_irq` completes.
4. `cm109_urb_irq_callback` calls `cm109_submit_ctl`.
5. `cm109_submit_ctl` grabs the lock, sets `dev->ctl_urb_pending = 1` again (it was *already* 1), and resubmits `dev->urb_ctl`! Double submission.
The typical scenario would be `usb_submit_urb` returns `-EBUSY` because of the `urb->hcpriv` check. However, the bug report shows a `kernel BUG at lib/list_debug.c:35`, suggesting the `urb->hcpriv` check *didn't* catch it. Why not?
Looking at the code, `usb_submit_urb` calls `usb_hcd_submit_urb`, which in the `dummy_hcd` case, calls `dummy_urb_enqueue`. In `dummy_urb_enqueue`, after the `usb_hcd_link_urb_to_ep` call, `urb->hcpriv` *should* be set. If `dummy_urb_enqueue` already has run, `urb->hcpriv` should be set, so the `usb_submit_urb` should return `-EBUSY`.
But if the URB is double submitted, then `usb_hcd_link_urb_to_ep` tries to add the same URB to the same list again, which is very dangerous and triggers the BUG!
However, both `cm109_submit_ctl` and `cm109_toggle_buzzer_async` use `dev->ctl_submit_lock`, so they *shouldn't* run concurrently! How could we get to a point where the lock is released and then reacquired with the same URB?
This means the original `cm109_submit_buzz_toggle` call must have *finished* before the `cm109_urb_irq_callback` is even called, and it *should* set `urb->hcpriv`. What's happening? There must be a scenario when `usb_submit_urb` returns 0, but `urb->hcpriv` is NULL.
I need to revisit the `usb_submit_urb` code and consider what happens on completion, through `usb_hcd_giveback_urb`. There's gotta be something I'm missing here...
|
| 43/2 |
2026/05/21 10:14 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/hcd.c IncludeLines:true Name:usb_hcd_giveback_urb]
Results: map[SourceCode:1714: /**
1715: * usb_hcd_giveback_urb - return URB from HCD to device driver
1716: * @hcd: host controller returning the URB
1717: * @urb: urb being returned to the USB device driver.
1718: * @status: completion status code for the URB.
1719: *
1720: * Context: atomic. The completion callback is invoked either in a work queue
1721: * (BH) context or in the caller's context, depending on whether the HCD_BH
1722: * flag is set in the @hcd structure, except that URBs submitted to the
1723: * root hub always complete in BH context.
1724: *
1725: * This hands the URB from HCD to its USB device driver, using its
1726: * completion function. The HCD has freed all per-urb resources
1727: * (and is done using urb->hcpriv). It also released all HCD locks;
1728: * the device driver won't cause problems if it frees, modifies,
1729: * or resubmits this URB.
1730: *
1731: * If @urb was unlinked, the value of @status will be overridden by
1732: * @urb->unlinked. Erroneous short transfers are detected in case
1733: * the HCD hasn't checked for them.
1734: */
1735: void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
1736: {
1737: struct giveback_urb_bh *bh;
1738: bool running;
1739:
1740: /* pass status to BH via unlinked */
1741: if (likely(!urb->unlinked))
1742: urb->unlinked = status;
1743:
1744: if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) {
1745: __usb_hcd_giveback_urb(urb);
1746: return;
1747: }
1748:
1749: if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe))
1750: bh = &hcd->high_prio_bh;
1751: else
1752: bh = &hcd->low_prio_bh;
1753:
1754: spin_lock(&bh->lock);
1755: list_add_tail(&urb->urb_list, &bh->head);
1756: running = bh->running;
1757: spin_unlock(&bh->lock);
1758:
1759: if (running)
1760: ;
1761: else if (bh->high_prio)
1762: queue_work(system_bh_highpri_wq, &bh->bh);
1763: else
1764: queue_work(system_bh_wq, &bh->bh);
1765: }
SourceFile:drivers/usb/core/hcd.c]
|
| 44/2 |
2026/05/21 10:14 |
llm |
expert |
0m
Model:
Tokens:
input: 56270
output: 57
thoughts: 179
Thoughts: **Analyzing USB Host Controller Driver Behavior**
Okay, so `usb_hcd_giveback_urb` is adding `urb->urb_list` to `bh->head`. Got it. `bh` likely refers to a "bottom half" structure, which seems logical for handling completion events. And that list addition happens under a spinlock, which is expected for thread-safe access.
Aha! Now I remember: `urb->urb_list` is definitely used for the bottom-half queue! This makes perfect sense; the driver is queuing up work to be done later. This means when `dummy_hcd` (the dummy host controller driver) finishes an URB, it's calling `usb_hcd_giveback_urb` to add it to the bottom half queue.
Now, a question is popping up in my head. Does `dummy_hcd` *actually* use `hcd_giveback_urb_in_bh(hcd)` or just set `HCD_BH`? I need to clarify that. Let me quickly examine `dummy_hcd.c` to be certain. I'm going to double check it right away.
|
| 45/2 |
2026/05/21 10:15 |
tool |
codesearch-find-references |
0m
Error: requested entity does not exist
Args: map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c IncludeSnippetLines:0 Name:HCD_BH SourceTreePrefix:]
Results: map[References:<nil> TruncatedOutput:false]
|
| 46/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 56777
output: 50
thoughts: 29
Thoughts: Here's my thought process, summarized as if I were considering the situation myself:
**HCD Flag Investigation**
Okay, so I see `HCD_BH` listed. My first thought is that this is probably a flag of some sort. Let's dig deeper. The next logical step is to check out `hcd_giveback_urb_in_bh`. Understanding the context of how this function interacts with that particular flag will likely shed light on the overall control flow and the *meaning* of the `HCD_BH` setting. I need to get a clear picture of what this flag actually signals. Understanding its state and how it's handled is key.
|
| 47/2 |
2026/05/21 10:15 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/hcd.c IncludeLines:true Name:hcd_giveback_urb_in_bh]
Results: map[SourceCode: 409: static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
410: {
411: return hcd->driver->flags & HCD_BH;
412: }
SourceFile:include/linux/usb/hcd.h]
|
| 48/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 57098
output: 57
thoughts: 13
Thoughts: Here's my take on those thoughts, tailored for an expert audience:
**Analyzing the `dummy_hcd` Driver Flags**
Okay, so the first thing on my mind is diving into the `dummy_hcd` driver. I need to get a clear picture of how it's configured. Specifically, I'm thinking about the driver flags. Knowing the current settings is absolutely fundamental to understanding its behavior and how it's interacting with the host controller. Are we dealing with any unusual configurations here? Are there any obvious red flags jumping out at me right away? This is the starting point for really digging into this driver; the flags hold the keys to its current operating state. Let's see what those flags are currently set to.
|
| 49/2 |
2026/05/21 10:15 |
tool |
codesearch-find-references |
0m
Error: requested entity does not exist
Args: map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c IncludeSnippetLines:2 Name:HCD_BH SourceTreePrefix:]
Results: map[References:<nil> TruncatedOutput:false]
|
| 50/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 57344
output: 49
thoughts: 68
Thoughts: Here's my summary, as the expert:
**HCD Interaction Oversight**
Okay, so I'm digging into this HCD code, and something's not quite right. My initial thought was that `dummy_hcd` wasn't explicitly setting `HCD_BH`, which felt odd. Then, I see `hcd_giveback_urb_in_bh` returns false. That means the intended behavior for post-completion handling isn't active. Which, in turn, suggests a direct call from `usb_hcd_giveback_urb` to `__usb_hcd_giveback_urb(urb)`. So, the URB is given back directly, bypassing the regular bottom half execution path. This is important because it changes the timing and context of the urb completion. Now, I have to figure out if that is the correct behavior for this platform.
|
| 51/2 |
2026/05/21 10:15 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/hcd.c IncludeLines:true Name:__usb_hcd_giveback_urb]
Results: map[SourceCode:1634: static void __usb_hcd_giveback_urb(struct urb *urb)
1635: {
1636: struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
1637: struct usb_anchor *anchor = urb->anchor;
1638: int status = urb->unlinked;
1639:
1640: urb->hcpriv = NULL;
1641: if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
1642: urb->actual_length < urb->transfer_buffer_length &&
1643: !status))
1644: status = -EREMOTEIO;
1645:
1646: unmap_urb_for_dma(hcd, urb);
1647: usbmon_urb_complete(&hcd->self, urb, status);
1648: usb_anchor_suspend_wakeups(anchor);
1649: usb_unanchor_urb(urb);
1650: if (likely(status == 0))
1651: usb_led_activity(USB_LED_EVENT_HOST);
1652:
1653: /* pass ownership to the completion handler */
1654: urb->status = status;
1655: /*
1656: * This function can be called in task context inside another remote
1657: * coverage collection section, but kcov doesn't support that kind of
1658: * recursion yet. Only collect coverage in softirq context for now.
1659: */
1660: kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum);
1661: urb->complete(urb);
1662: kcov_remote_stop_softirq();
1663:
1664: usb_anchor_resume_wakeups(anchor);
1665: atomic_dec(&urb->use_count);
1666: /*
1667: * Order the write of urb->use_count above before the read
1668: * of urb->reject below. Pairs with the memory barriers in
1669: * usb_kill_urb() and usb_poison_urb().
1670: */
1671: smp_mb__after_atomic();
1672:
1673: if (unlikely(atomic_read(&urb->reject)))
1674: wake_up(&usb_kill_urb_queue);
1675: usb_put_urb(urb);
1676: }
SourceFile:drivers/usb/core/hcd.c]
|
| 52/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 58383
output: 51
thoughts: 408
Thoughts: **Debugging a USB Control Transfer Issue**
Okay, so I'm diving into this USB driver code, and I've stumbled upon something interesting. It looks like the `__usb_hcd_giveback_urb` function is setting `urb->hcpriv` to `NULL` *before* calling the URB's completion callback, which in this case is either `cm109_urb_ctl_callback` or `cm109_urb_irq_callback`. This is crucial because it means that inside those callbacks, `urb->hcpriv` will be `NULL`.
Now, if `cm109_urb_irq_callback` is called, it eventually calls `cm109_submit_ctl`, which then calls `usb_submit_urb(dev->urb_ctl)`. Here's where it gets potentially tricky: If `dev->urb_ctl` is still active β meaning it was submitted previously (say, by `cm109_toggle_buzzer_async`) and hasn't finished yet β its `urb->hcpriv` *shouldn't* be `NULL`. It should still be set by the HCD. So, when `usb_submit_urb(dev->urb_ctl)` is called, it should, in theory, fail with an `-EBUSY` error because `urb->hcpriv` is already set.
But here's the mystery. It seems like it *isn't* failing. The question now is: Why didn't `usb_submit_urb` catch this? Let me look at the code for that function again. Ah, here it is:
```c
if (urb->hcpriv) {
WARN_ONCE(1, "URB %p submitted while active\n", urb);
return -EBUSY;
}
```
Okay, so the check *is* there. It clearly should have returned `-EBUSY` if `urb->hcpriv` was not NULL. Given what I'm seeing, there's a disconnect. If `dev->urb_ctl` is active, the HCD should have set `urb->hcpriv`.
The next possibility I can think of is whether it's possible that `dev->urb_ctl` *isn't* technically active (i.e. is not currently being processed), but it is still attached to the HCD or in some sort of list. When an URB completes, it appears that `dummy_hcd` calls `usb_hcd_unlink_urb_from_ep`. That is where I need to focus next.
|
| 53/2 |
2026/05/21 10:15 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/hcd.c IncludeLines:true Name:usb_hcd_unlink_urb_from_ep]
Results: map[SourceCode:1211: /**
1212: * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
1213: * @hcd: host controller to which @urb was submitted
1214: * @urb: URB being unlinked
1215: *
1216: * Host controller drivers should call this routine before calling
1217: * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
1218: * interrupts must be disabled. The actions carried out here are required
1219: * for URB completion.
1220: */
1221: void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
1222: {
1223: /* clear all state linking urb to this dev (and hcd) */
1224: spin_lock(&hcd_urb_list_lock);
1225: list_del_init(&urb->urb_list);
1226: spin_unlock(&hcd_urb_list_lock);
1227: }
SourceFile:drivers/usb/core/hcd.c]
|
| 54/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 59751
output: 18
thoughts: 134
Thoughts: **Analyzing the USB URB Flow**
Okay, so I'm tracing through this USB Universal Resource Block (URB) handling, and it seems like we have a clear sequence here. The `urb->urb_list` is first unlinked from `ep->urb_list` and then initialized. Makes sense, that's standard practice. Then, `usb_hcd_giveback_urb` gets called. Now, here's where it gets interesting. If `hcd_giveback_urb_in_bh` is true, *that* function apparently adds `urb->urb_list` to `bh->head`. Right, the bottom half processing.
But hold on a second⦠I'm pretty sure `dummy_hcd` *doesn't* actually set `HCD_BH`! It should be using the workqueue if it's following the rules. But I need to double-check that. Wait, maybe my assumption is wrong. I need to make sure I am thinking of the *right* `dummy_hcd` instance here. I'm going to quickly re-examine `dummy_hcd.c` to make sure I haven't missed something. I need to be sure that the bottom half is not actually being scheduled here.
|
| 55/2 |
2026/05/21 10:15 |
tool |
grepper |
0m
Args:
Results: map[Output:drivers/usb/core/hcd.c=1678=static void usb_giveback_urb_bh(struct work_struct *work)
--
drivers/usb/core/hcd.c-1720- * Context: atomic. The completion callback is invoked either in a work queue
drivers/usb/core/hcd.c:1721: * (BH) context or in the caller's context, depending on whether the HCD_BH
drivers/usb/core/hcd.c-1722- * flag is set in the @hcd structure, except that URBs submitted to the
--
drivers/usb/dwc2/hcd.c=4991=static struct hc_driver dwc2_hc_driver = {
--
drivers/usb/dwc2/hcd.c-4996- .irq = _dwc2_hcd_irq,
drivers/usb/dwc2/hcd.c:4997: .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
drivers/usb/dwc2/hcd.c-4998-
--
drivers/usb/dwc2/hcd_queue.c=1181=static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
--
drivers/usb/dwc2/hcd_queue.c-1208- * "Reserved Bandwidth Transfers"), we need to keep a reservation active as
drivers/usb/dwc2/hcd_queue.c:1209: * long as a device driver keeps submitting. Since we're using HCD_BH to give
drivers/usb/dwc2/hcd_queue.c-1210- * back the URB we need to give the driver a little bit of time before we
--
drivers/usb/host/ehci-grlib.c=24=static const struct hc_driver ehci_grlib_hc_driver = {
--
drivers/usb/host/ehci-grlib.c-32- .irq = ehci_irq,
drivers/usb/host/ehci-grlib.c:33: .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
drivers/usb/host/ehci-grlib.c-34-
--
drivers/usb/host/ehci-hcd.c=1239=static const struct hc_driver ehci_hc_driver = {
--
drivers/usb/host/ehci-hcd.c-1247- .irq = ehci_irq,
drivers/usb/host/ehci-hcd.c:1248: .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
drivers/usb/host/ehci-hcd.c-1249-
--
drivers/usb/host/ehci-ppc-of.c=25=static const struct hc_driver ehci_ppc_of_hc_driver = {
--
drivers/usb/host/ehci-ppc-of.c-33- .irq = ehci_irq,
drivers/usb/host/ehci-ppc-of.c:34: .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
drivers/usb/host/ehci-ppc-of.c-35-
--
drivers/usb/host/ehci-ps3.c=57=static const struct hc_driver ps3_ehci_hc_driver = {
--
drivers/usb/host/ehci-ps3.c-61- .irq = ehci_irq,
drivers/usb/host/ehci-ps3.c:62: .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
drivers/usb/host/ehci-ps3.c-63- .reset = ps3_ehci_hc_reset,
--
drivers/usb/host/ehci-sh.c=26=static const struct hc_driver ehci_sh_hc_driver = {
--
drivers/usb/host/ehci-sh.c-34- .irq = ehci_irq,
drivers/usb/host/ehci-sh.c:35: .flags = HCD_USB2 | HCD_DMA | HCD_MEMORY | HCD_BH,
drivers/usb/host/ehci-sh.c-36-
--
drivers/usb/host/ehci-xilinx-of.c=60=static const struct hc_driver ehci_xilinx_of_hc_driver = {
--
drivers/usb/host/ehci-xilinx-of.c-68- .irq = ehci_irq,
drivers/usb/host/ehci-xilinx-of.c:69: .flags = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
drivers/usb/host/ehci-xilinx-of.c-70-
--
drivers/usb/host/xhci.c=5555=static const struct hc_driver xhci_hc_driver = {
--
drivers/usb/host/xhci.c-5564- .flags = HCD_MEMORY | HCD_DMA | HCD_USB3 | HCD_SHARED |
drivers/usb/host/xhci.c:5565: HCD_BH,
drivers/usb/host/xhci.c-5566-
--
include/linux/usb/hcd.h=237=struct hc_driver {
--
include/linux/usb/hcd.h-254-#define HCD_MASK 0x0070
include/linux/usb/hcd.h:255:#define HCD_BH 0x0100 /* URB complete in BH context */
include/linux/usb/hcd.h-256-
--
include/linux/usb/hcd.h=409=static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
include/linux/usb/hcd.h-410-{
include/linux/usb/hcd.h:411: return hcd->driver->flags & HCD_BH;
include/linux/usb/hcd.h-412-}
]
|
| 56/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 61789
output: 52
thoughts: 1063
Thoughts: **Analyzing a Race Condition in USB URB Submission**
Okay, let's break this down. I'm seeing a potential race condition and need to understand the control flow and why the check I made is failing. The goal is to track down how a double list_add is happening in `usb_hcd_link_urb_to_ep`.
First, I observe that `dummy_hcd` doesn't set `HCD_BH`. This is key. Therefore, `hcd_giveback_urb_in_bh` returns false. So, if `!hcd_giveback_urb_in_bh(hcd)` evaluates to true, the code proceeds down a certain path. The check `is_root_hub(urb->dev)` evaluates if the device is a root hub. In this case, it's NOT a root hub, specifically a `cm109` device, so `!is_root_hub(urb->dev)` is true. Therefore, the combined condition is true, and the code calls `__usb_hcd_giveback_urb(urb)`.
`__usb_hcd_giveback_urb` will set `urb->hcpriv = NULL;` and invokes `urb->complete(urb);`. The `cm109_urb_irq_callback` is then called and submits the control transfer URB via `cm109_submit_ctl`. The `cm109_submit_ctl` function calls `usb_submit_urb(dev->urb_ctl)`.
Here's the problem: The original URB, `dev->urb_ctl` is *already* active from a prior `cm109_toggle_buzzer_async` call. This means `urb->hcpriv` should NOT be NULL. `usb_submit_urb` has a check for this, which should return `-EBUSY`, preventing submission. The `WARN_ONCE` should also fire. So, why isn't this happening? Why doesn't it return -EBUSY?
Looking back at `usb_submit_urb`, the code checks `urb->hcpriv`. If it's *not* NULL, then `-EBUSY` should be returned. But if it IS NULL, the function believes the URB can be submitted. So, why would this check pass if `dev->urb_ctl` is already submitted?
I need to understand what state the URB is in during these calls. If the check passes, `urb->hcpriv` *must* be NULL. But if `urb->hcpriv` is NULL, that means it's NOT active, and so I should not get a crash at `usb_hcd_link_urb_to_ep`.
Now, if `urb->hcpriv` is NULL, then the URB is NOT active. But if the URB is NOT active, how can the `usb_hcd_link_urb_to_ep` crash with a double list_add? Because `urb->urb_list` is already in a list!
Then, I went back to `dummy_urb_enqueue` to see how hcpriv is actually set. Ah! The critical point. `urb->hcpriv` is set *AFTER* the call to `usb_hcd_link_urb_to_ep`. This explains it. If `usb_submit_urb` is called on the SAME URB concurrently, both threads will see `urb->hcpriv == NULL` *before* the assignment. Each thread submits the URB. This means both will call `usb_hcd_submit_urb`. Both threads will call `dummy_urb_enqueue`. Thread 1 calls `usb_hcd_link_urb_to_ep`, which adds `urb->urb_list` to the list. Thread 2 *also* calls `usb_hcd_link_urb_to_ep`, trying to add the already-added list entry again! This is the double list_add.
However, I've got to revisit the locking. Both `cm109_submit_ctl` and `cm109_toggle_buzzer_async` take `dev->ctl_submit_lock`. If this is true, then they CANNOT run concurrently. If they cannot run concurrently, how can the race condition exist, meaning the double list add is impossible?
|
| 57/2 |
2026/05/21 10:15 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_toggle_buzzer_async]
Results: map[SourceCode: 475: static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
476: {
477: guard(spinlock_irqsave)(&dev->ctl_submit_lock);
478:
479: if (dev->ctl_urb_pending) {
480: /* URB completion will resubmit */
481: dev->buzzer_pending = 1;
482: } else {
483: dev->ctl_urb_pending = 1;
484: cm109_submit_buzz_toggle(dev);
485: }
486: }
SourceFile:drivers/input/misc/cm109.c]
|
| 58/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 64075
output: 49
thoughts: 25
Thoughts: Okay, here's my understanding, written as if it were my own thought process, assuming I'm an expert in this embedded systems area:
**Analyzing the Locking Mechanism of `cm109_toggle_buzzer_async`**
Right, so I'm digging into the locking mechanisms again. Specifically, I'm focusing on `cm109_toggle_buzzer_async`. The crucial point here is that this function *does* grab and use `dev->ctl_submit_lock`. That confirms my initial suspicion, and it's important to keep this fact front of mind as I proceed with the analysis. This lock clearly suggests it's designed to synchronize access to some shared control or submission resources related to that buzzer toggling functionality. Understanding precisely how `dev` is being handled is what I'll need to focus on next. I'll need to consider what level of contention that lock causes and if there are any potential bottlenecks related to it. I wonder if it could be a source of latency if other tasks also compete for the same resource. I'll need to review the entire control flow surrounding `cm109_toggle_buzzer_async` in order to figure out all the implications of this locking behavior.
|
| 59/2 |
2026/05/21 10:15 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_submit_ctl]
Results: map[SourceCode: 358: static void cm109_submit_ctl(struct cm109_dev *dev)
359: {
360: int error;
361:
362: guard(spinlock_irqsave)(&dev->ctl_submit_lock);
363:
364: dev->irq_urb_pending = 0;
365:
366: if (unlikely(dev->shutdown))
367: return;
368:
369: if (dev->buzzer_state)
370: dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
371: else
372: dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
373:
374: dev->ctl_data->byte[HID_OR1] = dev->keybit;
375: dev->ctl_data->byte[HID_OR2] = dev->keybit;
376:
377: dev->buzzer_pending = 0;
378: dev->ctl_urb_pending = 1;
379:
380: error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
381: if (error)
382: dev_err(&dev->intf->dev,
383: "%s: usb_submit_urb (urb_ctl) failed %d\n",
384: __func__, error);
385: }
SourceFile:drivers/input/misc/cm109.c]
|
| 60/2 |
2026/05/21 10:15 |
llm |
expert |
0m
Model:
Tokens:
input: 64874
output: 59
thoughts: 89
Thoughts: Okay, let me think this through.
**Analyzing Concurrent USB Submissions**
Right, so `cm109_submit_ctl` also grabs `dev->ctl_submit_lock`. That's important. It means those two functions *cannot* run at the same time. They're serialized by that lock. If they aren't concurrent with each other, how could `usb_submit_urb` possibly be called concurrently, especially since they both call `usb_submit_urb`? That makes no sense. Hold on... is there *any* other place that calls `usb_submit_urb` with the `dev->urb_ctl` urb? I need to be absolutely certain of this. I should probably quickly check for all references to `dev->urb_ctl` in the code, just to make absolutely sure. I need to be sure about this assumption.
|
| 61/2 |
2026/05/21 10:16 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeSnippetLines:2 Name:cm109_dev::urb_ctl SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_input_open SourceFile:drivers/input/misc/cm109.c SourceLine:566 SourceSnippet: 564:
565: dev->ctl_urb_pending = 1;
566: error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
567: if (!error) {
568: dev->open = 1;
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_stop_traffic SourceFile:drivers/input/misc/cm109.c SourceLine:518 SourceSnippet: 516: smp_wmb();
517:
518: usb_kill_urb(dev->urb_ctl);
519: usb_kill_urb(dev->urb_irq);
520:
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_submit_buzz_toggle SourceFile:drivers/input/misc/cm109.c SourceLine:351 SourceSnippet: 349: dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
350:
351: error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
352: if (error)
353: dev_err(&dev->intf->dev,
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_submit_ctl SourceFile:drivers/input/misc/cm109.c SourceLine:380 SourceSnippet: 378: dev->ctl_urb_pending = 1;
379:
380: error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
381: if (error)
382: dev_err(&dev->intf->dev,
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_cleanup SourceFile:drivers/input/misc/cm109.c SourceLine:664 SourceSnippet: 662:
663: usb_free_urb(dev->urb_irq); /* parameter validation in core/urb */
664: usb_free_urb(dev->urb_ctl); /* parameter validation in core/urb */
665: kfree(dev);
666: }
] map[ReferenceKind:writes ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:733 SourceSnippet: 731: goto err_out;
732:
733: dev->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
734: if (!dev->urb_ctl)
735: goto err_out;
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:734 SourceSnippet: 732:
733: dev->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
734: if (!dev->urb_ctl)
735: goto err_out;
736:
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:760 SourceSnippet: 758: dev->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN);
759:
760: usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
761: (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
762: cm109_urb_ctl_callback, dev);
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:763 SourceSnippet: 761: (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
762: cm109_urb_ctl_callback, dev);
763: dev->urb_ctl->transfer_dma = dev->ctl_dma;
764: dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
765: dev->urb_ctl->dev = udev;
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:764 SourceSnippet: 762: cm109_urb_ctl_callback, dev);
763: dev->urb_ctl->transfer_dma = dev->ctl_dma;
764: dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
765: dev->urb_ctl->dev = udev;
766:
] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:cm109_usb_probe SourceFile:drivers/input/misc/cm109.c SourceLine:765 SourceSnippet: 763: dev->urb_ctl->transfer_dma = dev->ctl_dma;
764: dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
765: dev->urb_ctl->dev = udev;
766:
767: /* find out the physical bus location */
]] TruncatedOutput:false]
|
| 62/2 |
2026/05/21 10:16 |
llm |
expert |
0m
Model:
Tokens:
input: 66893
output: 49
thoughts: 47
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm well-versed in kernel USB driver development.
**Analyzing the USB Control Transfer Submission**
Right, so `cm109_input_open` is the entry point, and it's calling `usb_submit_urb(dev->urb_ctl, GFP_KERNEL);`. The critical thing here is the `usb_submit_urb` function. It's the standard way to send a USB Request Block (URB) to the USB host controller. The `dev->urb_ctl` likely refers to a control URB, since we are calling it from an open function and that's usually where you'd set up control transfers for the device. The `GFP_KERNEL` argument indicates that this memory allocation is happening in kernel context and we're okay with blocking. Given that's the point we're at, it makes perfect sense to check out the details of `cm109_input_open` and determine what it's actually doing with this URB. I need to understand what this control URB is doing; is it configuring the device? Checking device status? What data is being sent or received? That function's definition will give me the essential clues.
|
| 63/2 |
2026/05/21 10:16 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_input_open]
Results: map[SourceCode: 542: static int cm109_input_open(struct input_dev *idev)
543: {
544: struct cm109_dev *dev = input_get_drvdata(idev);
545: int error;
546:
547: error = usb_autopm_get_interface(dev->intf);
548: if (error < 0) {
549: dev_err(&idev->dev, "%s - cannot autoresume, result %d\n",
550: __func__, error);
551: return error;
552: }
553:
554: scoped_guard(mutex, &dev->pm_mutex) {
555: dev->buzzer_state = 0;
556: dev->key_code = -1; /* no keys pressed */
557: dev->keybit = 0xf;
558:
559: /* issue INIT */
560: dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF;
561: dev->ctl_data->byte[HID_OR1] = dev->keybit;
562: dev->ctl_data->byte[HID_OR2] = dev->keybit;
563: dev->ctl_data->byte[HID_OR3] = 0x00;
564:
565: dev->ctl_urb_pending = 1;
566: error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
567: if (!error) {
568: dev->open = 1;
569: return 0;
570: }
571: }
572:
573: dev->ctl_urb_pending = 0;
574: usb_autopm_put_interface(dev->intf);
575:
576: dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n",
577: __func__, error);
578:
579: return error;
580: }
SourceFile:drivers/input/misc/cm109.c]
|
| 64/2 |
2026/05/21 10:16 |
llm |
expert |
0m
Model:
Tokens:
input: 67907
output: 41
thoughts: 727
Thoughts: **Race Condition Analysis in CM109 Driver**
Okay, so here's what's rattling around in my head. I'm looking at this `cm109` driver code and I've spotted a potential race condition. Specifically, I'm focusing on the interaction between `cm109_input_open` and `cm109_input_ev`. I see that `cm109_input_open` sets `dev->ctl_urb_pending = 1` and then immediately submits a USB URB with `usb_submit_urb(dev->urb_ctl, GFP_KERNEL)`. The key thing I'm noticing is that it *doesn't* take `dev->ctl_submit_lock` before doing all that.
Now, if `cm109_input_ev` gets called concurrently with `cm109_input_open`, we have a problem. `cm109_input_ev` calls `cm109_toggle_buzzer_async`, which *does* take that `dev->ctl_submit_lock`. Crucially, it checks `dev->ctl_urb_pending`. Here's the scenario: if `cm109_input_open` has set `dev->ctl_urb_pending = 1` but hasn't yet gotten around to submitting the URB with `usb_submit_urb`, then `cm109_toggle_buzzer_async` will see `dev->ctl_urb_pending == 1` and just set `dev->buzzer_pending = 1`. No big deal.
However, if `cm109_input_open` hasn't set `dev->ctl_urb_pending = 1` yet, then `cm109_toggle_buzzer_async` *will* set it to 1 and submit the URB itself! Then, `cm109_input_open` *also* sets `dev->ctl_urb_pending = 1` and calls `usb_submit_urb` AGAIN! That's it!
That's the race! The fact that `cm109_input_open` doesn't hold `dev->ctl_submit_lock` means these two functions can run concurrently and they both end up trying to call `usb_submit_urb(dev->urb_ctl)`. And I think that's why we're seeing this "double list_add" issue.
Now, I need to verify that `cm109_input_ev` actually *can* be called at the same time as `cm109_input_open`. Let's look at how the reproducer works. I see it opens `/dev/tty1` and writes to it. Writing to `/dev/tty1` triggers `kd_mksound`, which, in turn, calls `input_inject_event`. That calls `cm109_input_ev`, right? Okay, so that should establish the concurrent calls.
But wait. How is it injecting these events? `cm109_input_open` is called on the open event on the input device itself. Is the input device opened when `/dev/tty1` is opened? No, that's wrong. `kd_mksound` is injecting events into ALL input devices, that have `SND_BELL` or `SND_TONE`. This is the key. And, oh, now I see it. `input_inject_event` does *not* require the input device to be open! That's it. It's just iterating through all the handles with `input_handler_for_each_handle`, and the reproducer gets it. Okay, that confirms the race! We need to examine `input_inject_event`.
|
| 65/2 |
2026/05/21 10:16 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/input.c IncludeLines:true Name:input_inject_event]
Results: map[SourceCode: 401: /**
402: * input_inject_event() - send input event from input handler
403: * @handle: input handle to send event through
404: * @type: type of the event
405: * @code: event code
406: * @value: value of the event
407: *
408: * Similar to input_event() but will ignore event if device is
409: * "grabbed" and handle injecting event is not the one that owns
410: * the device.
411: */
412: void input_inject_event(struct input_handle *handle,
413: unsigned int type, unsigned int code, int value)
414: {
415: struct input_dev *dev = handle->dev;
416: struct input_handle *grab;
417:
418: if (is_event_supported(type, dev->evbit, EV_MAX)) {
419: guard(spinlock_irqsave)(&dev->event_lock);
420: guard(rcu)();
421:
422: grab = rcu_dereference(dev->grab);
423: if (!grab || grab == handle)
424: input_handle_event(dev, type, code, value);
425:
426: }
427: }
SourceFile:drivers/input/input.c]
|
| 66/2 |
2026/05/21 10:16 |
llm |
expert |
0m
Model:
Tokens:
input: 69921
output: 41
thoughts: 123
Thoughts: **Analyzing the Input Event Flow**
Okay, so I'm tracing how these input events are handled. It looks like `input_inject_event` kicks things off, and that, in turn, calls `input_handle_event`. From there, we hit `dev->event(dev, type, code, value)`. This goes specifically to `cm109_input_ev`, which is the correct handler for this device.
Now, I need to understand the relationship between this and the device state. Does `input_inject_event` *require* the underlying device to be opened? No, that doesn't seem to be the case. It appears to just need a valid handle.
Hmm, this is interesting... Let me think about `kd_mksound`. Now, I remember that uses `kbd_handler`. The puzzle piece is connecting: When a new input device is registered, `kbd_connect` gets called. And what does `kbd_connect` *do*? Ah, it creates a handle *and* it OPENS the input device! So, the device is already open at the time events are processed.
I should probably confirm that with the `kbd_connect` code. Let's take a look.
|
| 67/2 |
2026/05/21 10:16 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/vt/keyboard.c IncludeLines:true Name:kbd_connect]
Results: map[SourceCode:1540: /*
1541: * When a keyboard (or other input device) is found, the kbd_connect
1542: * function is called. The function then looks at the device, and if it
1543: * likes it, it can open it and get events from it. In this (kbd_connect)
1544: * function, we should decide which VT to bind that keyboard to initially.
1545: */
1546: static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
1547: const struct input_device_id *id)
1548: {
1549: int error;
1550:
1551: struct input_handle __free(kfree) *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
1552: if (!handle)
1553: return -ENOMEM;
1554:
1555: handle->dev = dev;
1556: handle->handler = handler;
1557: handle->name = "kbd";
1558:
1559: error = input_register_handle(handle);
1560: if (error)
1561: return error;
1562:
1563: error = input_open_device(handle);
1564: if (error)
1565: goto err_unregister_handle;
1566:
1567: retain_and_null_ptr(handle);
1568:
1569: return 0;
1570:
1571: err_unregister_handle:
1572: input_unregister_handle(handle);
1573: return error;
1574: }
SourceFile:drivers/tty/vt/keyboard.c]
|
| 68/2 |
2026/05/21 10:16 |
llm |
expert |
0m
Model:
Tokens:
input: 70855
output: 41
thoughts: 256
Thoughts: **My Analysis of the CM109 USB Driver Initialization**
Okay, so I've traced the flow here. It looks like `kbd_connect` is crucial. Specifically, `kbd_connect` calls `input_open_device` which in turn calls the device-specific open function, in this case, `cm109_input_open`. Alright, that makes sense.
Wait, let's step back a moment. `input_open_device` is actually triggered within `kbd_connect`. And where does *that* fit in? Ah, `kbd_connect` is called during the `input_register_device` process. Bingo.
So, since `kbd_connect` calls `input_open_device` and `kbd_connect` is invoked by `input_register_device` that means `cm109_input_open` is indirectly called by `input_register_device`. Good.
Now, where does *that* fit in? Got it. `input_register_device` is called during `cm109_usb_probe`. Okay, so `cm109_input_open` is ultimately invoked from `cm109_usb_probe`.
Now the interesting part. The reproducer writes to `/dev/tty1`, which then triggers `kd_mksound`. This thing iterates through all handles and calls `input_inject_event`. My question is, at what point does it do this? If `kbd_connect` has registered the handle, but hasn't completed or is in the middle of `input_open_device` when the reproducer fires up, can `kd_mksound` potentially find the handle and call `input_inject_event` at an inopportune time?
I need to look closer at `input_register_handle` to be sure.
|
| 69/2 |
2026/05/21 10:16 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/input.c IncludeLines:true Name:input_register_handle]
Results: map[SourceCode:2598: /**
2599: * input_register_handle - register a new input handle
2600: * @handle: handle to register
2601: *
2602: * This function puts a new input handle onto device's
2603: * and handler's lists so that events can flow through
2604: * it once it is opened using input_open_device().
2605: *
2606: * This function is supposed to be called from handler's
2607: * connect() method.
2608: */
2609: int input_register_handle(struct input_handle *handle)
2610: {
2611: struct input_handler *handler = handle->handler;
2612: struct input_dev *dev = handle->dev;
2613:
2614: input_handle_setup_event_handler(handle);
2615: /*
2616: * We take dev->mutex here to prevent race with
2617: * input_release_device().
2618: */
2619: scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
2620: /*
2621: * Filters go to the head of the list, normal handlers
2622: * to the tail.
2623: */
2624: if (handler->filter)
2625: list_add_rcu(&handle->d_node, &dev->h_list);
2626: else
2627: list_add_tail_rcu(&handle->d_node, &dev->h_list);
2628: }
2629:
2630: /*
2631: * Since we are supposed to be called from ->connect()
2632: * which is mutually exclusive with ->disconnect()
2633: * we can't be racing with input_unregister_handle()
2634: * and so separate lock is not needed here.
2635: */
2636: list_add_tail_rcu(&handle->h_node, &handler->h_list);
2637:
2638: if (handler->start)
2639: handler->start(handle);
2640:
2641: return 0;
2642: }
SourceFile:drivers/input/input.c]
|
| 70/2 |
2026/05/21 10:16 |
llm |
expert |
0m
Model:
Tokens:
input: 72214
output: 45
thoughts: 3302
Thoughts: **Analyzing the C-Media CM109 USB Driver Race Condition**
Okay, so here's the breakdown of this bug and what's racing in the `cm109` driver. `input_register_handle` is the crucial first step. It adds a handle to `handler->h_list`. Then, `kbd_connect` goes on to call `input_open_device(handle)`. Simultaneously, `kd_mksound` is going to call `input_handler_for_each_handle(&kbd_handler, ...)`.
`input_handler_for_each_handle` is where the action happens; it iterates over `handler->h_list`. This means that `kd_mksound` *can* find the handle before `input_open_device` is called, or while it is running. Specifically, if `kd_mksound` finds the handle while `cm109_input_open` is in progress, it'll jump in to call `input_inject_event`, which subsequently calls `cm109_input_ev`, which will call `cm109_toggle_buzzer_async`.
`cm109_toggle_buzzer_async` takes `dev->ctl_submit_lock`. Crucially, `cm109_input_open` *doesn't* take that same lock. So, they can run concurrently, which is where the race comes in. `cm109_input_open` sets `dev->ctl_urb_pending = 1` and then calls `usb_submit_urb(dev->urb_ctl)`.
Meanwhile, `cm109_toggle_buzzer_async` checks `dev->ctl_urb_pending`. If it is `0`, it sets it to `1` and then calls `cm109_submit_buzz_toggle`, which in turn, calls `usb_submit_urb(dev->urb_ctl)`.
Here's the critical timing. If `cm109_toggle_buzzer_async` runs *just* before `cm109_input_open` sets `dev->ctl_urb_pending = 1`, it will see that the value is `0`. It'll set it to `1` and then call `usb_submit_urb`. Then, `cm109_input_open` will also set `dev->ctl_urb_pending = 1` and also call `usb_submit_urb` again! This creates a *double submit* of `dev->urb_ctl`!
Now, the vulnerability. `usb_submit_urb` checks `urb->hcpriv` without any locking, and `dummy_hcd` sets `urb->hcpriv` *after* adding it to the list. That means that both threads can pass the check and call `dummy_urb_enqueue`. This calls `usb_hcd_link_urb_to_ep`, which will cause a double `list_add`! That's the root of the list corruption.
This is a classic race condition. The bug is definitely exploitable because this double `list_add` corrupts the `urb_list` in the endpoint. List corruption is a classic memory corruption bug, usually leading to arbitrary write or use-after-free conditions. However, the system might catch it with `__list_add_valid_or_report`, which would trigger a `BUG()`. Unfortunately, in production builds, we usually don't enable `CONFIG_DEBUG_LIST`. If that's the case, then it will just corrupt the list.
Now, a critical question: Can an unprivileged user trigger this? The reproducer uses `syz_usb_connect`, which in turn uses `/dev/raw-gadget` or similar USB gadget injection capabilities. Normally, this is only accessible to root. The key is to think if a *malicious USB device* can trigger it.
Yes, a malicious USB device *can* present itself as a `cm109` device. When it's plugged in, `cm109_usb_probe` will be called. During the probe, `input_register_device` will be called which leads to `kbd_connect`. If the attacker can also trigger `kd_mksound` simultaneously (e.g., by writing a bell character to the terminal), the race can be triggered!
Now, the next question: Is it possible for an unprivileged user to write to `/dev/tty1` or trigger a bell? Yes, anyone can print a bell character `\a` to their terminal, which can potentially trigger `kd_mksound` if the terminal is a VT. So, a physically present attacker plugging in a
|
| 71/2 |
2026/05/21 10:17 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/host/xhci.c IncludeLines:true Name:xhci_urb_enqueue]
Results: map[SourceCode:1618: /*
1619: * non-error returns are a promise to giveback() the urb later
1620: * we drop ownership so next owner (or urb unlink) can get it
1621: */
1622: static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
1623: {
1624: struct xhci_hcd *xhci = hcd_to_xhci(hcd);
1625: unsigned long flags;
1626: int ret = 0;
1627: unsigned int slot_id, ep_index;
1628: unsigned int *ep_state;
1629: struct urb_priv *urb_priv;
1630: int num_tds;
1631:
1632: ep_index = xhci_get_endpoint_index(&urb->ep->desc);
1633:
1634: if (usb_endpoint_xfer_isoc(&urb->ep->desc))
1635: num_tds = urb->number_of_packets;
1636: else if (usb_endpoint_is_bulk_out(&urb->ep->desc) &&
1637: urb->transfer_buffer_length > 0 &&
1638: urb->transfer_flags & URB_ZERO_PACKET &&
1639: !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc)))
1640: num_tds = 2;
1641: else
1642: num_tds = 1;
1643:
1644: urb_priv = kzalloc(struct_size(urb_priv, td, num_tds), mem_flags);
1645: if (!urb_priv)
1646: return -ENOMEM;
1647:
1648: urb_priv->num_tds = num_tds;
1649: urb_priv->num_tds_done = 0;
1650: urb->hcpriv = urb_priv;
1651:
1652: trace_xhci_urb_enqueue(urb);
1653:
1654: spin_lock_irqsave(&xhci->lock, flags);
1655:
1656: ret = xhci_check_args(hcd, urb->dev, urb->ep,
1657: true, true, __func__);
1658: if (ret <= 0) {
1659: ret = ret ? ret : -EINVAL;
1660: goto free_priv;
1661: }
1662:
1663: slot_id = urb->dev->slot_id;
1664:
1665: if (!HCD_HW_ACCESSIBLE(hcd)) {
1666: ret = -ESHUTDOWN;
1667: goto free_priv;
1668: }
1669:
1670: if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
1671: xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
1672: ret = -ENODEV;
1673: goto free_priv;
1674: }
1675:
1676: if (xhci->xhc_state & XHCI_STATE_DYING) {
1677: xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n",
1678: urb->ep->desc.bEndpointAddress, urb);
1679: ret = -ESHUTDOWN;
1680: goto free_priv;
1681: }
1682:
1683: ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state;
1684:
1685: if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) {
1686: xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n",
1687: *ep_state);
1688: ret = -EINVAL;
1689: goto free_priv;
1690: }
1691: if (*ep_state & EP_SOFT_CLEAR_TOGGLE) {
1692: xhci_warn(xhci, "Can't enqueue URB while manually clearing toggle\n");
1693: ret = -EINVAL;
1694: goto free_priv;
1695: }
1696:
1697: switch (usb_endpoint_type(&urb->ep->desc)) {
1698:
1699: case USB_ENDPOINT_XFER_CONTROL:
1700: ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
1701: slot_id, ep_index);
1702: break;
1703: case USB_ENDPOINT_XFER_BULK:
1704: ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
1705: slot_id, ep_index);
1706: break;
1707: case USB_ENDPOINT_XFER_INT:
1708: ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
1709: slot_id, ep_index);
1710: break;
1711: case USB_ENDPOINT_XFER_ISOC:
1712: ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,
1713: slot_id, ep_index);
1714: }
1715:
1716: if (ret) {
1717: free_priv:
1718: xhci_urb_free_priv(urb_priv);
1719: urb->hcpriv = NULL;
1720: }
1721: spin_unlock_irqrestore(&xhci->lock, flags);
1722: return ret;
1723: }
SourceFile:drivers/usb/host/xhci.c]
|
| 72/2 |
2026/05/21 10:17 |
llm |
expert |
0m
Model:
Tokens:
input: 78337
output: 49
thoughts: 1990
Thoughts: **Analysis of a Race Condition in the cm109 Driver**
Okay, so I've been digging into this potential vulnerability within the `cm109` driver and I think I've got a handle on it. The root of the problem seems to be a race condition in how the USB request blocks (`URBs`) are handled, specifically in the `xhci_urb_enqueue` function. I see that `urb->hcpriv` is set *before* the `xhci->lock` is even acquired. This is a critical oversight.
If we have concurrent calls to `usb_submit_urb`, it's possible that both threads might read a `NULL` value for `urb->hcpriv` before either of them has a chance to set it. Then, let's say Thread 1 allocates `urb_priv` and sets `urb->hcpriv = urb_priv`. Now Thread 2 does the same, allocating and *overwriting* Thread 1's `urb_priv` with its own. Both of them could then head off to `xhci_queue_ctrl_tx` or similar, which then calls `usb_hcd_link_urb_to_ep`. This leads to a double `list_add` on *any* HCD, and in the case of xHCI it also causes a memory leak of the original `urb_priv`. So, this is a fairly generic bug.
Now, let's nail down exploitability. I'm seeing a clear list corruption and potential denial-of-service here, but the crucial question is *accessibility*. Can an unprivileged user trigger this reliably? The race is between `cm109_input_open` and `cm109_input_ev`. I'm going through the different scenarios:
* Can an unprivileged user open `/dev/input/eventX` directly? No, usually not. But, `kbd_connect` calls it automatically on device registration. `kbd_connect` is called by `input_register_device`, which happens during `cm109_usb_probe`, which calls `cm109_input_open`. So, `cm109_input_open` is called automatically by the kernel when the device is plugged in!
* How about `kd_mksound` which calls `cm109_input_ev`? Well, any user who can print a bell character `\a` to a VT can trigger `kd_mksound`. An unprivileged user logged into a VT can certainly do this with `echo -e '\a'`. So the race condition hinges on whether `cm109_input_open` is running concurrently.
If the device is plugged in, the kernel automatically calls `cm109_input_open`. If a user *simultaneously* triggers the bell, `kd_mksound` calls `cm109_input_ev`, triggering the race. So, it comes down to a timing issue; the user needs to trigger the bell *exactly* when the device is plugged in. This would be a *Peripheral Trigger* - an attacker needs to physically plug in the device (or be able to open the input device).
I'm checking if there's any other way to trigger `cm109_input_open` without physical plugging. If the user can open and close the input device repeatedly, they could. Usually the `crw-rw----` permissions prevent this for `evdev` devices, but I need to make sure I consider all scenarios.
I'm also looking at other options, such as using `uinput`. But it seems that `/dev/uinput` typically also requires root/input group access. Also, Wayland or X server scenarios are out, because they don't allow control over opening and closing of devices.
So, realistically, to reliably trigger this without physical access or privileges is difficult. To trigger this reliably, an attacker must physically plug the device, or have the privileges to do so. Therefore, "Accessible From Unprivileged Processes" should be False, as it requires physical or privileged access.
Let's double-check other entry points to the `cm109_input_open`. The only place that it could potentially be entered is through the device probe/connect flow, or if the device is opened by a privileged process (like the `kbd` handler). If the device is already plugged in and the system suspends and resumes, `cm109_usb_resume` directly calls `usb_submit_urb` if `dev->open` is true.
Let's summarize the dimensions.
* Exploitable: Yes, list corruption.
* Denial Of Service: Yes.
* Accessible
|
| 73/2 |
2026/05/21 10:17 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_usb_resume]
Results: map[SourceCode: 824: static int cm109_usb_resume(struct usb_interface *intf)
825: {
826: struct cm109_dev *dev = usb_get_intfdata(intf);
827:
828: dev_info(&intf->dev, "cm109: usb_resume\n");
829:
830: guard(mutex)(&dev->pm_mutex);
831:
832: cm109_restore_state(dev);
833:
834: return 0;
835: }
SourceFile:drivers/input/misc/cm109.c]
|
| 74/2 |
2026/05/21 10:17 |
llm |
expert |
0m
Model:
Tokens:
input: 81607
output: 49
thoughts: 14
Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:
**Investigating `cm109_restore_state`**
Alright, time to dig into this. "Let's check `cm109_restore_state`." That's the key starting point. I need to get my head around this particular function or module or whatever `cm109_restore_state` represents in this context. What does it *do*? What are its inputs and outputs? What assumptions are being made about the system's state when it's called? Is it involved in a rollback scenario? Perhaps a boot process? Or maybe a reconfiguration routine?
My initial thought is to recall what I know about our architecture and how state is typically managed within this system. Immediately I'm trying to place this function within the broader context of the system's operation. I want to understand where it fits in the sequence of events, and what the dependencies might be. Is there any particular reason this one stands out?
Okay, let's get started...Let's check...
|
| 75/2 |
2026/05/21 10:17 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/cm109.c IncludeLines:true Name:cm109_restore_state]
Results: map[SourceCode: 527: static void cm109_restore_state(struct cm109_dev *dev)
528: {
529: if (dev->open) {
530: /*
531: * Restore buzzer state.
532: * This will also kick regular URB submission
533: */
534: cm109_toggle_buzzer_async(dev);
535: }
536: }
SourceFile:drivers/input/misc/cm109.c]
|
| 76/2 |
2026/05/21 10:17 |
llm |
expert |
0m
Model:
Tokens:
input: 82076
output: 66
thoughts: 4862
Thoughts: **Analysis of the CM109 USB Driver Double URB Submission Vulnerability**
Okay, so here's what I've figured out. We've got a double submission of a USB control URB (`urb_ctl`) in the CM109 USB audio driver. The key problem lies in a race condition between `cm109_input_open` and `cm109_toggle_buzzer_async`.
First, I realized `cm109_restore_state` doesn't open the input device, so suspend/resume doesn't directly trigger the bug. Then I considered the standard access controls around `/dev/input/eventX` and whether an unprivileged user could open the device and potentially trigger `cm109_input_open`. No, that's not possible without root or being in the `input` group. So, unprivileged access isn't the primary route.
Next, I thoroughly examined the code, focusing on how `dev->ctl_urb` might get submitted twice. The guard around `ctl_submit_lock` seemed like it would prevent concurrent execution of `cm109_toggle_buzzer_async` calls, but that's not the critical path.
The aha! moment was spotting the absence of a crucial check in `cm109_submit_ctl`. `cm109_submit_ctl`, called from `cm109_urb_irq_callback`, unconditionally submits `dev->urb_ctl`, even if it's already pending. This opens up the possibility of a double submission. The scenario plays out like this: `cm109_toggle_buzzer_async` gets called while an interrupt URB (`urb_irq`) is pending. `cm109_toggle_buzzer_async` sets `dev->ctl_urb_pending = 1` and submits `dev->urb_ctl`. Then, the `urb_irq` completes, calling `cm109_urb_irq_callback`, which, in turn, calls `cm109_submit_ctl`... and re-submits `dev->urb_ctl`. This race condition isn't based on calling `cm109_input_open` twice.
I meticulously traced the execution flow to be certain, and it all boils down to `cm109_toggle_buzzer_async` and `cm109_submit_ctl`'s interaction with the control URB pending state. However, it seems I initially overlooked the fact that `usb_submit_urb` returns -EBUSY and issues a warning. This prevents a double list add! Then I thought about `cm109_input_open`.
I realized that `cm109_input_open` *does* open the control URB without the same lock! *That's* the race! This provides the correct concurrency: the bug can occur as a race condition when the device is plugged in, and an attacker can exploit the double submission by plugging in the device and triggering a bell, such as by `echo -e '\a' > /dev/tty1`.
The crucial thing is `cm109_input_open` runs without the submission lock, and the write from the user triggered call to `cm109_toggle_buzzer_async` that *does* take the lock.
With my understanding of the `dummy_hcd` from the syzkaller reproducer, it means the syzkaller reproducer is likely creating a condition where the HCD doesn't properly handle `urb->hcpriv` and fails to detect a double submit. The double `list_add` is the key vulnerability.
So, in summary, we have a double USB URB submission vulnerability. It requires plugging a C-Media CM109 USB audio device into the system and triggering the bell. The bug requires *physical access* to the device to trigger a key press, or by exploiting the device if it's malicious. This classifies it as a Peripheral Trigger, and it can also occur in a VM Host context (e.g. Confidential Computing) if hotplugging the device. This does not require remote network access, unprivileged user accounts, or a file system trigger.
The vulnerability leads to memory corruption due to the double addition of a URB to a list, which is exploitable and can cause a denial-of-service condition (kernel crash).
|
| 77/2 |
2026/05/21 10:18 |
tool |
set-results |
0m
Args: map[DenialOfService:true Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:true]
Results: map[DenialOfService:true Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:true]
|
| 78/2 |
2026/05/21 10:18 |
llm |
expert |
0m
Model:
Tokens:
input: 88019
output: 741
thoughts: 477
Thoughts: **Finalizing the Response**
Okay, the analysis is complete, and it's time to craft the final response. My findings point to a race condition within the `cm109` USB driver, specifically between the `cm109_input_open()` and `cm109_toggle_buzzer_async()` functions.
It appears that when a CM109 USB device is connected, the kernel automatically registers it as an input device. The standard keyboard handler, `kbd_connect`, immediately opens this device, which triggers `cm109_input_open()`. The issue is, during this process, `cm109_input_open()` submits the control URB (`dev->urb_ctl`) without properly holding the `dev->ctl_submit_lock`.
Concurrently, there's another pathway for interference. If a bell event is initiated β for instance, by writing a bell character to a VT β `kd_mksound()` injects an event that calls `cm109_input_ev()`, and that leads to `cm109_toggle_buzzer_async()`. Now, `cm109_toggle_buzzer_async()` does take the lock (`dev->ctl_submit_lock`). It checks if the URB is already pending and submits the URB if it's not.
The problem lies in the concurrency. Because `cm109_input_open()` *doesn't* acquire the lock before submitting the URB, both functions can potentially run simultaneously and try to submit the *same* URB (`dev->urb_ctl`) at the same time.
While `usb_submit_urb()` in the USB core attempts to prevent double submission by checking `urb->hcpriv`, both threads can pass this check before the Host Controller Driver (HCD) sets `urb->hcpriv`. This means both threads will go on to enqueue the URB. This leads to a double `list_add` in the HCD's endpoint queue, corrupting the list.
Now, we all know that list corruption within the kernel is a serious vulnerability. It's generally exploitable, opening the door to memory corruption β think arbitrary write or use-after-free β which could lead to privilege escalation or a denial-of-service condition.
As far as triggering the bug, it requires either physically plugging in a USB device, or emulating one. This means an unprivileged user can't trigger it directly without physical access, since emulating USB devices or direct access to restricted input devices is typically beyond their capabilities. So it's either a Peripheral Trigger with physical access or a VM Host Trigger.
|
| 79/1 |
2026/05/21 10:18 |
action |
format-explanation |
0m
Results: map[Explanation:Based on the analysis of the bug report and the kernel source code, here is the
assessment of the vulnerability:
### Bug Mechanism
The bug is a race condition in the `cm109` USB driver (for C-Media CM109/CM119
USB phones) that leads to a double submission of the same USB Request Block
(URB), causing a double `list_add` and subsequent list corruption in the USB
core.
When a CM109 USB device is plugged in, the kernel registers it as an input
device. The VT keyboard handler (`kbd_connect`) automatically opens the device,
invoking the driver's `cm109_input_open()` callback. This function initializes
the device and submits the control URB (`dev->urb_ctl`) to the USB core.
Crucially, it does so **without** holding the driver's `dev->ctl_submit_lock`.
Concurrently, if a terminal bell event is triggered (e.g., an unprivileged user
printing a `\a` bell character to a virtual terminal like `/dev/tty1`),
`kd_mksound()` injects a sound event into the input subsystem. This invokes the
driver's `cm109_input_ev()` callback, which calls `cm109_toggle_buzzer_async()`.
This function takes the `dev->ctl_submit_lock`, checks if the control URB is
already pending, and if not, submits `dev->urb_ctl`.
Because `cm109_input_open()` does not hold the lock, both functions can execute
concurrently. They can both observe the URB as not pending and call
`usb_submit_urb(dev->urb_ctl)` simultaneously. The USB core's `usb_submit_urb()`
checks if the URB is already active by verifying `urb->hcpriv == NULL` without
any locks. Both threads can pass this check before the Host Controller Driver
(HCD) has a chance to set `urb->hcpriv`. Consequently, both threads proceed to
enqueue the URB, leading to a double `list_add` in the HCD's endpoint queue
(`usb_hcd_link_urb_to_ep`).
### Security Impact
* **Exploitable & Denial of Service:** Yes. A double `list_add` corrupts the
kernel's internal linked lists. While `CONFIG_DEBUG_LIST` (if enabled) will
catch this and safely crash the kernel (Denial of Service), production kernels
typically disable list debugging for performance. In such cases, the list
corruption can be manipulated to achieve arbitrary memory read/write or
use-after-free, which is a classic vector for privilege escalation.
* **Peripheral Trigger:** Yes. The bug requires the attacker to plug in a
malicious or standard CM109 USB device to trigger the `cm109_input_open()` path
while simultaneously triggering a terminal bell.
* **VM Host Trigger:** Yes. A malicious hypervisor can hotplug a virtual CM109
USB device into a Confidential Computing guest to trigger the vulnerability and
compromise the guest kernel.
* **Accessible From Unprivileged Processes:** No. While an unprivileged user can
trigger the terminal bell, they cannot trigger the `cm109_input_open()` path
without physical access to plug in the USB device, as unprivileged users do not
have the permissions to open `/dev/input/eventX` devices directly or emulate USB
devices via `/dev/raw-gadget`.]
|