| 0/0 |
2026/05/24 05:16 |
flow |
assessment-security |
45m
Results: map[DenialOfService:true Explanation:**Analysis of the Bug**
The bug report indicates an RCU stall (`rcu_preempt detected expedited stalls on
CPUs/tasks`) accompanied by a flood of kernel error messages from the `yealink`
USB driver:
```
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
```
**Root Cause**
The `yealink` driver uses two URBs to communicate with the USB device: a control
URB (`urb_ctl`) and an interrupt URB (`urb_irq`).
When these URBs complete, their respective completion handlers
(`urb_ctl_callback` and `urb_irq_callback`) are invoked.
In both callbacks, the driver checks if the URB completed with an error (`status
!= 0`). If an error occurred, it prints an error message using `dev_err()`:
```c
if (status)
dev_err(&yld->intf->dev, "%s - urb status %d\n",
__func__, status);
```
Crucially, the driver **does not abort or stop resubmitting the URBs** upon
encountering an error. Instead, it proceeds to submit the next URB in the
sequence (`urb_ctl_callback` submits `urb_irq`, and `urb_irq_callback` submits
`urb_ctl`).
If a malicious USB device (or a dummy HCD, as used in the syzkaller reproducer)
immediately completes these URBs with an error (e.g., `-EPROTO` / `-71`), it
creates an infinite ping-pong loop of URB submissions and completions.
This loop runs in the context of the HCD's completion handler (e.g., a timer
interrupt or tasklet). The continuous stream of `dev_err` messages floods the
kernel log buffer and the serial console. Because the console output is slow and
the loop runs in an interrupt context, it completely stalls the CPU, preventing
RCU grace periods from completing and leading to an RCU stall (Denial of
Service).
**Security Impact**
* **Exploitable:** No. The bug is purely an infinite loop of URB submissions and
printks. There is no memory corruption, out-of-bounds access, or use-after-free
involved.
* **Denial Of Service:** Yes. The infinite loop and printk flood will stall the
CPU, leading to a system hang and RCU stall.
* **Peripheral Trigger:** Yes. A malicious USB device (e.g., a Facedancer) can
trigger this by continuously returning errors for the control and interrupt
endpoints. When the device is plugged in, userspace daemons (like
`systemd-udevd`) will automatically open the input device to probe it, which
starts the URB submission loop.
* **Unprivileged / User Namespace:** No. Triggering this requires either
physical access to plug in a malicious USB device or root privileges to emulate
one via `/dev/raw-gadget`. Unprivileged users cannot trigger this bug. Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
|
| 1/1 |
2026/05/24 05:16 |
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);
}
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;
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 ea fa 72 40 93 69 01 b0 29 3d f4 00 10 01 09 02 1b 00 01 24 a8 00 80 09 04 00 00 01 03 00 00 00 09 05} (length 0x26)
// }
// union ANYUNION {
// ANYRES16: ANYRES16 (resource)
// }
// union ANYUNION {
// ANYRESDEC: ANYRES64 (resource)
// }
// }
// }
// conn_descs: nil
// ]
// returns fd_usb
memcpy((void*)0x200000000100, "... [truncated large byte array] ...", 38);
*(uint16_t*)0x200000000126 = -1;
sprintf((char*)0x200000000128, "%020llu", (long long)-1);
syz_usb_connect(/*speed=*/0, /*dev_len=*/0x2d, /*dev=*/0x200000000100, /*conn_descs=*/0);
return 0;
}
]
|
| 2/1 |
2026/05/24 05:16 |
action |
kernel-checkouter |
2m
Results: map[KernelSrc:/app/workdir/cache/src/8490d977eb4694e0ca62776eb870cf740a1c1f2a]
|
| 3/1 |
2026/05/24 05:18 |
action |
kernel-builder |
18m
Results: map[KernelObj:/app/workdir/cache/build/83aad98592d65ea43abc52cc27295d519beb6021]
|
| 4/1 |
2026/05/24 05:36 |
action |
codesearch-prepare |
9m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/05/24 05:46 |
agent |
expert |
16m
Model:
Results: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
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).
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.
Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.
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:
rcu: INFO: rcu_preempt detected expedited stalls on CPUs/tasks: {
0-....
} 2686 jiffies s: 1033 root: 0x1/.
rcu: blocking rcu_node structures (internal RCU debug):
Sending NMI from CPU 1 to CPUs 0:
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
NMI backtrace for cpu 0
CPU: 0 PID: 2577 Comm: kworker/0:6 Not tainted 6.10.0-rc1-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/02/2024
Workqueue: mm_percpu_wq vmstat_update
RIP: 0010:io_serial_out+0x8f/0xb0 drivers/tty/serial/8250/8250_port.c:413
Code: 48 8d 7d 40 44 89 e1 48 b8 00 00 00 00 00 fc ff df 48 89 fa d3 e3 48 c1 ea 03 80 3c 02 00 75 1c 66 03 5d 40 44 89 e8 89 da ee <5b> 5d 41 5c 41 5d c3 cc cc cc cc e8 51 05 0b ff eb a0 e8 da 05 0b
RSP: 0018:ffffc900000075c0 EFLAGS: 00000002
RAX: 000000000000005b RBX: 00000000000003f8 RCX: 0000000000000000
RDX: 00000000000003f8 RSI: ffffffff829a9955 RDI: ffffffff8d71fc60
RBP: ffffffff8d71fc20 R08: 0000000000000001 R09: 000000000000001f
R10: 0000000000000000 R11: 0000000000000003 R12: 0000000000000000
R13: 000000000000005b R14: ffffffff829a98f0 R15: 0000000000000000
FS: 0000000000000000(0000) GS:ffff8881f6400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fffe156bf38 CR3: 0000000111c66000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<NMI>
</NMI>
<IRQ>
serial_out drivers/tty/serial/8250/8250.h:122 [inline]
serial8250_console_fifo_write drivers/tty/serial/8250/8250_port.c:3322 [inline]
serial8250_console_write+0xce7/0x1090 drivers/tty/serial/8250/8250_port.c:3393
console_emit_next_record kernel/printk/printk.c:2928 [inline]
console_flush_all+0x53c/0xd70 kernel/printk/printk.c:2994
console_unlock+0xae/0x290 kernel/printk/printk.c:3063
vprintk_emit kernel/printk/printk.c:2345 [inline]
vprintk_emit+0x11a/0x5a0 kernel/printk/printk.c:2300
dev_vprintk_emit drivers/base/core.c:4951 [inline]
dev_printk_emit+0xfb/0x140 drivers/base/core.c:4962
__dev_printk+0xf5/0x270 drivers/base/core.c:4974
_dev_err+0xe5/0x120 drivers/base/core.c:5017
urb_ctl_callback+0x1eb/0x2f0 drivers/input/misc/yealink.c:454
__usb_hcd_giveback_urb+0x364/0x5c0 drivers/usb/core/hcd.c:1648
usb_hcd_giveback_urb+0x396/0x450 drivers/usb/core/hcd.c:1732
dummy_timer+0x17f6/0x3900 drivers/usb/gadget/udc/dummy_hcd.c:1987
__run_hrtimer kernel/time/hrtimer.c:1687 [inline]
__hrtimer_run_queues+0x20c/0xcc0 kernel/time/hrtimer.c:1751
hrtimer_interrupt+0x31b/0x800 kernel/time/hrtimer.c:1813
local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1032 [inline]
__sysvec_apic_timer_interrupt+0x10f/0x450 arch/x86/kernel/apic/apic.c:1049
instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1043 [inline]
sysvec_apic_timer_interrupt+0x8b/0xb0 arch/x86/kernel/apic/apic.c:1043
</IRQ>
<TASK>
asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:702
RIP: 0010:__raw_spin_unlock_irq include/linux/spinlock_api_smp.h:160 [inline]
RIP: 0010:_raw_spin_unlock_irq+0x29/0x50 kernel/locking/spinlock.c:202
Code: 90 f3 0f 1e fa 53 48 8b 74 24 08 48 89 fb 48 83 c7 18 e8 da 3c 9c fa 48 89 df e8 c2 b9 9c fa e8 8d 57 c5 fa fb bf 01 00 00 00 <e8> 02 30 91 fa 65 8b 05 83 9c 6e 79 85 c0 74 06 5b c3 cc cc cc cc
RSP: 0018:ffffc9000148fcb8 EFLAGS: 00000206
RAX: 00000000000012f3 RBX: ffff8881f643c7c0 RCX: 1ffffffff137b4d9
RDX: 0000000000000000 RSI: ffffffff86c7d680 RDI: 0000000000000001
RBP: ffff8881f6438400 R08: 0000000000000001 R09: 0000000000000001
R10: ffffffff89bde057 R11: 0000000000000001 R12: ffff888104b5ba00
R13: 0000000000000000 R14: 0000000000000001 R15: ffff8881000aa800
process_one_work+0x849/0x1b60 kernel/workqueue.c:3200
process_scheduled_works kernel/workqueue.c:3312 [inline]
worker_thread+0x6c8/0xf70 kernel/workqueue.c:3393
kthread+0x2c1/0x3a0 kernel/kthread.c:389
ret_from_fork+0x45/0x80 arch/x86/kernel/process.c:147
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
</TASK>
INFO: NMI handler (nmi_cpu_backtrace_handler) took too long to run: 2.123 msecs
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
raw-gadget.4 gadget.4: ignoring, device is not running
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: unexpected response 0
raw-gadget.4 gadget.4: ignoring, device is not running
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 3-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_ctl_callback - usb_submit_urb failed -19
yealink 4-1:36.0: urb_irq_callback - urb status -71
raw-gadget.4 gadget.4: ignoring, device is not running
yealink 4-1:36.0: unexpected response 0
raw-gadget.4 gadget.4: ignoring, device is not running
yealink 4-1:36.0: urb_ctl_callback - urb status -71
raw-gadget.4 gadget.4: ignoring, device is not running
yealink 4-1:36.0: urb_irq_callback - urb status -71
raw-gadget.4 gadget.4: ignoring, device is not running
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
yealink 1-1:36.0: urb_irq_callback - urb status -71
yealink 4-1:36.0: unexpected response 0
yealink 1-1:36.0: unexpected response 0
yealink 4-1:36.0: urb_ctl_callback - urb status -71
yealink 1-1:36.0: urb_ctl_callback - urb status -71
yealink 4-1:36.0: urb_irq_callback - urb status -71
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);
}
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;
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 ea fa 72 40 93 69 01 b0 29 3d f4 00 10 01 09 02 1b 00 01 24 a8 00 80 09 04 00 00 01 03 00 00 00 09 05} (length 0x26)
// }
// union ANYUNION {
// ANYRES16: ANYRES16 (resource)
// }
// union ANYUNION {
// ANYRESDEC: ANYRES64 (resource)
// }
// }
// }
// conn_descs: nil
// ]
// returns fd_usb
memcpy((void*)0x200000000100, "... [truncated large byte array] ...", 38);
*(uint16_t*)0x200000000126 = -1;
sprintf((char*)0x200000000128, "%020llu", (long long)-1);
syz_usb_connect(/*speed=*/0, /*dev_len=*/0x2d, /*dev=*/0x200000000100, /*conn_descs=*/0);
return 0;
}
Reply: **Analysis of the Bug**
The bug report indicates an RCU stall (`rcu_preempt detected expedited stalls on CPUs/tasks`) accompanied by a flood of kernel error messages from the `yealink` USB driver:
```
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
```
**Root Cause**
The `yealink` driver uses two URBs to communicate with the USB device: a control URB (`urb_ctl`) and an interrupt URB (`urb_irq`).
When these URBs complete, their respective completion handlers (`urb_ctl_callback` and `urb_irq_callback`) are invoked.
In both callbacks, the driver checks if the URB completed with an error (`status != 0`). If an error occurred, it prints an error message using `dev_err()`:
```c
if (status)
dev_err(&yld->intf->dev, "%s - urb status %d\n",
__func__, status);
```
Crucially, the driver **does not abort or stop resubmitting the URBs** upon encountering an error. Instead, it proceeds to submit the next URB in the sequence (`urb_ctl_callback` submits `urb_irq`, and `urb_irq_callback` submits `urb_ctl`).
If a malicious USB device (or a dummy HCD, as used in the syzkaller reproducer) immediately completes these URBs with an error (e.g., `-EPROTO` / `-71`), it creates an infinite ping-pong loop of URB submissions and completions.
This loop runs in the context of the HCD's completion handler (e.g., a timer interrupt or tasklet). The continuous stream of `dev_err` messages floods the kernel log buffer and the serial console. Because the console output is slow and the loop runs in an interrupt context, it completely stalls the CPU, preventing RCU grace periods from completing and leading to an RCU stall (Denial of Service).
**Security Impact**
* **Exploitable:** No. The bug is purely an infinite loop of URB submissions and printks. There is no memory corruption, out-of-bounds access, or use-after-free involved.
* **Denial Of Service:** Yes. The infinite loop and printk flood will stall the CPU, leading to a system hang and RCU stall.
* **Peripheral Trigger:** Yes. A malicious USB device (e.g., a Facedancer) can trigger this by continuously returning errors for the control and interrupt endpoints. When the device is plugged in, userspace daemons (like `systemd-udevd`) will automatically open the input device to probe it, which starts the URB submission loop.
* **Unprivileged / User Namespace:** No. Triggering this requires either physical access to plug in a malicious USB device or root privileges to emulate one via `/dev/raw-gadget`. Unprivileged users cannot trigger this bug.
|
| 6/2 |
2026/05/24 05:46 |
llm |
expert |
0m
Model:
Tokens:
input: 46222
output: 44
thoughts: 1013
Thoughts: **Analyzing a USB Interrupt Stall**
Okay, here's what I'm seeing: we've got an RCU stall detected. Classic. The kernel's complaining about expedited stalls on CPUs, and it looks like a Yealink device (specifically, `yealink 3-1:36.0`) is the culprit. There's an "unexpected response 0" and a `-71` urb status being reported. That immediately flags a USB interrupt issue.
The NMI backtrace confirms this. CPU 0 is hung, and the call chain looks like a logging storm is the problem. It goes: we have some kind of communication with a serial port, then printk is being called, and console logging being flushed. My guess is we have some kind of infinite loop or a flood of error messages.
The NMI backtrace, starting from the top, shows the `io_serial_out` function being called and being called by `serial8250_console_write` which is called by the `console_flush_all` function in `kernel/printk/printk.c`. Now, `console_flush_all` is called by `dev_printk_emit` called by `urb_ctl_callback` in `drivers/input/misc/yealink.c`. And that's where things get interesting. The backtrace shows `urb_ctl_callback` in `drivers/input/misc/yealink.c` which then calls all of the functions to write to the console.
So, the key is `urb_ctl_callback` in the Yealink driver. That's where I need to focus my attention. It looks like it is calling `printk` in an inappropriate context, causing RCU stall. Time to dive into the Yealink driver code and trace the USB handling, especially error handling. I need to figure out what's causing this flood of messages within `urb_ctl_callback` related to USB transfers and why those error messages are written, and if these error messages are legitimate, and if not, how to silence them.
|
| 7/2 |
2026/05/24 05:46 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:urb_ctl_callback]
Results: map[SourceCode: 448: static void urb_ctl_callback(struct urb *urb)
449: {
450: struct yealink_dev *yld = urb->context;
451: int ret = 0, status = urb->status;
452:
453: if (status)
454: dev_err(&yld->intf->dev, "%s - urb status %d\n",
455: __func__, status);
456:
457: switch (yld->ctl_data->cmd) {
458: case CMD_KEYPRESS:
459: case CMD_SCANCODE:
460: /* ask for a response */
461: if (!yld->shutdown)
462: ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
463: break;
464: default:
465: /* send new command */
466: yealink_do_idle_tasks(yld);
467: if (!yld->shutdown)
468: ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
469: break;
470: }
471:
472: if (ret && ret != -EPERM)
473: dev_err(&yld->intf->dev, "%s - usb_submit_urb failed %d\n",
474: __func__, ret);
475: }
SourceFile:drivers/input/misc/yealink.c]
|
| 8/2 |
2026/05/24 05:46 |
llm |
expert |
0m
Model:
Tokens:
input: 48160
output: 47
thoughts: 287
Thoughts: **Analyzing the USB Control Callback**
Okay, so I'm looking at this `urb_ctl_callback` function. The first thing that jumps out is the status check. If it's non-zero, indicating an error, it prints a message. Makes sense, that's standard error handling. Then, it's checking the command in `yld->ctl_data->cmd`. If it's *not* a keypress or scancode command, it moves on to some idle tasks via `yealink_do_idle_tasks(yld)` and then attempts to resubmit the URB with `usb_submit_urb(yld->urb_ctl, GFP_ATOMIC)`.
Now, if `usb_submit_urb` *succeeds*, the code just queues it again. I immediately see the potential for a loop here if the URB consistently fails immediately after submission. Thinking about edge cases... if the device is disconnected during this resubmission or if there's an immediate failure in the URB submission itself, `usb_submit_urb` might return an error, which is handled. However, a broken or malicious device, or a dummy HCD, might return an error immediately (like -71, EPROTO), which leads back to the callback, triggering the resubmission loop.
Wait, let's clarify that. If `usb_submit_urb` *returns 0*, meaning it *succeeds* in queuing the URB, and the HCD then *immediately* completes the URB (perhaps due to an endpoint issue), the callback is triggered *again*. This sounds like the real potential for a problem.
And now I'm remembering how the callback *actually* gets invoked: it's called from the HCD's "giveback" function, which means it might be in the same context as the URB submission or in a tasklet or softirq. That means that if the HCD completes the URB *immediately*, we could be looking at an infinite loop or a massive flood of `printk` calls, which could be very bad. Let me have a look at `yealink_do_idle_tasks` to check what is going on there.
|
| 9/2 |
2026/05/24 05:46 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:yealink_do_idle_tasks]
Results: map[SourceCode: 312: /* keep stat_master & stat_copy in sync.
313: */
314: static int yealink_do_idle_tasks(struct yealink_dev *yld)
315: {
316: u8 val;
317: int i, ix, len;
318:
319: ix = yld->stat_ix;
320:
321: memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
322: yld->ctl_data->cmd = CMD_KEYPRESS;
323: yld->ctl_data->size = 1;
324: yld->ctl_data->sum = 0xff - CMD_KEYPRESS;
325:
326: /* If state update pointer wraps do a KEYPRESS first. */
327: if (ix >= sizeof(yld->master)) {
328: yld->stat_ix = 0;
329: return 0;
330: }
331:
332: /* find update candidates: copy != master */
333: do {
334: val = yld->master.b[ix];
335: if (val != yld->copy.b[ix])
336: goto send_update;
337: } while (++ix < sizeof(yld->master));
338:
339: /* nothing todo, wait a bit and poll for a KEYPRESS */
340: yld->stat_ix = 0;
341: /* TODO how can we wait abit. ??
342: * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY);
343: */
344: return 0;
345:
346: send_update:
347:
348: /* Setup an appropriate update request */
349: yld->copy.b[ix] = val;
350: yld->ctl_data->data[0] = val;
351:
352: switch(ix) {
353: case offsetof(struct yld_status, led):
354: yld->ctl_data->cmd = CMD_LED;
355: yld->ctl_data->sum = -1 - CMD_LED - val;
356: break;
357: case offsetof(struct yld_status, dialtone):
358: yld->ctl_data->cmd = CMD_DIALTONE;
359: yld->ctl_data->sum = -1 - CMD_DIALTONE - val;
360: break;
361: case offsetof(struct yld_status, ringtone):
362: yld->ctl_data->cmd = CMD_RINGTONE;
363: yld->ctl_data->sum = -1 - CMD_RINGTONE - val;
364: break;
365: case offsetof(struct yld_status, keynum):
366: val--;
367: val &= 0x1f;
368: yld->ctl_data->cmd = CMD_SCANCODE;
369: yld->ctl_data->offset = cpu_to_be16(val);
370: yld->ctl_data->data[0] = 0;
371: yld->ctl_data->sum = -1 - CMD_SCANCODE - val;
372: break;
373: default:
374: len = sizeof(yld->master.s.lcd) - ix;
375: if (len > sizeof(yld->ctl_data->data))
376: len = sizeof(yld->ctl_data->data);
377:
378: /* Combine up to <len> consecutive LCD bytes in a singe request
379: */
380: yld->ctl_data->cmd = CMD_LCD;
381: yld->ctl_data->offset = cpu_to_be16(ix);
382: yld->ctl_data->size = len;
383: yld->ctl_data->sum = -CMD_LCD - ix - val - len;
384: for(i=1; i<len; i++) {
385: ix++;
386: val = yld->master.b[ix];
387: yld->copy.b[ix] = val;
388: yld->ctl_data->data[i] = val;
389: yld->ctl_data->sum -= val;
390: }
391: }
392: yld->stat_ix = ix + 1;
393: return 1;
394: }
SourceFile:drivers/input/misc/yealink.c]
|
| 10/2 |
2026/05/24 05:46 |
llm |
expert |
0m
Model:
Tokens:
input: 50320
output: 45
thoughts: 180
Thoughts: **Analyzing the Yealink Idle Task and USB Interaction**
Okay, so I'm looking at this `yealink_do_idle_tasks` function, and the first thing that jumps out is that it's setting `yld->ctl_data->cmd` to `CMD_KEYPRESS` by default. Interesting. Then it checks for updates, and if there are none, it simply returns. That means if nothing else happens, `yld->ctl_data->cmd` will *definitely* be `CMD_KEYPRESS`.
Now, the connection is starting to make sense. We have this `urb_ctl_callback` function, and inside its `switch` statement, we have cases for both `CMD_KEYPRESS` and `CMD_SCANCODE`. In both of those cases, if the device isn't shutting down, it calls `usb_submit_urb` with `yld->urb_irq`. The logic is pretty clear here; it seems like pressing any key on this device will submit an interrupt request.
Given the flow, it seems my next step is to understand what happens in that interrupt callback - `urb_irq_callback`. I need to figure out what data is being sent and processed to fully understand what's happening. The connection between the default `CMD_KEYPRESS` setting, the `urb_ctl_callback`, and the call to `usb_submit_urb` tells me that there is some form of key input that I need to analyze.
|
| 11/2 |
2026/05/24 05:46 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:urb_irq_callback]
Results: map[SourceCode: 396: /* Decide on how to handle responses
397: *
398: * The state transition diagram is somethhing like:
399: *
400: * syncState<--+
401: * | |
402: * | idle
403: * \|/ |
404: * init --ok--> waitForKey --ok--> getKey
405: * ^ ^ |
406: * | +-------ok-------+
407: * error,start
408: *
409: */
410: static void urb_irq_callback(struct urb *urb)
411: {
412: struct yealink_dev *yld = urb->context;
413: int ret, status = urb->status;
414:
415: if (status)
416: dev_err(&yld->intf->dev, "%s - urb status %d\n",
417: __func__, status);
418:
419: switch (yld->irq_data->cmd) {
420: case CMD_KEYPRESS:
421:
422: yld->master.s.keynum = yld->irq_data->data[0];
423: break;
424:
425: case CMD_SCANCODE:
426: dev_dbg(&yld->intf->dev, "get scancode %x\n",
427: yld->irq_data->data[0]);
428:
429: report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
430: break;
431:
432: default:
433: dev_err(&yld->intf->dev, "unexpected response %x\n",
434: yld->irq_data->cmd);
435: }
436:
437: yealink_do_idle_tasks(yld);
438:
439: if (!yld->shutdown) {
440: ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
441: if (ret && ret != -EPERM)
442: dev_err(&yld->intf->dev,
443: "%s - usb_submit_urb failed %d\n",
444: __func__, ret);
445: }
446: }
SourceFile:drivers/input/misc/yealink.c]
|
| 12/2 |
2026/05/24 05:46 |
llm |
expert |
0m
Model:
Tokens:
input: 51609
output: 48
thoughts: 862
Thoughts: **A Deep Dive into a Potential Yealink USB Driver Loop**
Okay, so here's what's happening in this Yealink driver... `urb_irq_callback` is calling `yealink_do_idle_tasks(yld)` and then it submits `yld->urb_ctl`. `urb_ctl_callback` *also* calls `yealink_do_idle_tasks(yld)` (unless the command is a KEYPRESS or SCANCODE) and then submits either `yld->urb_ctl` or `yld->urb_irq`. That alone doesn't immediately scream trouble.
Now, here's where it gets interesting. If `urb_ctl_callback` submits `urb_irq`, and `urb_irq` completes *immediately* with an error (let's say `-71`), `urb_irq_callback` *gets* called. `urb_irq_callback` then calls `yealink_do_idle_tasks(yld)`, which (if there are no updates) sets `yld->ctl_data->cmd` to `CMD_KEYPRESS`. And then? It submits `yld->urb_ctl`. Ugh.
If `urb_ctl` *also* completes immediately with an error, `urb_ctl_callback` gets called. This callback checks `yld->ctl_data->cmd`, sees it's `CMD_KEYPRESS`, and submits `yld->urb_irq`. *Boom*. Infinite loop. This ping-pong could happen if the device is disconnected, the endpoint is broken, or worse, if we're dealing with a dummy HCD that just immediately errors out.
Now, the code has error logging, which is *good*, but the problem is those errors are *printed*, and neither callback checks the `status` to see if there's an error.
Let me clarify: in `urb_ctl_callback` and `urb_irq_callback`, the code *prints* an error, but it *doesn't* return on error. It keeps submitting URBs.
If `usb_submit_urb` returns `-ENODEV` or `-EPERM`, that *should* break the loop at the `usb_submit_urb` level, but it returns 0 if the HCD accepts the URB. Ah, and that is what is happening. The `dummy_hcd` might accept the URB and then immediately complete it with, say, `-EPROTO` (-71) in a timer callback.
So here is what the stack trace shows. The `dummy_timer` function completes the URB, calls the callback, and the callback *immediately* submits another URB. It *looks* like `dummy_hcd` completes the URB in the same timer interrupt.
I should check `dummy_timer` in `dummy_hcd.c` to confirm.
|
| 13/2 |
2026/05/24 05:47 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c IncludeLines:true Name:dummy_timer]
Results: map[SourceCode:1777: /*
1778: * Drive both sides of the transfers; looks like irq handlers to both
1779: * drivers except that the callbacks are invoked from soft interrupt
1780: * context.
1781: */
1782: static enum hrtimer_restart dummy_timer(struct hrtimer *t)
1783: {
1784: struct dummy_hcd *dum_hcd = from_timer(dum_hcd, t, timer);
1785: struct dummy *dum = dum_hcd->dum;
1786: struct urbp *urbp, *tmp;
1787: unsigned long flags;
1788: int limit, total;
1789: int i;
1790:
1791: /* simplistic model for one frame's bandwidth */
1792: /* FIXME: account for transaction and packet overhead */
1793: switch (dum->gadget.speed) {
1794: case USB_SPEED_LOW:
1795: total = 8/*bytes*/ * 12/*packets*/;
1796: break;
1797: case USB_SPEED_FULL:
1798: total = 64/*bytes*/ * 19/*packets*/;
1799: break;
1800: case USB_SPEED_HIGH:
1801: total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
1802: break;
1803: case USB_SPEED_SUPER:
1804: /* Bus speed is 500000 bytes/ms, so use a little less */
1805: total = 490000;
1806: break;
1807: default: /* Can't happen */
1808: dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
1809: total = 0;
1810: break;
1811: }
1812:
1813: /* look at each urb queued by the host side driver */
1814: spin_lock_irqsave(&dum->lock, flags);
1815:
1816: if (!dum_hcd->udev) {
1817: dev_err(dummy_dev(dum_hcd),
1818: "timer fired with no URBs pending?\n");
1819: spin_unlock_irqrestore(&dum->lock, flags);
1820: return HRTIMER_NORESTART;
1821: }
1822: dum_hcd->next_frame_urbp = NULL;
1823:
1824: for (i = 0; i < DUMMY_ENDPOINTS; i++) {
1825: if (!ep_info[i].name)
1826: break;
1827: dum->ep[i].already_seen = 0;
1828: }
1829:
1830: restart:
1831: list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
1832: struct urb *urb;
1833: struct dummy_request *req;
1834: u8 address;
1835: struct dummy_ep *ep = NULL;
1836: int status = -EINPROGRESS;
1837:
1838: /* stop when we reach URBs queued after the timer interrupt */
1839: if (urbp == dum_hcd->next_frame_urbp)
1840: break;
1841:
1842: urb = urbp->urb;
1843: if (urb->unlinked)
1844: goto return_urb;
1845: else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1846: continue;
1847:
1848: /* Used up this frame's bandwidth? */
1849: if (total <= 0)
1850: continue;
1851:
1852: /* find the gadget's ep for this request (if configured) */
1853: address = usb_pipeendpoint (urb->pipe);
1854: if (usb_urb_dir_in(urb))
1855: address |= USB_DIR_IN;
1856: ep = find_endpoint(dum, address);
1857: if (!ep) {
1858: /* set_configuration() disagreement */
1859: dev_dbg(dummy_dev(dum_hcd),
1860: "no ep configured for urb %p\n",
1861: urb);
1862: status = -EPROTO;
1863: goto return_urb;
1864: }
1865:
1866: if (ep->already_seen)
1867: continue;
1868: ep->already_seen = 1;
1869: if (ep == &dum->ep[0] && urb->error_count) {
1870: ep->setup_stage = 1; /* a new urb */
1871: urb->error_count = 0;
1872: }
1873: if (ep->halted && !ep->setup_stage) {
1874: /* NOTE: must not be iso! */
1875: dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
1876: ep->ep.name, urb);
1877: status = -EPIPE;
1878: goto return_urb;
1879: }
1880: /* FIXME make sure both ends agree on maxpacket */
1881:
1882: /* handle control requests */
1883: if (ep == &dum->ep[0] && ep->setup_stage) {
1884: struct usb_ctrlrequest setup;
1885: int value;
1886:
1887: setup = *(struct usb_ctrlrequest *) urb->setup_packet;
1888: /* paranoia, in case of stale queued data */
1889: list_for_each_entry(req, &ep->queue, queue) {
1890: list_del_init(&req->queue);
1891: req->req.status = -EOVERFLOW;
1892: dev_dbg(udc_dev(dum), "stale req = %p\n",
1893: req);
1894:
1895: spin_unlock(&dum->lock);
1896: usb_gadget_giveback_request(&ep->ep, &req->req);
1897: spin_lock(&dum->lock);
1898: ep->already_seen = 0;
1899: goto restart;
1900: }
1901:
1902: /* gadget driver never sees set_address or operations
1903: * on standard feature flags. some hardware doesn't
1904: * even expose them.
1905: */
1906: ep->last_io = jiffies;
1907: ep->setup_stage = 0;
1908: ep->halted = 0;
1909:
1910: value = handle_control_request(dum_hcd, urb, &setup,
1911: &status);
1912:
1913: /* gadget driver handles all other requests. block
1914: * until setup() returns; no reentrancy issues etc.
1915: */
1916: if (value > 0) {
1917: ++dum->callback_usage;
1918: spin_unlock(&dum->lock);
1919: value = dum->driver->setup(&dum->gadget,
1920: &setup);
1921: spin_lock(&dum->lock);
1922: --dum->callback_usage;
1923:
1924: if (value >= 0) {
1925: /* no delays (max 64KB data stage) */
1926: limit = 64*1024;
1927: goto treat_control_like_bulk;
1928: }
1929: /* error, see below */
1930: }
1931:
1932: if (value < 0) {
1933: if (value != -EOPNOTSUPP)
1934: dev_dbg(udc_dev(dum),
1935: "setup --> %d\n",
1936: value);
1937: status = -EPIPE;
1938: urb->actual_length = 0;
1939: }
1940:
1941: goto return_urb;
1942: }
1943:
1944: /* non-control requests */
1945: limit = total;
1946: switch (usb_pipetype(urb->pipe)) {
1947: case PIPE_ISOCHRONOUS:
1948: /*
1949: * We don't support isochronous. But if we did,
1950: * here are some of the issues we'd have to face:
1951: *
1952: * Is it urb->interval since the last xfer?
1953: * Use urb->iso_frame_desc[i].
1954: * Complete whether or not ep has requests queued.
1955: * Report random errors, to debug drivers.
1956: */
1957: limit = max(limit, periodic_bytes(dum, ep));
1958: status = -EINVAL; /* fail all xfers */
1959: break;
1960:
1961: case PIPE_INTERRUPT:
1962: /* FIXME is it urb->interval since the last xfer?
1963: * this almost certainly polls too fast.
1964: */
1965: limit = max(limit, periodic_bytes(dum, ep));
1966: fallthrough;
1967:
1968: default:
1969: treat_control_like_bulk:
1970: ep->last_io = jiffies;
1971: total -= transfer(dum_hcd, urb, ep, limit, &status);
1972: break;
1973: }
1974:
1975: /* incomplete transfer? */
1976: if (status == -EINPROGRESS)
1977: continue;
1978:
1979: return_urb:
1980: list_del(&urbp->urbp_list);
1981: kfree(urbp);
1982: if (ep)
1983: ep->already_seen = ep->setup_stage = 0;
1984:
1985: usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
1986: spin_unlock(&dum->lock);
1987: usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
1988: spin_lock(&dum->lock);
1989:
1990: goto restart;
1991: }
1992:
1993: if (list_empty(&dum_hcd->urbp_list)) {
1994: usb_put_dev(dum_hcd->udev);
1995: dum_hcd->udev = NULL;
1996: } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1997: /* want a 1 msec delay here */
1998: hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
1999: }
2000:
2001: spin_unlock_irqrestore(&dum->lock, flags);
2002:
2003: return HRTIMER_NORESTART;
2004: }
SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]
|
| 14/2 |
2026/05/24 05:47 |
llm |
expert |
0m
Model:
Tokens:
input: 56561
output: 24
thoughts: 331
Thoughts: **Analyzing the USB Dummy Timer Loop**
Okay, let's break down this `dummy_timer` function. I see it's iterating through a queue of URBs, `dum_hcd->urbp_list`, using `list_for_each_entry_safe`. Standard stuff for handling a list in the kernel. The core action seems to be calling `usb_hcd_giveback_urb` on each URB. Now, that function is important; it can call `urb_ctl_callback`, which might, critically, submit *another* URB and append it to the `dum_hcd->urbp_list`. This introduces the possibility of the list changing *during* the iteration, a common concurrency issue.
Hmm, there's a safety mechanism in place. There's a check, right before the loop, and inside the loop:
```c
if (urbp == dum_hcd->next_frame_urbp)
break;
```
It looks like there's a mechanism in place to avoid infinite looping, but I'm concerned about how it interacts with the dynamic list. It's supposed to stop the loop when it reaches URBs queued *after* the timer interrupt. Then I see that `dum_hcd->next_frame_urbp` is set to `NULL` before the loop. So, the first time this code executes, the loop *won't* break, because we have:
```c
if (urbp == NULL)
break;
```
That doesn't make sense! `urbp` is never `NULL` in the `list_for_each_entry_safe` loop! Is this some sort of logic bug?
Hang on a minute... if `next_frame_urbp` is `NULL`, the `break` condition *never* gets triggered in that loop, because `urbp` will never be `NULL` within the loop. The loop will then keep iterating forever!
I need to trace where `next_frame_urbp` is actually set and figure out the intended logic. Something is definitely not right here.
|
| 15/2 |
2026/05/24 05:47 |
tool |
codesearch-find-references |
0m
Error:
Args: map[Name:next_frame_urbp]
Results: map[References:<nil> TruncatedOutput:false]
|
| 16/2 |
2026/05/24 05:47 |
llm |
expert |
0m
Model:
Tokens:
input: 57393
output: 20
thoughts: 13
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Analyzing the Search Query**
Okay, so the prompt is to summarize a thought process focused on "grep for `next_frame_urbp`". Immediately, my mind leaps to a few potential contexts. Given that I'm likely dealing with code or log analysis, `grep` is the key tool. The target, `next_frame_urbp`, suggests a low-level, possibly graphics-related function or variable. "URBP" likely indicates "Universal Rendering Bus Protocol", maybe a protocol or data structure pertaining to how graphics data is moved between different components. I'd need to consider if this is kernel-level, user-space, a specific graphics API (OpenGL, Vulkan, DirectX), or something more proprietary. The framing is to search using the grep command which means that I am searching through text files for the string next_frame_urbp. That is to say, I would want to search any text file that could contain this string of text. So I need to keep in mind, I need to consider all possible files that would make sense to have this string of text. I need to be methodical in my approach and ensure no stones are left unturned.
|
| 17/2 |
2026/05/24 05:47 |
tool |
grepper |
0m
Args: map[Expression:next_frame_urbp]
Results: map[Output:drivers/usb/gadget/udc/dummy_hcd.c=242=struct dummy_hcd {
--
drivers/usb/gadget/udc/dummy_hcd.c-251- struct list_head urbp_list;
drivers/usb/gadget/udc/dummy_hcd.c:252: struct urbp *next_frame_urbp;
drivers/usb/gadget/udc/dummy_hcd.c-253-
--
drivers/usb/gadget/udc/dummy_hcd.c=1261=static int dummy_urb_enqueue(
--
drivers/usb/gadget/udc/dummy_hcd.c-1299- urb->hcpriv = urbp;
drivers/usb/gadget/udc/dummy_hcd.c:1300: if (!dum_hcd->next_frame_urbp)
drivers/usb/gadget/udc/dummy_hcd.c:1301: dum_hcd->next_frame_urbp = urbp;
drivers/usb/gadget/udc/dummy_hcd.c-1302- if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
--
drivers/usb/gadget/udc/dummy_hcd.c=1782=static enum hrtimer_restart dummy_timer(struct hrtimer *t)
--
drivers/usb/gadget/udc/dummy_hcd.c-1821- }
drivers/usb/gadget/udc/dummy_hcd.c:1822: dum_hcd->next_frame_urbp = NULL;
drivers/usb/gadget/udc/dummy_hcd.c-1823-
--
drivers/usb/gadget/udc/dummy_hcd.c-1838- /* stop when we reach URBs queued after the timer interrupt */
drivers/usb/gadget/udc/dummy_hcd.c:1839: if (urbp == dum_hcd->next_frame_urbp)
drivers/usb/gadget/udc/dummy_hcd.c-1840- break;
]
|
| 18/2 |
2026/05/24 05:47 |
llm |
expert |
1m
Model:
Tokens:
input: 58243
output: 44
thoughts: 2477
Thoughts: **Analyzing the RCU Stall in the Yealink Driver**
Okay, let's break this down. My initial thought was that the `dummy_timer` in the dummy USB HCD might be causing an infinite loop somehow, but that's not the case. The timer is set up to fire every 1ms, using `hrtimer_start` with `HRTIMER_MODE_REL`. So, it's not a runaway process, but a periodic interrupt. The key is to find out why this periodic interrupt causes an RCU stall.
I started by looking at the control flow between `dummy_timer`, `dummy_urb_enqueue`, and the URB callback. The crucial bit seems to be the `dum_hcd->next_frame_urbp` pointer. The sequence is: `usb_submit_urb` in `urb_ctl_callback` calls `dummy_urb_enqueue`, and sets `next_frame_urbp`. `dummy_timer` iterates through a list of URBs (`urbp_list`), and breaks when it encounters `next_frame_urbp`. This logic looked sound. The `hrtimer_start` after this ensures that the timer fires every 1ms.
The code seems to be designed to schedule the timer for 1ms later, not to create an infinite loop. So, it's not the timer itself that's the problem, but what's *happening* inside the timer interrupt. I suspected a flood of `printk` statements might be the culprit. Specifically, the error handling where the `yealink` driver does:
```c
if (ret && ret != -EPERM)
dev_err(&yld->intf->dev, "%s - usb_submit_urb failed %d\n",
__func__, ret);
```
When an URB fails, an error message gets printed. A -71 (EPROTO) error triggers an error message. I started to wonder if this flood of printks was the cause. With a 1ms timer, that's potentially 1000 printks per second. With an error and retries, that can easily happen. Is that enough to stall RCU?
I looked into synchronous failures in `usb_submit_urb`, which would just return an error and print the message. That is, the callback doesn't loop if `usb_submit_urb` fails *synchronously*. So, it *must* be an asynchronous failure with retries.
Rereading `dummy_timer`, the flow is clear. There's an `urbp_list` of URBs, and `next_frame_urbp` is used to break the loop. The timer is scheduled to run again. So, the system is designed to handle URB completion asynchronously and schedule the next timer.
Then, I looked at the call stack, specifically `console_flush_all`. If the printk call is slow, it blocks. Since it's in a timer interrupt, and that is a hard interrupt, what's happening? After the timer fires, and if printk takes longer than 1ms, the timer might fire again immediately? No, the system does not work that way. I'm starting to think about what's actually logged in the system.
I noticed the repeated print messages: `urb_irq_callback`, `unexpected response 0`, `urb_ctl_callback` with `-71`. It looked like the `urb_ctl_callback` submits an `urb_irq`. `urb_irq` is being completed in the same timer interrupt. That led me to the conclusion that each timer interrupt processes one URB.
Then the problem became clearer. The flooding of printks from failed URBs might be the root cause. A slow serial console (like 115200 bps, which is about 11.5 KB/s) is easily overwhelmed by thousands of printks per second. If each printk is about 50 bytes, the output is now 50 KB/s. The buffer fills up, and `console_flush_all` spins. In hard interrupt context, interrupts are disabled. So `console_flush_all` might take a long time to drain.
The RCU stall is a symptom of the timer interrupt spending too much time printing to the serial console. The interrupt keeps adding and flushing messages. The buffer overflows, causing a huge delay in the timer interrupt. This is the problem.
So, is there a bug in the `yealink` driver? Yes, it blindly resubmits the URB even if there is an error. I need to check whether it handles `-ESHUTDOWN` and `-ENOENT` correctly. If the URB is not handled, this would lead to this problem.
|
| 19/2 |
2026/05/24 05:48 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:urb_ctl_callback]
Results: map[SourceCode: 448: static void urb_ctl_callback(struct urb *urb)
449: {
450: struct yealink_dev *yld = urb->context;
451: int ret = 0, status = urb->status;
452:
453: if (status)
454: dev_err(&yld->intf->dev, "%s - urb status %d\n",
455: __func__, status);
456:
457: switch (yld->ctl_data->cmd) {
458: case CMD_KEYPRESS:
459: case CMD_SCANCODE:
460: /* ask for a response */
461: if (!yld->shutdown)
462: ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
463: break;
464: default:
465: /* send new command */
466: yealink_do_idle_tasks(yld);
467: if (!yld->shutdown)
468: ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
469: break;
470: }
471:
472: if (ret && ret != -EPERM)
473: dev_err(&yld->intf->dev, "%s - usb_submit_urb failed %d\n",
474: __func__, ret);
475: }
SourceFile:drivers/input/misc/yealink.c]
|
| 20/2 |
2026/05/24 05:48 |
llm |
expert |
0m
Model:
Tokens:
input: 62226
output: 19
thoughts: 20
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm an expert in this field:
**Debugging a Potential Shutdown Race Condition**
Alright, so the code's checking `if (!yld->shutdown)`. My immediate thought is, "Okay, that's a condition check... but what's actually *controlling* that condition?" I need to understand the implications of this. A clear `shutdown` flag is important, but a simple check is not enough if it is a race condition.
I need to understand where `yld->shutdown` is actually *set*. Knowing *where* it's set is critical. Is it protected by a lock? Is it atomic? Is it set by another thread, or potentially from an interrupt handler? I need to trace back from this point to the initialization and all assignments. I need to understand *who* and *how* `shutdown` is being modified. The location in the code where this happens will determine the correctness of any multi-threaded operation. This check, as it stands, seems like a potential point for a race condition. I need to dig deeper.
|
| 21/2 |
2026/05/24 05:48 |
tool |
codesearch-find-references |
0m
Args:
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:amd5536_udc_stop SourceFile:drivers/usb/gadget/udc/snps_udc_core.c SourceLine:1983]] TruncatedOutput:false]
|
| 22/2 |
2026/05/24 05:48 |
llm |
expert |
0m
Model:
Tokens:
input: 62587
output: 15
thoughts: 21
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:
**Investigating a Potential Shutdown Issue in the Yealink Driver**
Right, let's get down to brass tacks. I need to figure out what's going on with this Yealink driver, specifically concerning potential shutdown interactions. The most direct approach, as always, is to dive straight into the code. The logical first step is to use `grep`. I'm going to search the `drivers/input/misc/yealink.c` file for any instances of the term `shutdown`. I'm not just looking for a simple string match, mind you. I'm looking for *meaningful* occurrences; variable names, function calls, or comments that are *relevant* to power management or system shutdown procedures within the Yealink driver context. This will give me a quick overview of how the driver handles (or *doesn't* handle) shutdown events and, hopefully, quickly reveal any potential areas of concern for me to dig into. A quick `grep` will get the ball rolling, and I'll determine my course of action from there.
|
| 23/2 |
2026/05/24 05:48 |
tool |
grepper |
0m
Args:
Results: map[Output:
Full output is too long, showing 500 out of 55713 lines.
Use more precise expression if possible.
[Documentation/ABI/stable/sysfs-driver-firmware-zynqmp=54=Users: Xilinx
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-55-
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:56:What: /sys/devices/platform/firmware\:zynqmp-firmware/shutdown_scope
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-57-Date: March 2020
--
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp=60=Description:
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:61: This sysfs interface allows to set the shutdown scope for the
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:62: next shutdown request. When the next shutdown is performed, the
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-63- platform specific portion of PSCI-system_off can use the chosen
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:64: shutdown scope.
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-65-
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:66: Following are available shutdown scopes(subtypes):
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-67-
--
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-82-
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:83: # cat /sys/devices/platform/firmware\:zynqmp-firmware/shutdown_scope
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:84: # echo <scope> > /sys/devices/platform/firmware\:zynqmp-firmware/shutdown_scope
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-85-
--
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-87-
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:88: # cat /sys/devices/platform/firmware\:zynqmp-firmware/shutdown_scope
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp:89: # echo "subsystem" > /sys/devices/platform/firmware\:zynqmp-firmware/shutdown_scope
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp-90-
--
Documentation/ABI/stable/sysfs-driver-mlxreg-io=66=Description: These files allow asserting system power cycling, switching
Documentation/ABI/stable/sysfs-driver-mlxreg-io-67- power supply units on and off and system's main power domain
Documentation/ABI/stable/sysfs-driver-mlxreg-io:68: shutdown.
Documentation/ABI/stable/sysfs-driver-mlxreg-io-69- Expected behavior:
--
Documentation/ABI/stable/sysfs-driver-mlxreg-io=93=Description: These files show the system reset cause, as following: power
Documentation/ABI/stable/sysfs-driver-mlxreg-io:94: auxiliary outage or power refresh, ASIC thermal shutdown, halt,
Documentation/ABI/stable/sysfs-driver-mlxreg-io-95- hotswap, watchdog, firmware reset, long press power button,
--
Documentation/ABI/stable/sysfs-driver-mlxreg-io=137=Description: These files show the system reset cause, as following:
Documentation/ABI/stable/sysfs-driver-mlxreg-io:138: COMEX thermal shutdown; wathchdog power off or reset was derived
Documentation/ABI/stable/sysfs-driver-mlxreg-io-139- by one of the next components: COMEX, switch board or by Small Form
--
Documentation/ABI/stable/sysfs-driver-mlxreg-io=341=Description: These files switching power supply units on and off.
--
Documentation/ABI/stable/sysfs-driver-mlxreg-io-347-
Documentation/ABI/stable/sysfs-driver-mlxreg-io:348:What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/shutdown_unlock
Documentation/ABI/stable/sysfs-driver-mlxreg-io-349-Date: October 2021
--
Documentation/ABI/stable/sysfs-driver-mlxreg-io=351=Contact: Vadim Pasternak <vadimp@nvidia.com>
Documentation/ABI/stable/sysfs-driver-mlxreg-io:352:Description: This file allows to unlock ASIC after thermal shutdown event.
Documentation/ABI/stable/sysfs-driver-mlxreg-io:353: When system thermal shutdown is enforced by ASIC, ASIC is
Documentation/ABI/stable/sysfs-driver-mlxreg-io-354- getting locked and after system boot it will not be available.
--
Documentation/ABI/stable/sysfs-driver-mlxreg-io-357- attribute to 1 (power cycle of main power domain).
Documentation/ABI/stable/sysfs-driver-mlxreg-io:358: Before setting shutdown_unlock to 1 it is recommended to
Documentation/ABI/stable/sysfs-driver-mlxreg-io-359- validate that system reboot cause is reset_asic_thermal or
Documentation/ABI/stable/sysfs-driver-mlxreg-io-360- reset_thermal_spc_or_pciesw.
Documentation/ABI/stable/sysfs-driver-mlxreg-io:361: In case shutdown_unlock is not set 1, the only way to release
Documentation/ABI/stable/sysfs-driver-mlxreg-io-362- ASIC from locking - is full system power cycle through the
--
Documentation/ABI/testing/sysfs-block-bcache=100=Description:
--
Documentation/ABI/testing/sysfs-block-bcache-102- switched on and off. In synchronous mode all writes are ordered
Documentation/ABI/testing/sysfs-block-bcache:103: such that the cache can reliably recover from unclean shutdown;
Documentation/ABI/testing/sysfs-block-bcache-104- if disabled bcache will not generally wait for writes to
--
Documentation/ABI/testing/sysfs-bus-papr-pmem=69=Description:
--
Documentation/ABI/testing/sysfs-bus-papr-pmem-72- to forcibly set specific bits returned from Hcall. These is then
Documentation/ABI/testing/sysfs-bus-papr-pmem:73: used to simulate various health or shutdown states for an nvdimm
Documentation/ABI/testing/sysfs-bus-papr-pmem-74- and are set by user-space tools like ndctl by issuing a PAPR DSM.
--
Documentation/ABI/testing/sysfs-class-chromeos=18=Description:
--
Documentation/ABI/testing/sysfs-class-chromeos-26- - "hibernate": Hibernate the EC.
Documentation/ABI/testing/sysfs-class-chromeos:27: - "at-shutdown": Reboot after an AP shutdown.
Documentation/ABI/testing/sysfs-class-chromeos-28-
--
Documentation/ABI/testing/sysfs-class-hwmon=861=Description:
--
Documentation/ABI/testing/sysfs-class-hwmon-865- system is expected take drastic action to reduce
Documentation/ABI/testing/sysfs-class-hwmon:866: power consumption, such as a system shutdown or
Documentation/ABI/testing/sysfs-class-hwmon-867- a forced powerdown of some devices.
--
Documentation/ABI/testing/sysfs-class-mic=40=Description:
--
Documentation/ABI/testing/sysfs-class-mic-49- a "boot" has to be written to this entry if
Documentation/ABI/testing/sysfs-class-mic:50: the card was previously shutdown during OSPM
Documentation/ABI/testing/sysfs-class-mic-51- suspend.
--
Documentation/ABI/testing/sysfs-class-mic-68- "reset" Initiates device reset.
Documentation/ABI/testing/sysfs-class-mic:69: "shutdown" Initiates card OS shutdown.
Documentation/ABI/testing/sysfs-class-mic-70- ========== ===================================================
Documentation/ABI/testing/sysfs-class-mic-71-
Documentation/ABI/testing/sysfs-class-mic:72:What: /sys/class/mic/mic<X>/shutdown_status
Documentation/ABI/testing/sysfs-class-mic-73-Date: October 2013
--
Documentation/ABI/testing/sysfs-class-mic=76=Description:
Documentation/ABI/testing/sysfs-class-mic-77- An Intel MIC device runs a Linux OS during its operation. This
Documentation/ABI/testing/sysfs-class-mic:78: OS can shutdown because of various reasons. When read, this
Documentation/ABI/testing/sysfs-class-mic:79: entry provides the status on why the card OS was shutdown.
Documentation/ABI/testing/sysfs-class-mic-80- Possible values are:
--
Documentation/ABI/testing/sysfs-class-mic-82- ========== ===================================================
Documentation/ABI/testing/sysfs-class-mic:83: "nop" shutdown status is not applicable, when the card OS
Documentation/ABI/testing/sysfs-class-mic-84- is "online"
--
Documentation/ABI/testing/sysfs-class-mic=170=Description:
--
Documentation/ABI/testing/sysfs-class-mic-172- via a heartbeat mechanism (see the description of
Documentation/ABI/testing/sysfs-class-mic:173: shutdown_status above). User space can turn off this
Documentation/ABI/testing/sysfs-class-mic-174- notification by setting heartbeat_enable to 0 and enable it by
--
Documentation/ABI/testing/sysfs-class-regulator=31=Description:
--
Documentation/ABI/testing/sysfs-class-regulator-52- "error" indicates an out-of-regulation status such as being
Documentation/ABI/testing/sysfs-class-regulator:53: disabled due to thermal shutdown, or voltage being unstable
Documentation/ABI/testing/sysfs-class-regulator-54- because of problems with the input power supply.
--
Documentation/ABI/testing/sysfs-driver-input-axp-pek=4=Description: Startup time in us. Board is powered on if the button is pressed
--
Documentation/ABI/testing/sysfs-driver-input-axp-pek-6-
Documentation/ABI/testing/sysfs-driver-input-axp-pek:7:What: /sys/class/input/input(x)/device/shutdown
Documentation/ABI/testing/sysfs-driver-input-axp-pek-8-Date: March 2014
--
Documentation/ABI/testing/sysfs-driver-input-axp-pek=10=Description: Shutdown time in us. Board is powered off if the button is pressed
Documentation/ABI/testing/sysfs-driver-input-axp-pek:11: for more than <shutdown_time>
--
Documentation/ABI/testing/sysfs-firmware-acpi=98=Description:
--
Documentation/ABI/testing/sysfs-firmware-acpi-218- Let's take power button fixed event for example, please kill acpid
Documentation/ABI/testing/sysfs-firmware-acpi:219: and other user space applications so that the machine won't shutdown
Documentation/ABI/testing/sysfs-firmware-acpi-220- when pressing the power button::
--
Documentation/ABI/testing/sysfs-fs-f2fs=456=Description: Show status of f2fs superblock in real time.
--
Documentation/ABI/testing/sysfs-fs-f2fs-465- 0x20 SBI_NEED_CP need to checkpoint
Documentation/ABI/testing/sysfs-fs-f2fs:466: 0x40 SBI_IS_SHUTDOWN shutdown by ioctl
Documentation/ABI/testing/sysfs-fs-f2fs-467- 0x80 SBI_IS_RECOVERED recovered orphan/data
--
Documentation/ABI/testing/sysfs-platform-dfl-fme=150=Description: Read-Only. It returns hardware trip threshold temperature in
--
Documentation/ABI/testing/sysfs-platform-dfl-fme-152- threshold, a fatal event will be triggered to board management
Documentation/ABI/testing/sysfs-platform-dfl-fme:153: controller (BMC) to shutdown FPGA.
Documentation/ABI/testing/sysfs-platform-dfl-fme-154-
--
Documentation/ABI/testing/sysfs-power=45=Description:
--
Documentation/ABI/testing/sysfs-power-58-
Documentation/ABI/testing/sysfs-power:59: 'shutdown' - the memory image will be saved by the kernel and
Documentation/ABI/testing/sysfs-power-60- the system will be powered off.
--
Documentation/ABI/testing/sysfs-power-82- - 'platform'
Documentation/ABI/testing/sysfs-power:83: - 'shutdown'
Documentation/ABI/testing/sysfs-power-84- - 'reboot'
--
Documentation/PCI/pci-error-recovery.rst=357=memory and remove itself from kernel operations, much as it would
Documentation/PCI/pci-error-recovery.rst:358:during system shutdown.
Documentation/PCI/pci-error-recovery.rst-359-
--
Documentation/PCI/pci-iov-howto.rst=109=Following piece of code illustrates the usage of the SR-IOV API.
--
Documentation/PCI/pci-iov-howto.rst-141-
Documentation/PCI/pci-iov-howto.rst:142: static void dev_shutdown(struct pci_dev *dev)
Documentation/PCI/pci-iov-howto.rst-143- {
--
Documentation/PCI/pci-iov-howto.rst-168- .driver.pm = &dev_pm_ops,
Documentation/PCI/pci-iov-howto.rst:169: .shutdown = dev_shutdown,
Documentation/PCI/pci-iov-howto.rst-170- .sriov_configure = dev_sriov_configure,
--
Documentation/PCI/pci.rst=358=of MSI/MSI-X usage.
--
Documentation/PCI/pci.rst-360-
Documentation/PCI/pci.rst:361:PCI device shutdown
Documentation/PCI/pci.rst-362-===================
--
Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.rst=489=task context pretty much any time during the life of the kernel. That
Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.rst:490:is, aside from some points in the suspend, hibernate, or shutdown code
Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.rst-491-path.
--
Documentation/RCU/Design/Requirements/Requirements.rst=1860=functions, for example, any outstanding mod_timer() must be dealt
Documentation/RCU/Design/Requirements/Requirements.rst:1861:with via timer_shutdown_sync() or similar.
Documentation/RCU/Design/Requirements/Requirements.rst-1862-
--
Documentation/admin-guide/bcache.rst=24=off, but can be switched on and off arbitrarily at runtime. Bcache goes to
Documentation/admin-guide/bcache.rst:25:great lengths to protect your data - it reliably handles unclean shutdown. (It
Documentation/admin-guide/bcache.rst:26:doesn't even have a notion of a clean shutdown; bcache simply doesn't return
Documentation/admin-guide/bcache.rst-27-writes as completed until they're on stable storage).
--
Documentation/admin-guide/cgroup-v1/memory.rst=895=maintaining cache level. Upon notification, the program (typically
Documentation/admin-guide/cgroup-v1/memory.rst-896-"Activity Manager") might analyze vmstat and act in advance (i.e.
Documentation/admin-guide/cgroup-v1/memory.rst:897:prematurely shutdown unimportant services).
Documentation/admin-guide/cgroup-v1/memory.rst-898-
--
Documentation/admin-guide/device-mapper/dm-raid.rst=276=recovery. Here is a fuller description of the individual fields:
--
Documentation/admin-guide/device-mapper/dm-raid.rst-296- - Array is undergoing its initial synchronization
Documentation/admin-guide/device-mapper/dm-raid.rst:297: or is resynchronizing after an unclean shutdown
Documentation/admin-guide/device-mapper/dm-raid.rst-298- (possibly aided by a bitmap).
--
Documentation/admin-guide/device-mapper/vdo-design.rst=330=Application write bios follow the steps outlined below.
--
Documentation/admin-guide/device-mapper/vdo-design.rst-502- problems. Circumstances causing an eviction include an application
Documentation/admin-guide/device-mapper/vdo-design.rst:503: flush, device shutdown, or a subsequent data_vio trying to overwrite
Documentation/admin-guide/device-mapper/vdo-design.rst-504- the same logical block address. A data_vio may also be evicted from
--
Documentation/admin-guide/device-mapper/vdo.rst=246=The messages are:
--
Documentation/admin-guide/device-mapper/vdo.rst-266-
Documentation/admin-guide/device-mapper/vdo.rst:267: dump-on-shutdown:
Documentation/admin-guide/device-mapper/vdo.rst-268- Perform a default dump next time vdo shuts down.
--
Documentation/admin-guide/ext4.rst=21=http://ext4.wiki.kernel.org/index.php/Ext4_Howto
--
Documentation/admin-guide/ext4.rst-63- running mounted with data=writeback can potentially leave stale data
Documentation/admin-guide/ext4.rst:64: exposed in recently written files in case of an unclean shutdown,
Documentation/admin-guide/ext4.rst-65- which could be a security exposure in some situations.) Configuring
--
Documentation/admin-guide/hw-vuln/multihit.rst=55=the linear address, a code fetch that happens on the same linear address may
Documentation/admin-guide/hw-vuln/multihit.rst:56:cause a machine-check error which can result in a system hang or shutdown.
Documentation/admin-guide/hw-vuln/multihit.rst-57-
--
Documentation/admin-guide/kernel-parameters.txt-3076-
Documentation/admin-guide/kernel-parameters.txt:3077: locktorture.shutdown_secs= [KNL]
Documentation/admin-guide/kernel-parameters.txt:3078: Set time (s) after boot system shutdown. This
Documentation/admin-guide/kernel-parameters.txt-3079- is useful for hands-off automated testing.
--
Documentation/admin-guide/kernel-parameters.txt-4000- nonmi_ipi [X86] Disable using NMI IPIs during panic/reboot to
Documentation/admin-guide/kernel-parameters.txt:4001: shutdown the other cpus. Instead use the REBOOT_VECTOR
Documentation/admin-guide/kernel-parameters.txt-4002- irq.
--
Documentation/admin-guide/kernel-parameters.txt-5222-
Documentation/admin-guide/kernel-parameters.txt:5223: rcuscale.shutdown= [KNL]
Documentation/admin-guide/kernel-parameters.txt-5224- Shut the system down after performance tests
--
Documentation/admin-guide/kernel-parameters.txt-5356-
Documentation/admin-guide/kernel-parameters.txt:5357: rcutorture.shutdown_secs= [KNL]
Documentation/admin-guide/kernel-parameters.txt:5358: Set time (s) after boot system shutdown. This
Documentation/admin-guide/kernel-parameters.txt-5359- is useful for hands-off automated testing.
--
Documentation/admin-guide/kernel-parameters.txt-5658-
Documentation/admin-guide/kernel-parameters.txt:5659: refscale.shutdown= [KNL]
Documentation/admin-guide/kernel-parameters.txt-5660- Shut down the system at the end of the performance
--
Documentation/admin-guide/kernel-parameters.txt-5905-
Documentation/admin-guide/kernel-parameters.txt:5906: scftorture.shutdown_secs= [KNL]
Documentation/admin-guide/kernel-parameters.txt-5907- The number of seconds following the start of the
--
Documentation/admin-guide/kernel-parameters.txt-6619-
Documentation/admin-guide/kernel-parameters.txt:6620: torture.ftrace_dump_at_shutdown= [KNL]
Documentation/admin-guide/kernel-parameters.txt:6621: Dump the ftrace buffer at torture-test shutdown,
Documentation/admin-guide/kernel-parameters.txt-6622- even if there were no errors. This can be a
--
Documentation/admin-guide/laptops/thinkpad-acpi.rst=585=Battery nearly empty alarms are a last resort attempt to get the
Documentation/admin-guide/laptops/thinkpad-acpi.rst:586:operating system to hibernate or shutdown cleanly (0x2313), or shutdown
Documentation/admin-guide/laptops/thinkpad-acpi.rst-587-cleanly (0x2413) before power is lost. They must be acted upon, as the
--
Documentation/admin-guide/laptops/thinkpad-acpi.rst=597=operating system is to force either an immediate suspend or hibernate
Documentation/admin-guide/laptops/thinkpad-acpi.rst:598:cycle, or a system shutdown. Obviously, something is very wrong if this
Documentation/admin-guide/laptops/thinkpad-acpi.rst-599-happens.
--
Documentation/admin-guide/laptops/thinkpad-acpi.rst=1027=mode with NVRAM backing (so that brightness changes are remembered across
Documentation/admin-guide/laptops/thinkpad-acpi.rst:1028:shutdown/reboot).
Documentation/admin-guide/laptops/thinkpad-acpi.rst-1029-
--
Documentation/admin-guide/laptops/thinkpad-acpi.rst=1194=selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing
Documentation/admin-guide/laptops/thinkpad-acpi.rst:1195:(so that volume/mute changes are remembered across shutdown/reboot).
Documentation/admin-guide/laptops/thinkpad-acpi.rst-1196-
--
Documentation/admin-guide/md.rst=191=All md devices contain:
--
Documentation/admin-guide/md.rst-405- This indicates how the array maintains consistency in case of unexpected
Documentation/admin-guide/md.rst:406: shutdown. It can be:
Documentation/admin-guide/md.rst-407-
--
Documentation/admin-guide/md.rst-412- Full resync is performed and all redundancy is regenerated when the
Documentation/admin-guide/md.rst:413: array is started after unclean shutdown.
Documentation/admin-guide/md.rst-414-
--
Documentation/admin-guide/md.rst-419- For raid4/5/6, journal device is used to log transactions and replay
Documentation/admin-guide/md.rst:420: after unclean shutdown.
Documentation/admin-guide/md.rst-421-
--
Documentation/admin-guide/md.rst=615=also have
--
Documentation/admin-guide/md.rst-622- redundancy is being recalculated after unclean
Documentation/admin-guide/md.rst:623: shutdown or creation
Documentation/admin-guide/md.rst-624-
--
Documentation/admin-guide/media/faq.rst=21=Some very frequently asked questions about Linux Digital TV support
--
Documentation/admin-guide/media/faq.rst-27- are powered down if they are unused (i.e. if the frontend device
Documentation/admin-guide/media/faq.rst:28: is closed). The ``dvb-core`` module parameter ``dvb_shutdown_timeout``
Documentation/admin-guide/media/faq.rst-29- allow you to change the timeout (default 5 seconds). Setting the
--
Documentation/admin-guide/mm/transhuge.rst=207=or by setting "inherit" while the top-level enabled is set to "always"
Documentation/admin-guide/mm/transhuge.rst:208:or "madvise"), and it'll be automatically shutdown when the last
Documentation/admin-guide/mm/transhuge.rst-209-hugepage size is disabled (either by directly setting "never", or by
--
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst=25=On startup, nfsd and lockd grace periods start. nfsd is shut down by a write of
--
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst-27-
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst:28:Between startup and shutdown, the number of threads may be adjusted up
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst-29-or down by additional writes to nfsd/threads or by writes to
--
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst=38=Note that the rpc server requires the caller to serialize addition and
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst:39:removal of listening sockets, and startup and shutdown of the server.
Documentation/admin-guide/nfs/nfsd-admin-interfaces.rst-40-For nfsd this is done using nfsd_mutex.
--
Documentation/admin-guide/pm/sleep-states.rst=160=following attributes (files):
--
Documentation/admin-guide/pm/sleep-states.rst-213-
Documentation/admin-guide/pm/sleep-states.rst:214: ``shutdown``
Documentation/admin-guide/pm/sleep-states.rst-215- Power off the system.
--
Documentation/admin-guide/ramoops.rst=147=file. Here is an example of usage::
--
Documentation/admin-guide/ramoops.rst-156- 0 ffffffff8101ea44 ffffffff8101bcf6 native_apic_mem_write <- disconnect_bsp_APIC+0x86/0xc0
Documentation/admin-guide/ramoops.rst:157: 0 ffffffff81020084 ffffffff8101a4b5 hpet_disable <- native_machine_shutdown+0x75/0x90
Documentation/admin-guide/ramoops.rst:158: 0 ffffffff81005f94 ffffffff8101a4bb iommu_shutdown_noop <- native_machine_shutdown+0x7b/0x90
Documentation/admin-guide/ramoops.rst-159- 0 ffffffff8101a6a1 ffffffff8101a437 native_machine_emergency_restart <- native_machine_restart+0x37/0x40
--
Documentation/admin-guide/spkguide.txt=32=provide speech access from the time the kernel is loaded, until the time
Documentation/admin-guide/spkguide.txt:33:the system is shutdown. This means that if you have obtained Linux
Documentation/admin-guide/spkguide.txt-34-installation media for a distribution which includes Speakup as a part
--
Documentation/admin-guide/sysrq.rst=193=Note that this just triggers a crash if there is no dump mechanism available.
--
Documentation/admin-guide/sysrq.rst-195-``sync(s)`` is handy before yanking removable medium or after using a rescue
Documentation/admin-guide/sysrq.rst:196:shell that provides no graceful shutdown -- it will ensure your data is
Documentation/admin-guide/sysrq.rst-197-safely written to the disk. Note that the sync hasn't taken place until you see
--
Documentation/admin-guide/xfs.rst=266=The following sysctls are available for the XFS filesystem:
--
Documentation/admin-guide/xfs.rst-293- This will generate detailed messages & backtraces for filesystem
Documentation/admin-guide/xfs.rst:294: shutdowns, for example. Current threshold values are:
Documentation/admin-guide/xfs.rst-295-
--
Documentation/arch/powerpc/eeh-pci-error-recovery.rst=252=which calls dev->stop() which is pcnet32_close()
Documentation/arch/powerpc/eeh-pci-error-recovery.rst:253:which then does the appropriate shutdown.
Documentation/arch/powerpc/eeh-pci-error-recovery.rst-254-
--
Documentation/arch/x86/intel_txt.rst=11=Intel TXT in Brief:
--
Documentation/arch/x86/intel_txt.rst-13-- Provides dynamic root of trust for measurement (DRTM)
Documentation/arch/x86/intel_txt.rst:14:- Data protection in case of improper shutdown
Documentation/arch/x86/intel_txt.rst-15-- Measurement and verification of launched environment
--
Documentation/arch/x86/intel_txt.rst=86=protection is provided for any data in the event of an improper
Documentation/arch/x86/intel_txt.rst:87:shutdown, and there is support for policy-based execution/verification.
Documentation/arch/x86/intel_txt.rst-88-This provides a more stable measurement and a higher assurance of
--
Documentation/arch/x86/intel_txt.rst=94=How Does it Work?
--
Documentation/arch/x86/intel_txt.rst-157-- At this point, tboot and TXT are out of the picture until a
Documentation/arch/x86/intel_txt.rst:158: shutdown (S<n>)
Documentation/arch/x86/intel_txt.rst-159-- In order to put a system into any of the sleep states after a TXT
--
Documentation/arch/x86/microcode.rst=153=taken at the end of the flow. Either way, they will wait for the thread
Documentation/arch/x86/microcode.rst:154:performing the wrmsr(0x79) to rendezvous in the MCE handler and shutdown
Documentation/arch/x86/microcode.rst-155-eventually if any of the threads in the system fail to check in to the
--
Documentation/core-api/cpu_hotplug.rst=31=Command Line Switches
--
Documentation/core-api/cpu_hotplug.rst-48-``cpu0_hotplug``
Documentation/core-api/cpu_hotplug.rst:49: Allow to shutdown CPU0.
Documentation/core-api/cpu_hotplug.rst-50-
--
Documentation/core-api/cpu_hotplug.rst=111=Each CPU folder contains an *online* file which controls the logical on (1) and
Documentation/core-api/cpu_hotplug.rst:112:off (0) state. To logically shutdown CPU4::
Documentation/core-api/cpu_hotplug.rst-113-
--
Documentation/core-api/cpu_hotplug.rst-116-
Documentation/core-api/cpu_hotplug.rst:117:Once the CPU is shutdown, it will be removed from */proc/interrupts*,
Documentation/core-api/cpu_hotplug.rst-118-*/proc/cpuinfo* and should also not be shown visible by the *top* command. To
--
Documentation/core-api/cpu_hotplug.rst=130=The offline case
--
Documentation/core-api/cpu_hotplug.rst-132-
Documentation/core-api/cpu_hotplug.rst:133:Once a CPU has been logically shutdown the teardown callbacks of registered
Documentation/core-api/cpu_hotplug.rst-134-hotplug states will be invoked, starting with ``CPUHP_ONLINE`` and terminating
--
Documentation/core-api/cpu_hotplug.rst=172=The state space is divided into three sections:
--
Documentation/core-api/cpu_hotplug.rst-210-
Documentation/core-api/cpu_hotplug.rst:211: The callbacks are used for low level hardware initialization/shutdown and
Documentation/core-api/cpu_hotplug.rst-212- for core subsystems.
--
Documentation/core-api/cpu_hotplug.rst=625=One way to verify whether a custom state is working as expected or not is to
Documentation/core-api/cpu_hotplug.rst:626:shutdown a CPU and then put it online again. It is also possible to put the CPU
Documentation/core-api/cpu_hotplug.rst-627-to certain state (for instance *CPUHP_AP_ONLINE*) and then go back to
--
Documentation/core-api/cpu_hotplug.rst=696=The following functions and configurations are required:
--
Documentation/core-api/cpu_hotplug.rst-704-``__cpu_disable()``
Documentation/core-api/cpu_hotplug.rst:705: Arch interface to shutdown a CPU, no more interrupts can be handled by the
Documentation/core-api/cpu_hotplug.rst:706: kernel after the routine returns. This includes the shutdown of the timer.
Documentation/core-api/cpu_hotplug.rst-707-
--
Documentation/core-api/kernel-api.rst=383=from several active domains, a "mem" (suspend-to-RAM) state may require
Documentation/core-api/kernel-api.rst:384:a more wholesale shutdown of clocks derived from higher speed PLLs and
Documentation/core-api/kernel-api.rst-385-oscillators, limiting the number of possible wakeup event sources. A
--
Documentation/core-api/local_ops.rst=136=Here is a sample module which implements a basic per cpu counter using
--
Documentation/core-api/local_ops.rst-193- {
Documentation/core-api/local_ops.rst:194: timer_shutdown_sync(&test_timer);
Documentation/core-api/local_ops.rst-195- }
--
Documentation/dev-tools/kfence.rst=303=page handling code to set up and deal with KFENCE allocations.
--
Documentation/dev-tools/kfence.rst-306- :functions: is_kfence_address
Documentation/dev-tools/kfence.rst:307: kfence_shutdown_cache
Documentation/dev-tools/kfence.rst-308- kfence_alloc kfence_free __kfence_free
--
Documentation/dev-tools/kunit/style.rst=80=functionality being tested. Test suites can have shared initialization and
Documentation/dev-tools/kunit/style.rst:81:shutdown code which is run for all tests in the suite. Not all subsystems need
Documentation/dev-tools/kunit/style.rst-82-to be split into multiple test suites (for example, simple drivers).
--
Documentation/devicetree/bindings/arm/vexpress-config.yaml=18=properties:
--
Documentation/devicetree/bindings/arm/vexpress-config.yaml-44-
Documentation/devicetree/bindings/arm/vexpress-config.yaml:45: shutdown:
Documentation/devicetree/bindings/arm/vexpress-config.yaml-46- type: object
--
Documentation/devicetree/bindings/arm/vexpress-config.yaml-48- compatible:
Documentation/devicetree/bindings/arm/vexpress-config.yaml:49: const: arm,vexpress-shutdown
Documentation/devicetree/bindings/arm/vexpress-config.yaml-50-
Documentation/devicetree/bindings/arm/vexpress-config.yaml-51- arm,vexpress-sysreg,func:
Documentation/devicetree/bindings/arm/vexpress-config.yaml:52: description: shutdown identifier
Documentation/devicetree/bindings/arm/vexpress-config.yaml-53- $ref: /schemas/types.yaml#/definitions/uint32-array
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml=9=description: |
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-32-
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml:33: The idt,shutdown and idt,output-enable-active properties control the
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml:34: SH (en_global_shutdown) and SP bits of the Primary Source and Shutdown
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-35- Register, respectively. Their behavior is summarized by the following
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml=50=properties:
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-82-
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml:83: idt,shutdown:
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-84- $ref: /schemas/types.yaml#/definitions/uint32
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-86- description: |
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml:87: If 1, this enables the shutdown functionality: the chip will be
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-88- shut down if the SD/OE pin is driven high. If 0, this disables the
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml:89: shutdown functionality: the chip will never be shut down based on
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-90- the value of the SD/OE pin. This property corresponds to the SH
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml=125=required:
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-128- - '#clock-cells'
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml:129: - idt,shutdown
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-130- - idt,output-enable-active
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml=155=examples:
--
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-181- /* Set the SD/OE pin's settings */
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml:182: idt,shutdown = <0>;
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml-183- idt,output-enable-active = <0>;
--
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml=16=properties:
--
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-41-
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml:42: shutdown-gpios:
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-43- maxItems: 1
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-44- description: |
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml:45: OF device-tree gpio specification for SD pin(active high shutdown input)
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-46-
--
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml=117=examples:
--
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-129- reg = <0x68>;
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml:130: shutdown-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-131- reset-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>;
--
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-166- reg = <0x68>;
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml:167: shutdown-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml-168- reset-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>;
--
Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml=20=properties:
--
Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml-86- description: The zynqmp-power node describes the power management
Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml:87: configurations. It will control remote suspend/shutdown interfaces.
Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml-88- type: object
--
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml=5=$schema: http://devicetree.org/meta-schemas/core.yaml#
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml-6-
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml:7:title: Xilinx LogiCORE Partial Reconfig Decoupler/AXI shutdown manager Softcore
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml-8-
--
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml=15=description: |
--
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml-20- bridge normally.
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml:21: Xilinx LogiCORE Dynamic Function eXchange(DFX) AXI shutdown manager Softcore
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml-22- is compatible with the Xilinx LogiCORE pr-decoupler. The Dynamic Function
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml:23: eXchange AXI shutdown manager prevents AXI traffic from passing through the
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml-24- bridge. The controller safely handles AXI4MM and AXI4-Lite interfaces on a
--
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml=31=properties:
--
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml-37- - items:
Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml:38: - const: xlnx,dfx-axi-shutdown-manager-1.00
]
]
|
| 24/2 |
2026/05/24 05:49 |
llm |
expert |
0m
Model:
Tokens:
input: 74247
output: 35
thoughts: 48
Thoughts: **Analyzing the Yealink Driver Shutdown Procedure**
Okay, so I'm digging into this `yealink_dev` structure and noticed this `yld->shutdown` field. Interesting. My mind immediately went to the driver source, so I'm going to jump into `drivers/input/misc/yealink.c` right away. To clarify what's going on, I think I'll use the codesearch-find-references functionality to check for all instances of "shutdown" within that file. That should give me a good picture of how and where this `shutdown` field is being used in the Yealink driver, which will help me understand its purpose and how the system manages the device's lifecycle. I expect to find some key interactions related to device power management or system shutdown sequences, right? Let's see what turns up!
|
| 25/2 |
2026/05/24 05:49 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c Name:shutdown]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:amd5536_udc_stop SourceFile:drivers/usb/gadget/udc/snps_udc_core.c SourceLine:1983]] TruncatedOutput:false]
|
| 26/2 |
2026/05/24 05:49 |
llm |
expert |
0m
Model:
Tokens:
input: 74593
output: 18
thoughts: 21
Thoughts: Okay, here's my thought process on that prompt, rendered as a first-person summary, keeping in mind I'm dealing with an expert audience:
**Debugging Strategy Evolved**
Alright, I'm at a point where I need to figure out what's going on. Instead of just wading blindly through the code, I need to be more strategic. Let's see...I should leverage my knowledge of the codebase and try a more targeted approach. Hmm, considering the context, the first thing that springs to mind is a potential shutdown sequence. Okay, a logical first step is a quick search for a function call related to `yealink_dev::shutdown`. That's the most likely culprit. If that doesn't immediately turn up anything, I'll fall back to a broader grep search within the relevant files. Gotta be efficient here. This initial targeted approach might shave off a ton of time, as opposed to a full code dive.
|
| 27/2 |
2026/05/24 05:49 |
tool |
grepper |
0m
Error:
Args: map[Expression:shutdown.*yealink]
Results:
|
| 28/2 |
2026/05/24 05:49 |
llm |
expert |
1m
Model:
Tokens:
input: 74844
output: 17
thoughts: 21
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:
**Investigating a Potential Shutdown Issue in the Yealink Driver**
Right, let's get down to brass tacks. I need to figure out what's going on with this Yealink driver, specifically concerning potential shutdown interactions. The most direct approach, as always, is to dive straight into the code. The logical first step is to use `grep`. I'm going to search the `drivers/input/misc/yealink.c` file for any instances of the term `shutdown`. I'm not just looking for a simple string match, mind you. I'm looking for *meaningful* occurrences; variable names, function calls, or comments that are *relevant* to power management or system shutdown procedures within the Yealink driver context. This will give me a quick overview of how the driver handles (or *doesn't* handle) shutdown events and, hopefully, quickly reveal any potential areas of concern for me to dig into. A quick `grep` will get the ball rolling, and I'll determine my course of action from there.
|
| 29/2 |
2026/05/24 05:50 |
tool |
grepper |
0m
Error:
Args: map[Expression:shutdown.*yld]
Results:
|
| 30/2 |
2026/05/24 05:50 |
llm |
expert |
0m
Model:
Tokens:
input: 75146
output: 26
thoughts: 23
Thoughts: Here's my thought process, as if I were thinking it:
**Investigating the Yealink Driver Shutdown Behavior**
Okay, so I'm trying to figure out how the Yealink driver, specifically within `drivers/input/misc/yealink.c`, handles shutdowns. I need to get a handle on what might be going on, especially if there are any subtle interactions with the broader system shutdown process. Therefore, I need to look for any specific code related to `shutdown` within that file. Grepping directly in this file is the most efficient way to achieve that goal. Itβs the fastest way to get a focused view of how the `yealink` driver, as it exists in the kernel, responds to a `shutdown` event.
|
| 31/2 |
2026/05/24 05:50 |
tool |
grepper |
0m
Error:
Args: map[Expression:shutdown.*drivers/input/misc/yealink.c]
Results:
|
| 32/2 |
2026/05/24 05:50 |
llm |
expert |
0m
Model:
Tokens:
input: 75366
output: 17
thoughts: 17
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Git Grep Conundrum**
Right, so I was just running a `git grep` and hit a bit of a snag. I was trying to refine my search with a more complex expression, thinking I could incorporate the filename directly within the search pattern itself, you know, something elegant like: `"my_pattern file:my_file.py"`. But then it hit me β `git grep`, at least as I understand it, doesn't actually allow for that kind of direct file-specific inclusion within the primary search expression. It seems to treat the filename argument as *separate* from the search term itself, acting more like a filter applied *after* the pattern matching. I could achieve the result I was looking for, but not in the way I was thinking. I'll need to re-evaluate the search strategy. This might mean leveraging other options, constructing the command differently, or possibly piping results. Back to the drawing board for a more efficient approach!
|
| 33/2 |
2026/05/24 05:50 |
tool |
grepper |
0m
Args: map[Expression:yld->shutdown]
Results: map[Output:drivers/input/misc/yealink.c=410=static void urb_irq_callback(struct urb *urb)
--
drivers/input/misc/yealink.c-438-
drivers/input/misc/yealink.c:439: if (!yld->shutdown) {
drivers/input/misc/yealink.c-440- ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
--
drivers/input/misc/yealink.c=448=static void urb_ctl_callback(struct urb *urb)
--
drivers/input/misc/yealink.c-460- /* ask for a response */
drivers/input/misc/yealink.c:461: if (!yld->shutdown)
drivers/input/misc/yealink.c-462- ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
--
drivers/input/misc/yealink.c-466- yealink_do_idle_tasks(yld);
drivers/input/misc/yealink.c:467: if (!yld->shutdown)
drivers/input/misc/yealink.c-468- ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
--
drivers/input/misc/yealink.c=529=static void input_close(struct input_dev *dev)
--
drivers/input/misc/yealink.c-532-
drivers/input/misc/yealink.c:533: yld->shutdown = 1;
drivers/input/misc/yealink.c-534- /*
--
drivers/input/misc/yealink.c-542-
drivers/input/misc/yealink.c:543: yld->shutdown = 0;
drivers/input/misc/yealink.c-544- smp_wmb();
]
|
| 34/2 |
2026/05/24 05:50 |
llm |
expert |
0m
Model:
Tokens:
input: 76101
output: 42
thoughts: 64
Thoughts: Okay, here's the summary, rendered as a first-person thought process, keeping in mind the user's expertise:
**The Shutdown Flag Conundrum**
Right, so `yld->shutdown` is *only* set to 1 in `input_close`. Okay, got it. That's a bit restrictive. It's *not* being set when the USB device is actually disconnected. Hmm, that's a potential vulnerability. What's the expected behavior during a disconnect scenario? My initial assumption was incorrect, apparently.
Let's dive into the `usb_disconnect` function. That seems like the logical place to start digging into this. Specifically, I should check the implementation within `drivers/input/misc/yealink.c`. I need to understand exactly what happens when the physical device is yanked from the system. I expect some sort of clean up to happen there. Time to inspect the relevant code.
|
| 35/2 |
2026/05/24 05:50 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:usb_disconnect]
Results: map[SourceCode: 839: static void usb_disconnect(struct usb_interface *intf)
840: {
841: struct yealink_dev *yld;
842:
843: down_write(&sysfs_rwsema);
844: yld = usb_get_intfdata(intf);
845: sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
846: usb_set_intfdata(intf, NULL);
847: up_write(&sysfs_rwsema);
848:
849: usb_cleanup(yld, 0);
850: }
SourceFile:drivers/input/misc/yealink.c]
|
| 36/2 |
2026/05/24 05:50 |
llm |
expert |
0m
Model:
Tokens:
input: 76620
output: 42
thoughts: 9
Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:
**Investigating `usb_cleanup`**
Right, let's dive into this. The initial thought here, as a seasoned professional, is to immediately check and see how the `usb_cleanup` function is handling things. It's the standard entry point, when dealing with USB device management so that's where I need to start. I'm thinking about the various resources it should be freeing, the potential race conditions it might be guarding against, and the overall reliability of the cleanup process. Let's see how well this is functioning.
|
| 37/2 |
2026/05/24 05:50 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:usb_cleanup]
Results: map[SourceCode: 816: static int usb_cleanup(struct yealink_dev *yld, int err)
817: {
818: if (yld == NULL)
819: return err;
820:
821: if (yld->idev) {
822: if (err)
823: input_free_device(yld->idev);
824: else
825: input_unregister_device(yld->idev);
826: }
827:
828: usb_free_urb(yld->urb_irq);
829: usb_free_urb(yld->urb_ctl);
830:
831: kfree(yld->ctl_req);
832: usb_free_coherent(yld->udev, USB_PKT_LEN, yld->ctl_data, yld->ctl_dma);
833: usb_free_coherent(yld->udev, USB_PKT_LEN, yld->irq_data, yld->irq_dma);
834:
835: kfree(yld);
836: return err;
837: }
SourceFile:drivers/input/misc/yealink.c]
|
| 38/2 |
2026/05/24 05:50 |
llm |
expert |
0m
Model:
Tokens:
input: 77168
output: 42
thoughts: 121
Thoughts: **Analyzing the USB Cleanup Process**
Okay, hold on a second! I'm tracing through this `usb_cleanup` function and I've hit a point where it calls `input_unregister_device(yld->idev)`. My immediate thought is, what's the consequence of that call? Specifically, does `input_unregister_device` trigger an `input_close` call?
Right, the documentation confirms it. `input_unregister_device` *does* call `input_close_device` if there are open file handles associated with the input device.
But then a new thought surfaces: what if there *aren't* any open handles? Does `input_close` get skipped in that scenario? The code path seems to suggest it would be.
Wait... if there are no open handles, isn't `yld->shutdown` already set to 1? That seems to be the intended behavior.
To be absolutely sure, I need to double-check the implementations of `input_open` and `input_close` and verify that the shutdown flag is set. That's the key to confirming this whole interaction.
|
| 39/2 |
2026/05/24 05:50 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:input_open]
Results: map[SourceCode: 501: static int input_open(struct input_dev *dev)
502: {
503: struct yealink_dev *yld = input_get_drvdata(dev);
504: int i, ret;
505:
506: dev_dbg(&yld->intf->dev, "%s\n", __func__);
507:
508: /* force updates to device */
509: for (i = 0; i<sizeof(yld->master); i++)
510: yld->copy.b[i] = ~yld->master.b[i];
511: yld->key_code = -1; /* no keys pressed */
512:
513: yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone));
514:
515: /* issue INIT */
516: memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
517: yld->ctl_data->cmd = CMD_INIT;
518: yld->ctl_data->size = 10;
519: yld->ctl_data->sum = 0x100-CMD_INIT-10;
520: if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
521: dev_dbg(&yld->intf->dev,
522: "%s - usb_submit_urb failed with result %d\n",
523: __func__, ret);
524: return ret;
525: }
526: return 0;
527: }
SourceFile:drivers/input/misc/yealink.c]
|
| 40/2 |
2026/05/24 05:50 |
llm |
expert |
0m
Model:
Tokens:
input: 78066
output: 42
thoughts: 29
Thoughts: Here's a summary of my immediate thought process, expressed in the first person, assuming I'm deeply familiar with USB driver internals:
**Investigating a USB Device Shutdown Sequence**
Okay, hold on a second... is `yld->shutdown` being initialized to zero within `usb_probe`? That seems potentially significant. I need to quickly verify that initialization point. Alright, let's dive back into the `usb_probe` function. This is critical to understanding the shutdown behaviour, and I need to make sure I haven't missed a crucial detail in its initialization. Let's see what's going on within `usb_probe`. I need to reconstruct the execution.
|
| 41/2 |
2026/05/24 05:50 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:usb_probe]
Results: map[SourceCode: 852: static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
853: {
854: struct usb_device *udev = interface_to_usbdev (intf);
855: struct driver_info *nfo = (struct driver_info *)id->driver_info;
856: struct usb_host_interface *interface;
857: struct usb_endpoint_descriptor *endpoint;
858: struct yealink_dev *yld;
859: struct input_dev *input_dev;
860: int ret, pipe, i;
861:
862: interface = intf->cur_altsetting;
863:
864: if (interface->desc.bNumEndpoints < 1)
865: return -ENODEV;
866:
867: endpoint = &interface->endpoint[0].desc;
868: if (!usb_endpoint_is_int_in(endpoint))
869: return -ENODEV;
870:
871: yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL);
872: if (!yld)
873: return -ENOMEM;
874:
875: yld->udev = udev;
876: yld->intf = intf;
877:
878: yld->idev = input_dev = input_allocate_device();
879: if (!input_dev)
880: return usb_cleanup(yld, -ENOMEM);
881:
882: /* allocate usb buffers */
883: yld->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
884: GFP_KERNEL, &yld->irq_dma);
885: if (yld->irq_data == NULL)
886: return usb_cleanup(yld, -ENOMEM);
887:
888: yld->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
889: GFP_KERNEL, &yld->ctl_dma);
890: if (!yld->ctl_data)
891: return usb_cleanup(yld, -ENOMEM);
892:
893: yld->ctl_req = kmalloc(sizeof(*(yld->ctl_req)), GFP_KERNEL);
894: if (yld->ctl_req == NULL)
895: return usb_cleanup(yld, -ENOMEM);
896:
897: /* allocate urb structures */
898: yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
899: if (yld->urb_irq == NULL)
900: return usb_cleanup(yld, -ENOMEM);
901:
902: yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
903: if (yld->urb_ctl == NULL)
904: return usb_cleanup(yld, -ENOMEM);
905:
906: /* get a handle to the interrupt data pipe */
907: pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
908: ret = usb_maxpacket(udev, pipe);
909: if (ret != USB_PKT_LEN)
910: dev_err(&intf->dev, "invalid payload size %d, expected %zd\n",
911: ret, USB_PKT_LEN);
912:
913: /* initialise irq urb */
914: usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
915: USB_PKT_LEN,
916: urb_irq_callback,
917: yld, endpoint->bInterval);
918: yld->urb_irq->transfer_dma = yld->irq_dma;
919: yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
920: yld->urb_irq->dev = udev;
921:
922: /* initialise ctl urb */
923: yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
924: USB_DIR_OUT;
925: yld->ctl_req->bRequest = USB_REQ_SET_CONFIGURATION;
926: yld->ctl_req->wValue = cpu_to_le16(0x200);
927: yld->ctl_req->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
928: yld->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN);
929:
930: usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
931: (void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
932: urb_ctl_callback, yld);
933: yld->urb_ctl->transfer_dma = yld->ctl_dma;
934: yld->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
935: yld->urb_ctl->dev = udev;
936:
937: /* find out the physical bus location */
938: usb_make_path(udev, yld->phys, sizeof(yld->phys));
939: strlcat(yld->phys, "/input0", sizeof(yld->phys));
940:
941: /* register settings for the input device */
942: input_dev->name = nfo->name;
943: input_dev->phys = yld->phys;
944: usb_to_input_id(udev, &input_dev->id);
945: input_dev->dev.parent = &intf->dev;
946:
947: input_set_drvdata(input_dev, yld);
948:
949: input_dev->open = input_open;
950: input_dev->close = input_close;
951: /* input_dev->event = input_ev; TODO */
952:
953: /* register available key events */
954: input_dev->evbit[0] = BIT_MASK(EV_KEY);
955: for (i = 0; i < 256; i++) {
956: int k = map_p1k_to_key(i);
957: if (k >= 0) {
958: set_bit(k & 0xff, input_dev->keybit);
959: if (k >> 8)
960: set_bit(k >> 8, input_dev->keybit);
961: }
962: }
963:
964: ret = input_register_device(yld->idev);
965: if (ret)
966: return usb_cleanup(yld, ret);
967:
968: usb_set_intfdata(intf, yld);
969:
970: /* clear visible elements */
971: for (i = 0; i < ARRAY_SIZE(lcdMap); i++)
972: setChar(yld, i, ' ');
973:
974: /* display driver version on LCD line 3 */
975: store_line3(&intf->dev, NULL,
976: DRIVER_VERSION, sizeof(DRIVER_VERSION));
977:
978: /* Register sysfs hooks (don't care about failure) */
979: ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
980: return 0;
981: }
SourceFile:drivers/input/misc/yealink.c]
|
| 42/2 |
2026/05/24 05:50 |
llm |
expert |
1m
Model:
Tokens:
input: 80549
output: 41
thoughts: 133
Thoughts: **Analyzing the USB Disconnect Flow**
Okay, hold on a second. I need to clarify something in the USB device disconnection sequence. It seems like `yld->shutdown` isn't explicitly set in the `usb_disconnect` function. That raises a concern: If a USB device is yanked out while it's still open, does that mean `input_close` isn't called immediately? But wait, I'm pretty sure `input_unregister_device` *does* take care of calling `input_close` if the device has open file descriptors. Let's trace it through. Right, `usb_disconnect` triggers `usb_cleanup(yld, 0)`. And `usb_cleanup` specifically calls `input_unregister_device(yld->idev)`. So, the question remains: will `input_unregister_device` call `input_close` if the device is currently in use? Time to dive into the code for `input_unregister_device` and confirm my assumptions.
|
| 43/2 |
2026/05/24 05:51 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/input.c IncludeLines:true Name:input_unregister_device]
Results: map[SourceCode:2494: /**
2495: * input_unregister_device - unregister previously registered device
2496: * @dev: device to be unregistered
2497: *
2498: * This function unregisters an input device. Once device is unregistered
2499: * the caller should not try to access it as it may get freed at any moment.
2500: */
2501: void input_unregister_device(struct input_dev *dev)
2502: {
2503: if (dev->devres_managed) {
2504: WARN_ON(devres_destroy(dev->dev.parent,
2505: devm_input_device_unregister,
2506: devm_input_device_match,
2507: dev));
2508: __input_unregister_device(dev);
2509: /*
2510: * We do not do input_put_device() here because it will be done
2511: * when 2nd devres fires up.
2512: */
2513: } else {
2514: __input_unregister_device(dev);
2515: input_put_device(dev);
2516: }
2517: }
SourceFile:drivers/input/input.c]
|
| 44/2 |
2026/05/24 05:51 |
llm |
expert |
0m
Model:
Tokens:
input: 81308
output: 42
thoughts: 12
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Diving into `__input_unregister_device`**
Right, let's get down to it. My immediate thought, as I see that function name, is that we're dealing with the core unregistration process for an input device. `__` implies this is an internal function, probably a lower-level routine. I'm expecting this to be the workhorse that handles all the gritty details of removing a device from the input subsystem. Things like deregistering character devices, freeing resources allocated during registration, maybe cleaning up any sysfs entries, and undoubtedly interacting with the core device lists and data structures within the kernel's input framework. I'll need to confirm if it has any lock contention in it, and how it handles potential race conditions with interrupt handlers and other device-related threads. My assumption is that it'll take the registered input device structure as an argument (likely a `struct input_dev` or similar) and perform a comprehensive tear-down. I'll be curious to see how robust the error handling is.
|
| 45/2 |
2026/05/24 05:52 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/input.c IncludeLines:true Name:__input_unregister_device]
Results: map[SourceCode:2287: static void __input_unregister_device(struct input_dev *dev)
2288: {
2289: struct input_handle *handle, *next;
2290:
2291: input_disconnect_device(dev);
2292:
2293: mutex_lock(&input_mutex);
2294:
2295: list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
2296: handle->handler->disconnect(handle);
2297: WARN_ON(!list_empty(&dev->h_list));
2298:
2299: del_timer_sync(&dev->timer);
2300: list_del_init(&dev->node);
2301:
2302: input_wakeup_procfs_readers();
2303:
2304: mutex_unlock(&input_mutex);
2305:
2306: device_del(&dev->dev);
2307: }
SourceFile:drivers/input/input.c]
|
| 46/2 |
2026/05/24 05:52 |
llm |
expert |
0m
Model:
Tokens:
input: 81911
output: 41
thoughts: 10
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience:
**Analyzing an Unfamiliar Term**
Hmm, `input_disconnect_device`... that's a bit unexpected. My initial reaction is a slight eyebrow raise. It's not a common term in my typical work, so I'm immediately running through my mental taxonomy of related concepts. Is this a custom function? Something specific to a particular framework or library? The naming convention feels vaguely familiar, but I can't quite place it off the top of my head. I'm already starting to consider the potential context: is it related to hardware interaction, perhaps low-level driver operations? Or maybe it's something higher-level, related to managing input events and device availability within an application or operating system? I'm picturing the layers of abstraction and trying to pinpoint where this piece might fit. I need to understand its function to work out why it's there.
|
| 47/2 |
2026/05/24 05:52 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/input.c IncludeLines:true Name:input_disconnect_device]
Results: map[SourceCode: 749: /*
750: * Prepare device for unregistering
751: */
752: static void input_disconnect_device(struct input_dev *dev)
753: {
754: struct input_handle *handle;
755:
756: /*
757: * Mark device as going away. Note that we take dev->mutex here
758: * not to protect access to dev->going_away but rather to ensure
759: * that there are no threads in the middle of input_open_device()
760: */
761: mutex_lock(&dev->mutex);
762: dev->going_away = true;
763: mutex_unlock(&dev->mutex);
764:
765: spin_lock_irq(&dev->event_lock);
766:
767: /*
768: * Simulate keyup events for all pressed keys so that handlers
769: * are not left with "stuck" keys. The driver may continue
770: * generate events even after we done here but they will not
771: * reach any handlers.
772: */
773: if (input_dev_release_keys(dev))
774: input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
775:
776: list_for_each_entry(handle, &dev->h_list, d_node)
777: handle->open = 0;
778:
779: spin_unlock_irq(&dev->event_lock);
780: }
SourceFile:drivers/input/input.c]
|
| 48/2 |
2026/05/24 05:52 |
llm |
expert |
0m
Model:
Tokens:
input: 82653
output: 43
thoughts: 1472
Thoughts: **UAF and RCU Stall Analysis**
Okay, let's break this down. First, `input_disconnect_device` doesn't call `dev->close()`, it just sets `handle->open` to 0. That means the driver's shutdown flag (`yld->shutdown`) isn't set, and the URBs are still running. Then, `usb_cleanup` is called. It frees the URBs using `usb_free_urb`, but that *doesn't* kill them, just decrements a ref count. `usb_disconnect` also doesn't explicitly call `usb_kill_urb`, so the URBs are left running, potentially forever.
Now, looking at `usb_cleanup` again:
```c
usb_free_urb(yld->urb_irq);
usb_free_urb(yld->urb_ctl);
```
No `usb_kill_urb` there. So, the URBs are left running and then `kfree(yld)` is called. If the URBs *do* complete, they're going to access freed memory, specifically `yld`. That's a classic use-after-free!
The bug report mentions an RCU stall. The error message shows an unexpected response (-71) from the URB. That suggests an issue before device disconnection. If `yld` were completely freed, `dev_err` would likely crash immediately, or at least show garbage. But it *prints* the device name (`yealink 3-1:36.0: ...`), meaning parts of `yld->intf->dev` are still valid. The reproducer just connects and disconnects a dummy USB device. When the process exits, `usb_disconnect` is called and then `usb_cleanup`, which frees `yld` and leaves running URBs that are accessing freed memory - a UAF!
Wait, but `dummy_hcd` might complete URBs synchronously during `usb_disconnect`? No, the `dummy_hcd` completes URBs in `dummy_timer`. Then, when a device is disconnected, `usb_hcd_flush_endpoint` is called and unlinks the URBs. During that unlinking, the status should be either `-ENOENT` or `-ESHUTDOWN`.
Let's look at `urb_ctl_callback` again:
```c
if (status)
dev_err(&yld->intf->dev, "%s - urb status %d\n",
__func__, status);
```
The status is `-71`. Why `-71` and not `-ENOENT` or `-ESHUTDOWN`? Because `dummy_hcd` returns `-EPROTO` for control requests if there is no endpoint configured, or if the setup stage fails.
In `dummy_timer`:
```c
ep = find_endpoint(dum, address);
if (!ep) {
/* set_configuration() disagreement */
dev_dbg(dummy_dev(dum_hcd),
"no ep configured for urb %p\n",
urb);
status = -EPROTO;
goto return_urb;
}
```
If the endpoint isn't configured, `dummy_hcd` returns `-EPROTO` (-71). The reproducer connects a device but doesn't configure an endpoint or the driver is submitting URBs to unconfigured endpoints.
Here's the likely scenario: The `yealink` driver submits `urb_ctl` and `urb_irq`. If the device is malicious and doesn't have the endpoints, `dummy_hcd` returns `-EPROTO`. `urb_ctl_callback` is called with `-71`. The error is printed, then the URB is resubmitted because `yld->shutdown` is still 0.
```c
if (!yld->shutdown)
ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
```
`usb_submit_urb` succeeds (because `dummy_hcd` accepts the URB) and then `dummy_timer` runs again, sees the URB, returns `-EPROTO`, and calls the callback. This creates an infinite loop, submitting, completing, printing, and submitting again. The messages are being printed every millisecond. The `dummy_timer` breaks if `urbp == dum_hcd->next_frame_urbp`, which means one URB per timer interrupt (1ms). Is that printing flood enough to cause an RCU stall?
Yes, a flood of printk calls, every millisecond can overwhelm the console. Because the timer is running from a hardirq, it can block the CPU and cause an R
|
| 49/2 |
2026/05/24 05:52 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/driver.c IncludeLines:true Name:usb_unbind_interface]
Results: map[SourceCode: 430: /* called from driver core with dev locked */
431: static int usb_unbind_interface(struct device *dev)
432: {
433: struct usb_driver *driver = to_usb_driver(dev->driver);
434: struct usb_interface *intf = to_usb_interface(dev);
435: struct usb_host_endpoint *ep, **eps = NULL;
436: struct usb_device *udev;
437: int i, j, error, r;
438: int lpm_disable_error = -ENODEV;
439:
440: intf->condition = USB_INTERFACE_UNBINDING;
441:
442: /* Autoresume for set_interface call below */
443: udev = interface_to_usbdev(intf);
444: error = usb_autoresume_device(udev);
445:
446: /* If hub-initiated LPM policy may change, attempt to disable LPM until
447: * the driver is unbound. If LPM isn't disabled, that's fine because it
448: * wouldn't be enabled unless all the bound interfaces supported
449: * hub-initiated LPM.
450: */
451: if (driver->disable_hub_initiated_lpm)
452: lpm_disable_error = usb_unlocked_disable_lpm(udev);
453:
454: /*
455: * Terminate all URBs for this interface unless the driver
456: * supports "soft" unbinding and the device is still present.
457: */
458: if (!driver->soft_unbind || udev->state == USB_STATE_NOTATTACHED)
459: usb_disable_interface(udev, intf, false);
460:
461: driver->disconnect(intf);
462:
463: /* Free streams */
464: for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
465: ep = &intf->cur_altsetting->endpoint[i];
466: if (ep->streams == 0)
467: continue;
468: if (j == 0) {
469: eps = kmalloc_array(USB_MAXENDPOINTS, sizeof(void *),
470: GFP_KERNEL);
471: if (!eps)
472: break;
473: }
474: eps[j++] = ep;
475: }
476: if (j) {
477: usb_free_streams(intf, eps, j, GFP_KERNEL);
478: kfree(eps);
479: }
480:
481: /* Reset other interface state.
482: * We cannot do a Set-Interface if the device is suspended or
483: * if it is prepared for a system sleep (since installing a new
484: * altsetting means creating new endpoint device entries).
485: * When either of these happens, defer the Set-Interface.
486: */
487: if (intf->cur_altsetting->desc.bAlternateSetting == 0) {
488: /* Already in altsetting 0 so skip Set-Interface.
489: * Just re-enable it without affecting the endpoint toggles.
490: */
491: usb_enable_interface(udev, intf, false);
492: } else if (!error && !intf->dev.power.is_prepared) {
493: r = usb_set_interface(udev, intf->altsetting[0].
494: desc.bInterfaceNumber, 0);
495: if (r < 0)
496: intf->needs_altsetting0 = 1;
497: } else {
498: intf->needs_altsetting0 = 1;
499: }
500: usb_set_intfdata(intf, NULL);
501:
502: intf->condition = USB_INTERFACE_UNBOUND;
503: intf->needs_remote_wakeup = 0;
504:
505: /* Attempt to re-enable USB3 LPM, if the disable succeeded. */
506: if (!lpm_disable_error)
507: usb_unlocked_enable_lpm(udev);
508:
509: /* Unbound interfaces are always runtime-PM-disabled and -suspended */
510: if (driver->supports_autosuspend)
511: pm_runtime_disable(dev);
512: pm_runtime_set_suspended(dev);
513:
514: if (!error)
515: usb_autosuspend_device(udev);
516:
517: return 0;
518: }
SourceFile:drivers/usb/core/driver.c]
|
| 50/2 |
2026/05/24 05:52 |
llm |
expert |
0m
Model:
Tokens:
input: 86619
output: 43
thoughts: 123
Thoughts: **My Analysis of the USB Interface Unbinding Process**
Okay, so I'm digging into this `usb_unbind_interface` function. Let me break down what's happening here. The code first checks if `driver->soft_unbind` is set, or if the USB device state is `USB_STATE_NOTATTACHED`. Crucially, for the `yealink` driver we're working with, `soft_unbind` is *not* set. This means the conditional will trigger the `usb_disable_interface` call.
The real kicker here is the *timing*. Because `usb_disable_interface` is called *before* `driver->disconnect(intf)`. And I know from experience, that `usb_disable_interface` is responsible for canceling *all* URBs associated with that specific interface. That's a pretty heavy-handed operation, potentially leading to issues depending on what the driver's disconnect function is relying on.
I need to confirm this assumption about `usb_disable_interface`, and I'm going to do that by examining that function's implementation right now. The sequence of operation is very important here.
|
| 51/2 |
2026/05/24 05:52 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/message.c IncludeLines:true Name:usb_disable_interface]
Results: map[SourceCode:1332: /**
1333: * usb_disable_interface -- Disable all endpoints for an interface
1334: * @dev: the device whose interface is being disabled
1335: * @intf: pointer to the interface descriptor
1336: * @reset_hardware: flag to erase any endpoint state stored in the
1337: * controller hardware
1338: *
1339: * Disables all the endpoints for the interface's current altsetting.
1340: */
1341: void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
1342: bool reset_hardware)
1343: {
1344: struct usb_host_interface *alt = intf->cur_altsetting;
1345: int i;
1346:
1347: for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
1348: usb_disable_endpoint(dev,
1349: alt->endpoint[i].desc.bEndpointAddress,
1350: reset_hardware);
1351: }
1352: }
SourceFile:drivers/usb/core/message.c]
|
| 52/2 |
2026/05/24 05:52 |
llm |
expert |
0m
Model:
Tokens:
input: 87375
output: 48
thoughts: 1732
Thoughts: **Analyzing the Yealink Driver Disconnect Sequence**
Okay, so here's what I'm seeing. `usb_disable_endpoint` eventually calls `usb_hcd_flush_endpoint`, which should cancel all URBs and wait for completion. The core of the issue seems to be how the `yealink` driver handles its URBs during disconnection. Specifically, it submits `urb_ctl` to endpoint 0 (the control endpoint) using `usb_fill_control_urb`. Now, that's where things get interesting. Endpoint 0 is *not* part of the interface's endpoints, and `usb_disable_interface` *only* disables the endpoints listed in `alt->endpoint`. Therefore, `urb_ctl` (on endpoint 0) isn't getting cancelled by `usb_disable_interface`!
This means `urb_ctl` can still be active or resubmitted even *after* `driver->disconnect(intf)` is called and the driver is being disconnected. And here's the kicker: `usb_disconnect` frees `yld`. So, if `urb_ctl` completes *after* `yld` is freed, its callback `urb_ctl_callback` is called, and this callback, running on a freed structure ( `yld`), tries to access it and potentially resubmit the URB. That's a textbook use-after-free scenario.
Let's double-check this: if `urb_ctl` goes to endpoint 0, it *won't* be cancelled by `usb_disable_interface`. Where else might it get cancelled? `usb_cleanup` in `yealink.c` calls `usb_free_urb(yld->urb_irq)` and `usb_free_urb(yld->urb_ctl)`. But, `usb_free_urb` *only* decrements the reference count. It doesn't actually cancel the URB! So, no, `urb_ctl` isn't ever explicitly cancelled.
Wait a second. What about `urb_irq`? That one goes to `endpoint->bEndpointAddress`, which is an interrupt endpoint. That endpoint *is* part of the interface, so `usb_disable_interface` *should* cancel it. `usb_hcd_flush_endpoint` should take care of that. BUT, `urb_ctl_callback` *can resubmit `urb_irq`*! If `urb_ctl_callback` executes *after* `usb_disable_interface`, it can resubmit!
Hang on. If the endpoint is disabled, `usb_submit_urb` will error out (likely with `-ENOENT` or `-EPFNOSUPPORT`). If that happens, `urb_ctl_callback` prints an error but it doesn't resubmit `urb_ctl`, and that would be fine. Okay, so in the case of a submit failure, it skips resubmitting `urb_ctl`. In that branch of the code (`CMD_KEYPRESS`), an error means no infinite loop. However, what if the `ctl_data->cmd` is not `CMD_KEYPRESS`? The code then calls `yealink_do_idle_tasks(yld)`. And if that function returns that there are changes, it submits `urb_ctl`, again to endpoint 0! Since endpoint 0 is *not* disabled, that URB might succeed! Then the cycle starts all over again! `urb_ctl` completes, calls `urb_ctl_callback`, which could resubmit `urb_ctl` again if there are updates.
However, if `yealink_do_idle_tasks` returns 0, the callback sets `yld->ctl_data->cmd = CMD_KEYPRESS`. The next time it runs, `urb_ctl_callback` will *only* submit `urb_irq`. If that fails, the whole loop stops. So this sequence seems to break out eventually. It will stop when it finally tries to submit `urb_irq` and that fails.
But wait. The bug report talks about an RCU stall, not a use-after-free. The report says, "rcu: INFO: rcu_preempt detected expedited stalls on CPUs/tasks" and shows the `yealink` driver reporting "unexpected response 0" and "-71" statuses. This means the problem isn't a direct use-after-free (yet). The looping is occurring BEFORE the device is truly disconnected, or at least it's *preventing* the disconnect from finishing (like if itβs running in a timer interrupt and starving the CPU, so the disconnect task cannot run).
Yes! The code is running inside `dummy_timer`, a timer interrupt β a hardirq. That interrupt is
|
| 53/2 |
2026/05/24 05:52 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c IncludeLines:true Name:dummy_timer]
Results: map[SourceCode:1777: /*
1778: * Drive both sides of the transfers; looks like irq handlers to both
1779: * drivers except that the callbacks are invoked from soft interrupt
1780: * context.
1781: */
1782: static enum hrtimer_restart dummy_timer(struct hrtimer *t)
1783: {
1784: struct dummy_hcd *dum_hcd = from_timer(dum_hcd, t, timer);
1785: struct dummy *dum = dum_hcd->dum;
1786: struct urbp *urbp, *tmp;
1787: unsigned long flags;
1788: int limit, total;
1789: int i;
1790:
1791: /* simplistic model for one frame's bandwidth */
1792: /* FIXME: account for transaction and packet overhead */
1793: switch (dum->gadget.speed) {
1794: case USB_SPEED_LOW:
1795: total = 8/*bytes*/ * 12/*packets*/;
1796: break;
1797: case USB_SPEED_FULL:
1798: total = 64/*bytes*/ * 19/*packets*/;
1799: break;
1800: case USB_SPEED_HIGH:
1801: total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
1802: break;
1803: case USB_SPEED_SUPER:
1804: /* Bus speed is 500000 bytes/ms, so use a little less */
1805: total = 490000;
1806: break;
1807: default: /* Can't happen */
1808: dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
1809: total = 0;
1810: break;
1811: }
1812:
1813: /* look at each urb queued by the host side driver */
1814: spin_lock_irqsave(&dum->lock, flags);
1815:
1816: if (!dum_hcd->udev) {
1817: dev_err(dummy_dev(dum_hcd),
1818: "timer fired with no URBs pending?\n");
1819: spin_unlock_irqrestore(&dum->lock, flags);
1820: return HRTIMER_NORESTART;
1821: }
1822: dum_hcd->next_frame_urbp = NULL;
1823:
1824: for (i = 0; i < DUMMY_ENDPOINTS; i++) {
1825: if (!ep_info[i].name)
1826: break;
1827: dum->ep[i].already_seen = 0;
1828: }
1829:
1830: restart:
1831: list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
1832: struct urb *urb;
1833: struct dummy_request *req;
1834: u8 address;
1835: struct dummy_ep *ep = NULL;
1836: int status = -EINPROGRESS;
1837:
1838: /* stop when we reach URBs queued after the timer interrupt */
1839: if (urbp == dum_hcd->next_frame_urbp)
1840: break;
1841:
1842: urb = urbp->urb;
1843: if (urb->unlinked)
1844: goto return_urb;
1845: else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1846: continue;
1847:
1848: /* Used up this frame's bandwidth? */
1849: if (total <= 0)
1850: continue;
1851:
1852: /* find the gadget's ep for this request (if configured) */
1853: address = usb_pipeendpoint (urb->pipe);
1854: if (usb_urb_dir_in(urb))
1855: address |= USB_DIR_IN;
1856: ep = find_endpoint(dum, address);
1857: if (!ep) {
1858: /* set_configuration() disagreement */
1859: dev_dbg(dummy_dev(dum_hcd),
1860: "no ep configured for urb %p\n",
1861: urb);
1862: status = -EPROTO;
1863: goto return_urb;
1864: }
1865:
1866: if (ep->already_seen)
1867: continue;
1868: ep->already_seen = 1;
1869: if (ep == &dum->ep[0] && urb->error_count) {
1870: ep->setup_stage = 1; /* a new urb */
1871: urb->error_count = 0;
1872: }
1873: if (ep->halted && !ep->setup_stage) {
1874: /* NOTE: must not be iso! */
1875: dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
1876: ep->ep.name, urb);
1877: status = -EPIPE;
1878: goto return_urb;
1879: }
1880: /* FIXME make sure both ends agree on maxpacket */
1881:
1882: /* handle control requests */
1883: if (ep == &dum->ep[0] && ep->setup_stage) {
1884: struct usb_ctrlrequest setup;
1885: int value;
1886:
1887: setup = *(struct usb_ctrlrequest *) urb->setup_packet;
1888: /* paranoia, in case of stale queued data */
1889: list_for_each_entry(req, &ep->queue, queue) {
1890: list_del_init(&req->queue);
1891: req->req.status = -EOVERFLOW;
1892: dev_dbg(udc_dev(dum), "stale req = %p\n",
1893: req);
1894:
1895: spin_unlock(&dum->lock);
1896: usb_gadget_giveback_request(&ep->ep, &req->req);
1897: spin_lock(&dum->lock);
1898: ep->already_seen = 0;
1899: goto restart;
1900: }
1901:
1902: /* gadget driver never sees set_address or operations
1903: * on standard feature flags. some hardware doesn't
1904: * even expose them.
1905: */
1906: ep->last_io = jiffies;
1907: ep->setup_stage = 0;
1908: ep->halted = 0;
1909:
1910: value = handle_control_request(dum_hcd, urb, &setup,
1911: &status);
1912:
1913: /* gadget driver handles all other requests. block
1914: * until setup() returns; no reentrancy issues etc.
1915: */
1916: if (value > 0) {
1917: ++dum->callback_usage;
1918: spin_unlock(&dum->lock);
1919: value = dum->driver->setup(&dum->gadget,
1920: &setup);
1921: spin_lock(&dum->lock);
1922: --dum->callback_usage;
1923:
1924: if (value >= 0) {
1925: /* no delays (max 64KB data stage) */
1926: limit = 64*1024;
1927: goto treat_control_like_bulk;
1928: }
1929: /* error, see below */
1930: }
1931:
1932: if (value < 0) {
1933: if (value != -EOPNOTSUPP)
1934: dev_dbg(udc_dev(dum),
1935: "setup --> %d\n",
1936: value);
1937: status = -EPIPE;
1938: urb->actual_length = 0;
1939: }
1940:
1941: goto return_urb;
1942: }
1943:
1944: /* non-control requests */
1945: limit = total;
1946: switch (usb_pipetype(urb->pipe)) {
1947: case PIPE_ISOCHRONOUS:
1948: /*
1949: * We don't support isochronous. But if we did,
1950: * here are some of the issues we'd have to face:
1951: *
1952: * Is it urb->interval since the last xfer?
1953: * Use urb->iso_frame_desc[i].
1954: * Complete whether or not ep has requests queued.
1955: * Report random errors, to debug drivers.
1956: */
1957: limit = max(limit, periodic_bytes(dum, ep));
1958: status = -EINVAL; /* fail all xfers */
1959: break;
1960:
1961: case PIPE_INTERRUPT:
1962: /* FIXME is it urb->interval since the last xfer?
1963: * this almost certainly polls too fast.
1964: */
1965: limit = max(limit, periodic_bytes(dum, ep));
1966: fallthrough;
1967:
1968: default:
1969: treat_control_like_bulk:
1970: ep->last_io = jiffies;
1971: total -= transfer(dum_hcd, urb, ep, limit, &status);
1972: break;
1973: }
1974:
1975: /* incomplete transfer? */
1976: if (status == -EINPROGRESS)
1977: continue;
1978:
1979: return_urb:
1980: list_del(&urbp->urbp_list);
1981: kfree(urbp);
1982: if (ep)
1983: ep->already_seen = ep->setup_stage = 0;
1984:
1985: usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
1986: spin_unlock(&dum->lock);
1987: usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
1988: spin_lock(&dum->lock);
1989:
1990: goto restart;
1991: }
1992:
1993: if (list_empty(&dum_hcd->urbp_list)) {
1994: usb_put_dev(dum_hcd->udev);
1995: dum_hcd->udev = NULL;
1996: } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1997: /* want a 1 msec delay here */
1998: hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
1999: }
2000:
2001: spin_unlock_irqrestore(&dum->lock, flags);
2002:
2003: return HRTIMER_NORESTART;
2004: }
SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]
|
| 54/2 |
2026/05/24 05:52 |
llm |
expert |
0m
Model:
Tokens:
input: 93600
output: 41
thoughts: 1048
Thoughts: **Analyzing the USB Driver Vulnerability**
Okay, let's break this down. It looks like `dummy_timer` has a flaw. It seems like the timer's behaviour hinges on `dum_hcd->next_frame_urbp`, which is only initialized in `dummy_urb_enqueue` if it's NULL. My initial thought is that if `urb_ctl_callback` submits `urb_irq`, then the `next_frame_urbp` will become `urb_irq`, and the timer will process one URB per millisecond. This initially seems slow, but now I understand it doesn't matter how often the timer ticks; the real problem is the sheer number of printks being generated within that timer.
One URB per millisecond isn't the issue; it's the 1000 printks per second that's causing the problem. That many printks can quickly overwhelm the serial console, since its bandwidth is low. The printk buffer fills, and `console_flush_all` begins spinning to flush to the slow serial console, and since `console_flush_all` is called from within a hardirq context, this leads to an RCU stall. We are essentially experiencing a Denial of Service attack caused by a flood of printks.
It appears to be a DoS, which means it can be exploited. The current reproducer uses `syz_usb_connect`, which, in turn, requires access to `/dev/raw-gadget`, which in most scenarios requires root privileges. This means that a standard user can't trigger this attack.
But now, a thought is forming - What if a malicious USB device could cause this? The `yealink` driver, or any USB driver, may be tricked into sending error codes from the HCD (e.g. xhci). A USB device can return an error for the `urb_ctl` and `urb_irq` URBs. The HCD then completes the URB with an error status, and the driver immediately resubmits the URB. If the HCD completes the resubmitted URB immediately β maybe because the endpoint is halted or the device has disconnected β a tight loop of submissions and completions could be established. The loop could be even tighter than our 1ms timer! This could flood the system with printks and URB submissions causing a CPU stall, which could be exploited, even with a normal user.
From what I can tell, it's not directly accessible from unprivileged processes unless they have access to `/dev/raw-gadget` (or similar), which they don't, but it can be triggered by plugging in a malicious USB device (Peripheral Trigger).
Let's do a memory corruption check: `usb_disconnect` doesn't cancel `urb_ctl` because it's on endpoint 0. Let's see... `usb_disable_interface` disables endpoints in `alt->endpoint`, but Endpoint 0 is the default control pipe, which is NOT in `alt->endpoint`. Therefore, `usb_disable_interface` does NOT disable endpoint 0. `usb_unbind_interface` only calls `usb_disable_interface` and the driver's disconnect function. But, if a device is physically disconnected, `usb_disconnect` is called for the device. And, the `usb_disconnect` function lives in `drivers/usb/core/hub.c`.
|
| 55/2 |
2026/05/24 05:53 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/hub.c IncludeLines:true Name:usb_disconnect]
Results: map[SourceCode:2257: /**
2258: * usb_disconnect - disconnect a device (usbcore-internal)
2259: * @pdev: pointer to device being disconnected
2260: *
2261: * Context: task context, might sleep
2262: *
2263: * Something got disconnected. Get rid of it and all of its children.
2264: *
2265: * If *pdev is a normal device then the parent hub must already be locked.
2266: * If *pdev is a root hub then the caller must hold the usb_bus_idr_lock,
2267: * which protects the set of root hubs as well as the list of buses.
2268: *
2269: * Only hub drivers (including virtual root hub drivers for host
2270: * controllers) should ever call this.
2271: *
2272: * This call is synchronous, and may not be used in an interrupt context.
2273: */
2274: void usb_disconnect(struct usb_device **pdev)
2275: {
2276: struct usb_port *port_dev = NULL;
2277: struct usb_device *udev = *pdev;
2278: struct usb_hub *hub = NULL;
2279: int port1 = 1;
2280:
2281: /* mark the device as inactive, so any further urb submissions for
2282: * this device (and any of its children) will fail immediately.
2283: * this quiesces everything except pending urbs.
2284: */
2285: usb_set_device_state(udev, USB_STATE_NOTATTACHED);
2286: dev_info(&udev->dev, "USB disconnect, device number %d\n",
2287: udev->devnum);
2288:
2289: /*
2290: * Ensure that the pm runtime code knows that the USB device
2291: * is in the process of being disconnected.
2292: */
2293: pm_runtime_barrier(&udev->dev);
2294:
2295: usb_lock_device(udev);
2296:
2297: hub_disconnect_children(udev);
2298:
2299: /* deallocate hcd/hardware state ... nuking all pending urbs and
2300: * cleaning up all state associated with the current configuration
2301: * so that the hardware is now fully quiesced.
2302: */
2303: dev_dbg(&udev->dev, "unregistering device\n");
2304: usb_disable_device(udev, 0);
2305: usb_hcd_synchronize_unlinks(udev);
2306:
2307: if (udev->parent) {
2308: port1 = udev->portnum;
2309: hub = usb_hub_to_struct_hub(udev->parent);
2310: port_dev = hub->ports[port1 - 1];
2311:
2312: sysfs_remove_link(&udev->dev.kobj, "port");
2313: sysfs_remove_link(&port_dev->dev.kobj, "device");
2314:
2315: /*
2316: * As usb_port_runtime_resume() de-references udev, make
2317: * sure no resumes occur during removal
2318: */
2319: if (!test_and_set_bit(port1, hub->child_usage_bits))
2320: pm_runtime_get_sync(&port_dev->dev);
2321:
2322: typec_deattach(port_dev->connector, &udev->dev);
2323: }
2324:
2325: usb_remove_ep_devs(&udev->ep0);
2326: usb_unlock_device(udev);
2327:
2328: /* Unregister the device. The device driver is responsible
2329: * for de-configuring the device and invoking the remove-device
2330: * notifier chain (used by usbfs and possibly others).
2331: */
2332: device_del(&udev->dev);
2333:
2334: /* Free the device number and delete the parent's children[]
2335: * (or root_hub) pointer.
2336: */
2337: release_devnum(udev);
2338:
2339: /* Avoid races with recursively_mark_NOTATTACHED() */
2340: spin_lock_irq(&device_state_lock);
2341: *pdev = NULL;
2342: spin_unlock_irq(&device_state_lock);
2343:
2344: if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits))
2345: pm_runtime_put(&port_dev->dev);
2346:
2347: hub_free_dev(udev);
2348:
2349: put_device(&udev->dev);
2350: }
SourceFile:drivers/usb/core/hub.c]
|
| 56/2 |
2026/05/24 05:53 |
llm |
expert |
0m
Model:
Tokens:
input: 96870
output: 43
thoughts: 105
Thoughts: **Dissecting the USB Disconnect Process**
Okay, so I'm looking at `usb_disconnect` for a USB device and I'm immediately noticing something that sets off alarm bells. First, it calls `usb_set_device_state(udev, USB_STATE_NOTATTACHED)`. Right, that makes sense on the surface, sets the device state to "not attached." But what are the *implications*? Ah, yes, itβll cause `usb_submit_urb` to bomb out with `-ENODEV` from now on. Fine, expected.
But *then*... it calls `usb_disable_device(udev, 0)`. Hold on. `usb_disable_device`... that's a *general* disabling function, right? It doesn't seem to be endpoint-specific. So, if I'm understanding this correctly, that disables *all* endpoints. Even endpoint *zero*! The control endpoint! That seems a little drastic, doesn't it? I need to double-check `usb_disable_device`. I want to see if my understanding of its scope is correct because disabling that endpoint seems... aggressive.
|
| 57/2 |
2026/05/24 05:53 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/usb/core/message.c IncludeLines:true Name:usb_disable_device]
Results: map[SourceCode:1382: /**
1383: * usb_disable_device - Disable all the endpoints for a USB device
1384: * @dev: the device whose endpoints are being disabled
1385: * @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
1386: *
1387: * Disables all the device's endpoints, potentially including endpoint 0.
1388: * Deallocates hcd/hardware state for the endpoints (nuking all or most
1389: * pending urbs) and usbcore state for the interfaces, so that usbcore
1390: * must usb_set_configuration() before any interfaces could be used.
1391: */
1392: void usb_disable_device(struct usb_device *dev, int skip_ep0)
1393: {
1394: int i;
1395:
1396: /* getting rid of interfaces will disconnect
1397: * any drivers bound to them (a key side effect)
1398: */
1399: if (dev->actconfig) {
1400: /*
1401: * FIXME: In order to avoid self-deadlock involving the
1402: * bandwidth_mutex, we have to mark all the interfaces
1403: * before unregistering any of them.
1404: */
1405: for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
1406: dev->actconfig->interface[i]->unregistering = 1;
1407:
1408: for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
1409: struct usb_interface *interface;
1410:
1411: /* remove this interface if it has been registered */
1412: interface = dev->actconfig->interface[i];
1413: if (!device_is_registered(&interface->dev))
1414: continue;
1415: dev_dbg(&dev->dev, "unregistering interface %s\n",
1416: dev_name(&interface->dev));
1417: remove_intf_ep_devs(interface);
1418: device_del(&interface->dev);
1419: }
1420:
1421: /* Now that the interfaces are unbound, nobody should
1422: * try to access them.
1423: */
1424: for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
1425: put_device(&dev->actconfig->interface[i]->dev);
1426: dev->actconfig->interface[i] = NULL;
1427: }
1428:
1429: usb_disable_usb2_hardware_lpm(dev);
1430: usb_unlocked_disable_lpm(dev);
1431: usb_disable_ltm(dev);
1432:
1433: dev->actconfig = NULL;
1434: if (dev->state == USB_STATE_CONFIGURED)
1435: usb_set_device_state(dev, USB_STATE_ADDRESS);
1436: }
1437:
1438: dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
1439: skip_ep0 ? "non-ep0" : "all");
1440:
1441: usb_disable_device_endpoints(dev, skip_ep0);
1442: }
SourceFile:drivers/usb/core/message.c]
|
| 58/2 |
2026/05/24 05:53 |
llm |
expert |
1m
Model:
Tokens:
input: 98275
output: 22
thoughts: 646
Thoughts: **My Analysis of a Potential USB Driver Bug**
Okay, let's break this down. It seems I've stumbled upon a potential race condition and use-after-free vulnerability within a USB driver, specifically during device disconnection. Here's what I'm seeing.
The `usb_disable_device` function, as part of the disconnection process, calls `device_del(&interface->dev)`. This triggers the driver unbinding sequence, which includes a call to the driver's `disconnect` function via `usb_unbind_interface`. My initial concern is that `driver->disconnect` is executed **during** `usb_disable_device`, specifically *before* endpoint 0 is disabled, which is managed later by `usb_disable_device_endpoints`.
Now, the driver's `disconnect` function, in this example (`yealink.c`), frees the `yld` structure which appears to store vital control data. The problem is, endpoint 0 might *still* be actively communicating through URBs (USB Request Blocks) before the endpoint is disabled. This is problematic because after `usb_set_device_state(udev, USB_STATE_NOTATTACHED)` is called, any attempts to submit new URBs will fail with `-ENODEV`. However, the URB might still be running.
The real kicker is the potential for a use-after-free. If a control URB, such as `urb_ctl`, completes *after* `yld` has been freed within the `disconnect` function, but *before* `usb_disable_device_endpoints` cancels it, the callback function `urb_ctl_callback` would be called. This callback, accessing `yld->ctl_data->cmd` and `yld->shutdown`, would be accessing freed memory β a clear use-after-free vulnerability.
Digging deeper, I see that the `usb_cleanup` function also frees `yld`, specifically:
```c
usb_free_urb(yld->urb_irq);
usb_free_urb(yld->urb_ctl);
kfree(yld->ctl_req);
usb_free_coherent(yld->udev, USB_PKT_LEN, yld->ctl_data, yld->ctl_dma);
usb_free_coherent(yld->udev, USB_PKT_LEN, yld->irq_data, yld->irq_dma);
kfree(yld);
```
This confirms that access to both `yld->ctl_data` and `yld` itself are dangerous after `usb_cleanup` is called.
Here's the critical point. `usb_free_urb` *doesn't* cancel the URB immediately. Furthermore, `usb_free_coherent` releases the DMA buffer associated with the URB. This leads to a classic DMA-after-free scenario! The HCD (Host Controller Driver) may continue writing to a freed DMA buffer if the URB is still running, which is a major security risk!
My focus now is on what's missing. The standard practice for USB drivers during disconnection involves calling `usb_kill_urb` within the `disconnect` function. This explicitly cancels all pending URBs. *This* driver, the `yealink` driver, appears to be missing these crucial calls. So I need to verify that.
|
| 59/2 |
2026/05/24 05:54 |
tool |
grepper |
0m
Error:
Args: map[Expression:usb_kill_urb.*yealink]
Results:
|
| 60/2 |
2026/05/24 05:54 |
llm |
expert |
0m
Model:
Tokens:
input: 99675
output: 30
thoughts: 25
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Investigating a Potential USB Issue in Yealink Input Drivers**
Right, let's dive into this. The initial impulse here is to get straight to the point. I need to figure out what's going on with this Yealink driver, likely related to USB handling. So, I'm thinking, "Let's grep." That's the go-to for rapid code investigation. The function name `usb_kill_urb` immediately flags a potential area of concern. Specifically, I'm expecting this to relate to some sort of USB transfer issue; perhaps timeouts, errors, or a need for cleanup. I'm going directly to `drivers/input/misc/yealink.c` because the keyword suggests that this is related to a particular driver implementation. That's the most logical place to begin digging for root causes. This search will likely pinpoint the specific lines responsible for USB communication and error handling, where the use of this function may indicate a point of failure or a potential resource management problem.
|
| 61/2 |
2026/05/24 05:54 |
tool |
grepper |
0m
Error:
Args: map[Expression:usb_kill_urb.*drivers/input/misc/yealink.c]
Results:
|
| 62/2 |
2026/05/24 05:54 |
llm |
expert |
0m
Model:
Tokens:
input: 99975
output: 19
thoughts: 25
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing the Yealink Driver**
Alright, so the initial plan is straightforward: I need to dig into the Yealink driver, specifically looking for how it handles USB communication. My instinct tells me that the function `usb_kill_urb` is a critical piece of the puzzle, likely used for canceling or stopping USB transfer requests. So, my immediate thought is to use `grep` β the quick and dirty, yet often effective, method β directly within the `yealink.c` file located in the `drivers/input/misc` directory. This will allow me to rapidly identify all instances where this function is called and understand the context around its usage. This will give me a first pass overview of the USB communications in the driver. From there, I can decide where to go and dive deeper into the code.
|
| 63/2 |
2026/05/24 05:54 |
tool |
grepper |
0m
Args: map[Expression:usb_kill_urb]
Results: map[Output:
Full output is too long, showing 500 out of 2605 lines.
Use more precise expression if possible.
[Documentation/driver-api/usb/URB.rst=175=returns; you must still wait for the completion handler to be called.
Documentation/driver-api/usb/URB.rst-176-
Documentation/driver-api/usb/URB.rst:177:To cancel an URB synchronously, call :c:func:`usb_kill_urb`::
Documentation/driver-api/usb/URB.rst-178-
Documentation/driver-api/usb/URB.rst:179: void usb_kill_urb(struct urb *urb)
Documentation/driver-api/usb/URB.rst-180-
--
Documentation/driver-api/usb/URB.rst=185=they will get a ``-EPERM`` error. Thus you can be sure that when
Documentation/driver-api/usb/URB.rst:186::c:func:`usb_kill_urb` returns, the URB is totally idle.
Documentation/driver-api/usb/URB.rst-187-
--
Documentation/driver-api/usb/URB.rst=189=time, and the completion handler may free the URB. If this happens
Documentation/driver-api/usb/URB.rst:190:while :c:func:`usb_unlink_urb` or :c:func:`usb_kill_urb` is running, it will
Documentation/driver-api/usb/URB.rst-191-cause a memory-access violation. The driver is responsible for avoiding this,
--
Documentation/driver-api/usb/URB.rst=198=is to increment the URB's reference count while holding the lock, then
Documentation/driver-api/usb/URB.rst:199:drop the lock and call usb_unlink_urb or usb_kill_urb, and then
Documentation/driver-api/usb/URB.rst-200-decrement the URB's reference count. You increment the reference
--
Documentation/driver-api/usb/anchors.rst=9=driver has to keep track of the URBs it has submitted
Documentation/driver-api/usb/anchors.rst:10:to know they've all completed or to call usb_kill_urb
Documentation/driver-api/usb/anchors.rst-11-for them. The anchor is a data structure takes care of
--
Documentation/driver-api/usb/power-management.rst=303=is optional. The methods' jobs are quite simple:
--
Documentation/driver-api/usb/power-management.rst-308- the driver will return 0, in which case it must cancel all
Documentation/driver-api/usb/power-management.rst:309: outstanding URBs (:c:func:`usb_kill_urb`) and not submit any more.
Documentation/driver-api/usb/power-management.rst-310-
--
drivers/bluetooth/bcm203x.c=233=static void bcm203x_disconnect(struct usb_interface *intf)
--
drivers/bluetooth/bcm203x.c-241-
drivers/bluetooth/bcm203x.c:242: usb_kill_urb(data->urb);
drivers/bluetooth/bcm203x.c-243-
--
drivers/bluetooth/bfusb.c=94=static void bfusb_unlink_urbs(struct bfusb_data *data)
--
drivers/bluetooth/bfusb.c-102- urb = ((struct bfusb_data_scb *) skb->cb)->urb;
drivers/bluetooth/bfusb.c:103: usb_kill_urb(urb);
drivers/bluetooth/bfusb.c-104- skb_queue_tail(&data->completed_q, skb);
--
drivers/bluetooth/btusb.c=1330=static void btusb_intr_complete(struct urb *urb)
--
drivers/bluetooth/btusb.c-1350- } else if (urb->status == -ENOENT) {
drivers/bluetooth/btusb.c:1351: /* Avoid suspend failed when usb_kill_urb */
drivers/bluetooth/btusb.c-1352- return;
--
drivers/bluetooth/btusb.c=1446=static void btusb_bulk_complete(struct urb *urb)
--
drivers/bluetooth/btusb.c-1466- } else if (urb->status == -ENOENT) {
drivers/bluetooth/btusb.c:1467: /* Avoid suspend failed when usb_kill_urb */
drivers/bluetooth/btusb.c-1468- return;
--
drivers/bluetooth/btusb.c=1535=static void btusb_isoc_complete(struct urb *urb)
--
drivers/bluetooth/btusb.c-1563- } else if (urb->status == -ENOENT) {
drivers/bluetooth/btusb.c:1564: /* Avoid suspend failed when usb_kill_urb */
drivers/bluetooth/btusb.c-1565- return;
--
drivers/bluetooth/btusb.c=1700=static void btusb_diag_complete(struct urb *urb)
--
drivers/bluetooth/btusb.c-1718- } else if (urb->status == -ENOENT) {
drivers/bluetooth/btusb.c:1719: /* Avoid suspend failed when usb_kill_urb */
drivers/bluetooth/btusb.c-1720- return;
--
drivers/bluetooth/btusb.c=2654=static void btusb_mtk_wmt_recv(struct urb *urb)
--
drivers/bluetooth/btusb.c-2706- } else if (urb->status == -ENOENT) {
drivers/bluetooth/btusb.c:2707: /* Avoid suspend failed when usb_kill_urb */
drivers/bluetooth/btusb.c-2708- return;
--
drivers/comedi/drivers/usbdux.c=206=static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs)
--
drivers/comedi/drivers/usbdux.c-210- for (i = 0; i < num_urbs; i++)
drivers/comedi/drivers/usbdux.c:211: usb_kill_urb(urbs[i]);
drivers/comedi/drivers/usbdux.c-212-}
--
drivers/comedi/drivers/usbdux.c=1117=static void usbduxsub_unlink_pwm_urbs(struct comedi_device *dev)
--
drivers/comedi/drivers/usbdux.c-1120-
drivers/comedi/drivers/usbdux.c:1121: usb_kill_urb(devpriv->pwm_urb);
drivers/comedi/drivers/usbdux.c-1122-}
--
drivers/comedi/drivers/usbduxfast.c=195=static int usbduxfast_ai_stop(struct comedi_device *dev, int do_unlink)
--
drivers/comedi/drivers/usbduxfast.c-203- /* kill the running transfer */
drivers/comedi/drivers/usbduxfast.c:204: usb_kill_urb(devpriv->urb);
drivers/comedi/drivers/usbduxfast.c-205- }
--
drivers/comedi/drivers/usbduxfast.c=980=static void usbduxfast_detach(struct comedi_device *dev)
--
drivers/comedi/drivers/usbduxfast.c-993- /* waits until a running transfer is over */
drivers/comedi/drivers/usbduxfast.c:994: usb_kill_urb(devpriv->urb);
drivers/comedi/drivers/usbduxfast.c-995-
--
drivers/comedi/drivers/usbduxsigma.c=169=static void usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs)
--
drivers/comedi/drivers/usbduxsigma.c-173- for (i = 0; i < num_urbs; i++)
drivers/comedi/drivers/usbduxsigma.c:174: usb_kill_urb(urbs[i]);
drivers/comedi/drivers/usbduxsigma.c-175-}
--
drivers/comedi/drivers/usbduxsigma.c=988=static void usbduxsigma_pwm_stop(struct comedi_device *dev, int do_unlink)
--
drivers/comedi/drivers/usbduxsigma.c-993- if (devpriv->pwm_urb)
drivers/comedi/drivers/usbduxsigma.c:994: usb_kill_urb(devpriv->pwm_urb);
drivers/comedi/drivers/usbduxsigma.c-995- }
--
drivers/gnss/usb.c=85=static void gnss_usb_close(struct gnss_device *gdev)
--
drivers/gnss/usb.c-88-
drivers/gnss/usb.c:89: usb_kill_urb(gusb->read_urb);
drivers/gnss/usb.c-90-}
--
drivers/greybus/es2.c=228=static int es2_cport_in_enable(struct es2_ap_dev *es2,
--
drivers/greybus/es2.c-250- urb = cport_in->urb[i];
drivers/greybus/es2.c:251: usb_kill_urb(urb);
drivers/greybus/es2.c-252- }
--
drivers/greybus/es2.c=257=static void es2_cport_in_disable(struct es2_ap_dev *es2,
--
drivers/greybus/es2.c-264- urb = cport_in->urb[i];
drivers/greybus/es2.c:265: usb_kill_urb(urb);
drivers/greybus/es2.c-266- }
--
drivers/greybus/es2.c=269=static int es2_arpc_in_enable(struct es2_ap_dev *es2)
--
drivers/greybus/es2.c-290- urb = es2->arpc_urb[i];
drivers/greybus/es2.c:291: usb_kill_urb(urb);
drivers/greybus/es2.c-292- }
--
drivers/greybus/es2.c=297=static void es2_arpc_in_disable(struct es2_ap_dev *es2)
--
drivers/greybus/es2.c-303- urb = es2->arpc_urb[i];
drivers/greybus/es2.c:304: usb_kill_urb(urb);
drivers/greybus/es2.c-305- }
--
drivers/greybus/es2.c=453=static void message_cancel(struct gb_message *message)
--
drivers/greybus/es2.c-476-
drivers/greybus/es2.c:477: usb_kill_urb(urb);
drivers/greybus/es2.c-478-
--
drivers/greybus/es2.c=773=static void es2_destroy(struct es2_ap_dev *es2)
--
drivers/greybus/es2.c-784- urb = es2->cport_out_urb[i];
drivers/greybus/es2.c:785: usb_kill_urb(urb);
drivers/greybus/es2.c-786- usb_free_urb(urb);
--
drivers/hid/hid-thrustmaster.c=260=static void thrustmaster_remove(struct hid_device *hdev)
--
drivers/hid/hid-thrustmaster.c-263-
drivers/hid/hid-thrustmaster.c:264: usb_kill_urb(tm_wheel->urb);
drivers/hid/hid-thrustmaster.c-265-
--
drivers/hid/hid-u2fzero.c=125=static int u2fzero_recv(struct u2fzero_device *dev,
--
drivers/hid/hid-u2fzero.c-156- if (ret == 0) {
drivers/hid/hid-u2fzero.c:157: usb_kill_urb(dev->urb);
drivers/hid/hid-u2fzero.c-158- hid_err(hdev, "urb submission timed out");
--
drivers/hid/usbhid/hid-core.c=737=static void usbhid_close(struct hid_device *hid)
--
drivers/hid/usbhid/hid-core.c-755- hid_cancel_delayed_stuff(usbhid);
drivers/hid/usbhid/hid-core.c:756: usb_kill_urb(usbhid->urbin);
drivers/hid/usbhid/hid-core.c-757- usbhid->intf->needs_remote_wakeup = 0;
--
drivers/hid/usbhid/hid-core.c=767=void usbhid_init_reports(struct hid_device *hid)
--
drivers/hid/usbhid/hid-core.c-786- if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
drivers/hid/usbhid/hid-core.c:787: usb_kill_urb(usbhid->urbctrl);
drivers/hid/usbhid/hid-core.c-788- if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
drivers/hid/usbhid/hid-core.c:789: usb_kill_urb(usbhid->urbout);
drivers/hid/usbhid/hid-core.c-790- ret = usbhid_wait_io(hid);
--
drivers/hid/usbhid/hid-core.c=1207=static void usbhid_stop(struct hid_device *hid)
--
drivers/hid/usbhid/hid-core.c-1235-
drivers/hid/usbhid/hid-core.c:1236: usb_kill_urb(usbhid->urbin);
drivers/hid/usbhid/hid-core.c:1237: usb_kill_urb(usbhid->urbout);
drivers/hid/usbhid/hid-core.c:1238: usb_kill_urb(usbhid->urbctrl);
drivers/hid/usbhid/hid-core.c-1239-
--
drivers/hid/usbhid/hid-core.c=1466=static void hid_cease_io(struct usbhid_device *usbhid)
--
drivers/hid/usbhid/hid-core.c-1468- del_timer_sync(&usbhid->io_retry);
drivers/hid/usbhid/hid-core.c:1469: usb_kill_urb(usbhid->urbin);
drivers/hid/usbhid/hid-core.c:1470: usb_kill_urb(usbhid->urbctrl);
drivers/hid/usbhid/hid-core.c:1471: usb_kill_urb(usbhid->urbout);
drivers/hid/usbhid/hid-core.c-1472-}
--
drivers/hid/usbhid/usbkbd.c=229=static void usb_kbd_close(struct input_dev *dev)
--
drivers/hid/usbhid/usbkbd.c-232-
drivers/hid/usbhid/usbkbd.c:233: usb_kill_urb(kbd->irq);
drivers/hid/usbhid/usbkbd.c-234-}
--
drivers/hid/usbhid/usbkbd.c=369=static void usb_kbd_disconnect(struct usb_interface *intf)
--
drivers/hid/usbhid/usbkbd.c-374- if (kbd) {
drivers/hid/usbhid/usbkbd.c:375: usb_kill_urb(kbd->irq);
drivers/hid/usbhid/usbkbd.c-376- input_unregister_device(kbd->dev);
drivers/hid/usbhid/usbkbd.c:377: usb_kill_urb(kbd->led);
drivers/hid/usbhid/usbkbd.c-378- usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
--
drivers/hid/usbhid/usbmouse.c=99=static void usb_mouse_close(struct input_dev *dev)
--
drivers/hid/usbhid/usbmouse.c-102-
drivers/hid/usbhid/usbmouse.c:103: usb_kill_urb(mouse->irq);
drivers/hid/usbhid/usbmouse.c-104-}
--
drivers/hid/usbhid/usbmouse.c=203=static void usb_mouse_disconnect(struct usb_interface *intf)
--
drivers/hid/usbhid/usbmouse.c-208- if (mouse) {
drivers/hid/usbhid/usbmouse.c:209: usb_kill_urb(mouse->irq);
drivers/hid/usbhid/usbmouse.c-210- input_unregister_device(mouse->dev);
--
drivers/hwmon/powerz.c=113=static int powerz_read_data(struct usb_device *udev, struct powerz_priv *priv)
--
drivers/hwmon/powerz.c-134- (&priv->completion, msecs_to_jiffies(5))) {
drivers/hwmon/powerz.c:135: usb_kill_urb(priv->urb);
drivers/hwmon/powerz.c-136- return -EIO;
--
drivers/hwmon/powerz.c=246=static void powerz_disconnect(struct usb_interface *intf)
--
drivers/hwmon/powerz.c-250- mutex_lock(&priv->mutex);
drivers/hwmon/powerz.c:251: usb_kill_urb(priv->urb);
drivers/hwmon/powerz.c-252- usb_free_urb(priv->urb);
--
drivers/input/joystick/iforce/iforce-usb.c=122=static void iforce_usb_stop_io(struct iforce *iforce)
--
drivers/input/joystick/iforce/iforce-usb.c-126-
drivers/input/joystick/iforce/iforce-usb.c:127: usb_kill_urb(iforce_usb->irq);
drivers/input/joystick/iforce/iforce-usb.c:128: usb_kill_urb(iforce_usb->out);
drivers/input/joystick/iforce/iforce-usb.c-129-}
--
drivers/input/joystick/pxrc.c=101=static void pxrc_close(struct input_dev *input)
--
drivers/input/joystick/pxrc.c-105- guard(mutex)(&pxrc->pm_mutex);
drivers/input/joystick/pxrc.c:106: usb_kill_urb(pxrc->urb);
drivers/input/joystick/pxrc.c-107- pxrc->is_open = false;
--
drivers/input/joystick/pxrc.c=204=static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
--
drivers/input/joystick/pxrc.c-209- if (pxrc->is_open)
drivers/input/joystick/pxrc.c:210: usb_kill_urb(pxrc->urb);
drivers/input/joystick/pxrc.c-211-
--
drivers/input/joystick/pxrc.c=226=static int pxrc_pre_reset(struct usb_interface *intf)
--
drivers/input/joystick/pxrc.c-230- mutex_lock(&pxrc->pm_mutex);
drivers/input/joystick/pxrc.c:231: usb_kill_urb(pxrc->urb);
drivers/input/joystick/pxrc.c-232- return 0;
--
drivers/input/joystick/xpad.c=1738=static int xpad_start_input(struct usb_xpad *xpad)
--
drivers/input/joystick/xpad.c-1747- if (error) {
drivers/input/joystick/xpad.c:1748: usb_kill_urb(xpad->irq_in);
drivers/input/joystick/xpad.c-1749- return error;
--
drivers/input/joystick/xpad.c=1777=static void xpad_stop_input(struct usb_xpad *xpad)
drivers/input/joystick/xpad.c-1778-{
drivers/input/joystick/xpad.c:1779: usb_kill_urb(xpad->irq_in);
drivers/input/joystick/xpad.c-1780-}
--
drivers/input/joystick/xpad.c=1812=static int xpad360w_start_input(struct usb_xpad *xpad)
--
drivers/input/joystick/xpad.c-1828- if (error) {
drivers/input/joystick/xpad.c:1829: usb_kill_urb(xpad->irq_in);
drivers/input/joystick/xpad.c-1830- return error;
--
drivers/input/joystick/xpad.c=1836=static void xpad360w_stop_input(struct usb_xpad *xpad)
drivers/input/joystick/xpad.c-1837-{
drivers/input/joystick/xpad.c:1838: usb_kill_urb(xpad->irq_in);
drivers/input/joystick/xpad.c-1839-
--
drivers/input/misc/ati_remote2.c=228=static int ati_remote2_submit_urbs(struct ati_remote2 *ar2)
--
drivers/input/misc/ati_remote2.c-239- if (r) {
drivers/input/misc/ati_remote2.c:240: usb_kill_urb(ar2->urb[0]);
drivers/input/misc/ati_remote2.c-241- dev_err(&ar2->intf[1]->dev,
--
drivers/input/misc/ati_remote2.c=249=static void ati_remote2_kill_urbs(struct ati_remote2 *ar2)
drivers/input/misc/ati_remote2.c-250-{
drivers/input/misc/ati_remote2.c:251: usb_kill_urb(ar2->urb[1]);
drivers/input/misc/ati_remote2.c:252: usb_kill_urb(ar2->urb[0]);
drivers/input/misc/ati_remote2.c-253-}
--
drivers/input/misc/cm109.c=515=static void cm109_stop_traffic(struct cm109_dev *dev)
--
drivers/input/misc/cm109.c-522-
drivers/input/misc/cm109.c:523: usb_kill_urb(dev->urb_ctl);
drivers/input/misc/cm109.c:524: usb_kill_urb(dev->urb_irq);
drivers/input/misc/cm109.c-525-
--
drivers/input/misc/ims-pcu.c=1590=static void ims_pcu_buffers_free(struct ims_pcu *pcu)
drivers/input/misc/ims-pcu.c-1591-{
drivers/input/misc/ims-pcu.c:1592: usb_kill_urb(pcu->urb_in);
drivers/input/misc/ims-pcu.c-1593- usb_free_urb(pcu->urb_in);
--
drivers/input/misc/ims-pcu.c-1599-
drivers/input/misc/ims-pcu.c:1600: usb_kill_urb(pcu->urb_ctrl);
drivers/input/misc/ims-pcu.c-1601- usb_free_urb(pcu->urb_ctrl);
--
drivers/input/misc/ims-pcu.c=1721=static int ims_pcu_start_io(struct ims_pcu *pcu)
--
drivers/input/misc/ims-pcu.c-1737- error);
drivers/input/misc/ims-pcu.c:1738: usb_kill_urb(pcu->urb_ctrl);
drivers/input/misc/ims-pcu.c-1739- return -EIO;
--
drivers/input/misc/ims-pcu.c=1745=static void ims_pcu_stop_io(struct ims_pcu *pcu)
drivers/input/misc/ims-pcu.c-1746-{
drivers/input/misc/ims-pcu.c:1747: usb_kill_urb(pcu->urb_in);
drivers/input/misc/ims-pcu.c:1748: usb_kill_urb(pcu->urb_ctrl);
drivers/input/misc/ims-pcu.c-1749-}
--
drivers/input/misc/keyspan_remote.c=416=static void keyspan_close(struct input_dev *dev)
--
drivers/input/misc/keyspan_remote.c-419-
drivers/input/misc/keyspan_remote.c:420: usb_kill_urb(remote->irq_urb);
drivers/input/misc/keyspan_remote.c-421-}
--
drivers/input/misc/keyspan_remote.c=558=static void keyspan_disconnect(struct usb_interface *interface)
--
drivers/input/misc/keyspan_remote.c-566- input_unregister_device(remote->input);
drivers/input/misc/keyspan_remote.c:567: usb_kill_urb(remote->irq_urb);
drivers/input/misc/keyspan_remote.c-568- usb_free_urb(remote->irq_urb);
--
drivers/input/misc/powermate.c=300=static int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id)
--
drivers/input/misc/powermate.c-408-
drivers/input/misc/powermate.c:409: fail5: usb_kill_urb(pm->irq);
drivers/input/misc/powermate.c-410- fail4: usb_free_urb(pm->config);
--
drivers/input/misc/powermate.c=419=static void powermate_disconnect(struct usb_interface *intf)
--
drivers/input/misc/powermate.c-425- pm->requires_update = 0;
drivers/input/misc/powermate.c:426: usb_kill_urb(pm->irq);
drivers/input/misc/powermate.c-427- input_unregister_device(pm->input);
drivers/input/misc/powermate.c:428: usb_kill_urb(pm->config);
drivers/input/misc/powermate.c-429- usb_free_urb(pm->irq);
--
drivers/input/misc/yealink.c=529=static void input_close(struct input_dev *dev)
--
drivers/input/misc/yealink.c-539-
drivers/input/misc/yealink.c:540: usb_kill_urb(yld->urb_ctl);
drivers/input/misc/yealink.c:541: usb_kill_urb(yld->urb_irq);
drivers/input/misc/yealink.c-542-
--
drivers/input/mouse/appletouch.c=807=static void atp_close(struct input_dev *input)
--
drivers/input/mouse/appletouch.c-810-
drivers/input/mouse/appletouch.c:811: usb_kill_urb(dev->urb);
drivers/input/mouse/appletouch.c-812- cancel_work_sync(&dev->work);
--
drivers/input/mouse/appletouch.c=942=static void atp_disconnect(struct usb_interface *iface)
--
drivers/input/mouse/appletouch.c-947- if (dev) {
drivers/input/mouse/appletouch.c:948: usb_kill_urb(dev->urb);
drivers/input/mouse/appletouch.c-949- input_unregister_device(dev->input);
--
drivers/input/mouse/appletouch.c=972=static int atp_suspend(struct usb_interface *iface, pm_message_t message)
--
drivers/input/mouse/appletouch.c-975-
drivers/input/mouse/appletouch.c:976: usb_kill_urb(dev->urb);
drivers/input/mouse/appletouch.c-977- return 0;
--
drivers/input/mouse/bcm5974.c=783=static int bcm5974_start_traffic(struct bcm5974 *dev)
--
drivers/input/mouse/bcm5974.c-805-err_kill_bt:
drivers/input/mouse/bcm5974.c:806: usb_kill_urb(dev->bt_urb);
drivers/input/mouse/bcm5974.c-807-err_reset_mode:
--
drivers/input/mouse/bcm5974.c=813=static void bcm5974_pause_traffic(struct bcm5974 *dev)
drivers/input/mouse/bcm5974.c-814-{
drivers/input/mouse/bcm5974.c:815: usb_kill_urb(dev->tp_urb);
drivers/input/mouse/bcm5974.c:816: usb_kill_urb(dev->bt_urb);
drivers/input/mouse/bcm5974.c-817- bcm5974_wellspring_mode(dev, false);
--
drivers/input/mouse/synaptics_usb.c=274=static void synusb_close(struct input_dev *dev)
--
drivers/input/mouse/synaptics_usb.c-281- mutex_lock(&synusb->pm_mutex);
drivers/input/mouse/synaptics_usb.c:282: usb_kill_urb(synusb->urb);
drivers/input/mouse/synaptics_usb.c-283- synusb->intf->needs_remote_wakeup = 0;
--
drivers/input/mouse/synaptics_usb.c=473=static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
--
drivers/input/mouse/synaptics_usb.c-477- mutex_lock(&synusb->pm_mutex);
drivers/input/mouse/synaptics_usb.c:478: usb_kill_urb(synusb->urb);
drivers/input/mouse/synaptics_usb.c-479- mutex_unlock(&synusb->pm_mutex);
--
drivers/input/mouse/synaptics_usb.c=501=static int synusb_pre_reset(struct usb_interface *intf)
--
drivers/input/mouse/synaptics_usb.c-505- mutex_lock(&synusb->pm_mutex);
drivers/input/mouse/synaptics_usb.c:506: usb_kill_urb(synusb->urb);
drivers/input/mouse/synaptics_usb.c-507-
--
drivers/input/tablet/acecad.c=104=static void usb_acecad_close(struct input_dev *dev)
--
drivers/input/tablet/acecad.c-107-
drivers/input/tablet/acecad.c:108: usb_kill_urb(acecad->irq);
drivers/input/tablet/acecad.c-109-}
--
drivers/input/tablet/aiptek.c=839=static void aiptek_close(struct input_dev *inputdev)
--
drivers/input/tablet/aiptek.c-842-
drivers/input/tablet/aiptek.c:843: usb_kill_urb(aiptek->urb);
drivers/input/tablet/aiptek.c-844-}
--
drivers/input/tablet/aiptek.c=1865=static void aiptek_disconnect(struct usb_interface *intf)
--
drivers/input/tablet/aiptek.c-1874- */
drivers/input/tablet/aiptek.c:1875: usb_kill_urb(aiptek->urb);
drivers/input/tablet/aiptek.c-1876- input_unregister_device(aiptek->inputdev);
--
drivers/input/tablet/hanwang.c=290=static void hanwang_close(struct input_dev *dev)
--
drivers/input/tablet/hanwang.c-293-
drivers/input/tablet/hanwang.c:294: usb_kill_urb(hanwang->irq);
drivers/input/tablet/hanwang.c-295-}
--
drivers/input/tablet/kbtab.c=102=static void kbtab_close(struct input_dev *dev)
--
drivers/input/tablet/kbtab.c-105-
drivers/input/tablet/kbtab.c:106: usb_kill_urb(kbtab->irq);
drivers/input/tablet/kbtab.c-107-}
--
drivers/input/tablet/pegasus_notetaker.c=217=static int pegasus_open(struct input_dev *dev)
--
drivers/input/tablet/pegasus_notetaker.c-241-err_kill_urb:
drivers/input/tablet/pegasus_notetaker.c:242: usb_kill_urb(pegasus->irq);
drivers/input/tablet/pegasus_notetaker.c-243- cancel_work_sync(&pegasus->init);
--
drivers/input/tablet/pegasus_notetaker.c=250=static void pegasus_close(struct input_dev *dev)
--
drivers/input/tablet/pegasus_notetaker.c-254- mutex_lock(&pegasus->pm_mutex);
drivers/input/tablet/pegasus_notetaker.c:255: usb_kill_urb(pegasus->irq);
drivers/input/tablet/pegasus_notetaker.c-256- cancel_work_sync(&pegasus->init);
--
drivers/input/tablet/pegasus_notetaker.c=410=static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
--
drivers/input/tablet/pegasus_notetaker.c-414- mutex_lock(&pegasus->pm_mutex);
drivers/input/tablet/pegasus_notetaker.c:415: usb_kill_urb(pegasus->irq);
drivers/input/tablet/pegasus_notetaker.c-416- cancel_work_sync(&pegasus->init);
--
drivers/input/touchscreen/usbtouchscreen.c=1035=static void nexio_exit(struct usbtouch_usb *usbtouch)
--
drivers/input/touchscreen/usbtouchscreen.c-1038-
drivers/input/touchscreen/usbtouchscreen.c:1039: usb_kill_urb(priv->ack);
drivers/input/touchscreen/usbtouchscreen.c-1040- usb_free_urb(priv->ack);
--
drivers/input/touchscreen/usbtouchscreen.c=1558=static void usbtouch_close(struct input_dev *input)
--
drivers/input/touchscreen/usbtouchscreen.c-1564- if (!usbtouch->type->irq_always)
drivers/input/touchscreen/usbtouchscreen.c:1565: usb_kill_urb(usbtouch->irq);
drivers/input/touchscreen/usbtouchscreen.c-1566- usbtouch->is_open = false;
--
drivers/input/touchscreen/usbtouchscreen.c=1575=static int usbtouch_suspend
--
drivers/input/touchscreen/usbtouchscreen.c-1579-
drivers/input/touchscreen/usbtouchscreen.c:1580: usb_kill_urb(usbtouch->irq);
drivers/input/touchscreen/usbtouchscreen.c-1581-
--
drivers/isdn/hardware/mISDN/hfcsusb.c=1746=release_hw(struct hfcsusb *hw)
--
drivers/isdn/hardware/mISDN/hfcsusb.c-1769- if (hw->ctrl_urb) {
drivers/isdn/hardware/mISDN/hfcsusb.c:1770: usb_kill_urb(hw->ctrl_urb);
drivers/isdn/hardware/mISDN/hfcsusb.c-1771- usb_free_urb(hw->ctrl_urb);
--
drivers/media/dvb-frontends/rtl2832_sdr.c=266=static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_dev *dev)
--
drivers/media/dvb-frontends/rtl2832_sdr.c-273- /* stop the URB */
drivers/media/dvb-frontends/rtl2832_sdr.c:274: usb_kill_urb(dev->urb_list[i]);
drivers/media/dvb-frontends/rtl2832_sdr.c-275- }
--
drivers/media/radio/si470x/radio-si470x-usb.c=563=static int si470x_usb_driver_probe(struct usb_interface *intf,
--
drivers/media/radio/si470x/radio-si470x-usb.c-747-err_all:
drivers/media/radio/si470x/radio-si470x-usb.c:748: usb_kill_urb(radio->int_in_urb);
drivers/media/radio/si470x/radio-si470x-usb.c-749-err_buf:
--
drivers/media/radio/si470x/radio-si470x-usb.c=771=static int si470x_usb_driver_suspend(struct usb_interface *intf,
--
drivers/media/radio/si470x/radio-si470x-usb.c-781- if (radio->int_in_urb)
drivers/media/radio/si470x/radio-si470x-usb.c:782: usb_kill_urb(radio->int_in_urb);
drivers/media/radio/si470x/radio-si470x-usb.c-783- }
--
drivers/media/radio/si470x/radio-si470x-usb.c=816=static void si470x_usb_driver_disconnect(struct usb_interface *intf)
--
drivers/media/radio/si470x/radio-si470x-usb.c-822- video_unregister_device(&radio->videodev);
drivers/media/radio/si470x/radio-si470x-usb.c:823: usb_kill_urb(radio->int_in_urb);
drivers/media/radio/si470x/radio-si470x-usb.c-824- usb_set_intfdata(intf, NULL);
--
drivers/media/rc/ati_remote.c=346=static void ati_remote_close(struct ati_remote *ati_remote)
--
drivers/media/rc/ati_remote.c-349- if (--ati_remote->users == 0)
drivers/media/rc/ati_remote.c:350: usb_kill_urb(ati_remote->irq_urb);
drivers/media/rc/ati_remote.c-351- mutex_unlock(&ati_remote->open_mutex);
--
drivers/media/rc/ati_remote.c=401=static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd,
]
]
|
| 64/2 |
2026/05/24 05:54 |
llm |
expert |
0m
Model:
Tokens:
input: 110689
output: 42
thoughts: 163
Thoughts: **Yealink USB Driver Deep Dive**
Okay, so I'm digging into this Yealink driver, and it looks like `yealink.c` *does* indeed call `usb_kill_urb`! Specifically, line 540 and 541 within the `input_close` function. That's a key detail for managing USB URBs.
Wait, hold on a second! I need to confirm that. Let me double-check that `input_close` function in `yealink.c` to make absolutely sure. Gotta be thorough.
|
| 65/2 |
2026/05/24 05:54 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:input_close]
Results: map[SourceCode: 529: static void input_close(struct input_dev *dev)
530: {
531: struct yealink_dev *yld = input_get_drvdata(dev);
532:
533: yld->shutdown = 1;
534: /*
535: * Make sure the flag is seen by other CPUs before we start
536: * killing URBs so new URBs won't be submitted
537: */
538: smp_wmb();
539:
540: usb_kill_urb(yld->urb_ctl);
541: usb_kill_urb(yld->urb_irq);
542:
543: yld->shutdown = 0;
544: smp_wmb();
545: }
SourceFile:drivers/input/misc/yealink.c]
|
| 66/2 |
2026/05/24 05:54 |
llm |
expert |
1m
Model:
Tokens:
input: 111278
output: 41
thoughts: 556
Thoughts: **Analyzing USB Device Shutdown Logic**
Okay, so I'm digging into this code and trying to understand how this Yealink USB device handles shutdown. First, `input_close` sets the `yld->shutdown` flag to 1, then kills the URBs with `usb_kill_urb`. But then, *immediately* it sets `yld->shutdown` back to 0. That seems... odd.
I realize that `input_close` is triggered during `usb_disconnect` β specifically via `input_unregister_device` β which would kill those URBs. But then I have to remember that `input_close` only runs *if* the device was opened. Hmmm, if the device was *never* opened, does `input_close` ever get called? If not, are the URBs even submitted if the device is never opened?
Let me look at `usb_probe` in `yealink.c`. Ah, there we go. It initializes the control URB (`yld->urb_ctl`). It sets up the request type, value, index, length... it even fills the control URB with `usb_fill_control_urb`.
However, is it submitted? It *initializes* the URBs, but I don't see an explicit `usb_submit_urb` in `usb_probe`. I need to be sure. Wait! `input_open` submits `urb_ctl`: `if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0)`. Okay, so at least *one* of the URBs *is* submitted during the `input_open` call!
But, I think there is more to it... I should check `usb_probe` again. Let me review `usb_probe`... Okay, now it's clear, they do `setChar` and `store_line3` after, and these might also submit URBs! I'll need to check those functions to ensure the device handles all USB calls appropriately.
|
| 67/2 |
2026/05/24 05:56 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:setChar]
Results: map[SourceCode: 125: /* Display a char,
126: * char '\9' and '\n' are placeholders and do not overwrite the original text.
127: * A space will always hide an icon.
128: */
129: static int setChar(struct yealink_dev *yld, int el, int chr)
130: {
131: int i, a, m, val;
132:
133: if (el >= ARRAY_SIZE(lcdMap))
134: return -EINVAL;
135:
136: if (chr == '\t' || chr == '\n')
137: return 0;
138:
139: yld->lcdMap[el] = chr;
140:
141: if (lcdMap[el].type == '.') {
142: a = lcdMap[el].u.p.a;
143: m = lcdMap[el].u.p.m;
144: if (chr != ' ')
145: yld->master.b[a] |= m;
146: else
147: yld->master.b[a] &= ~m;
148: return 0;
149: }
150:
151: val = map_to_seg7(&map_seg7, chr);
152: for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) {
153: m = lcdMap[el].u.s[i].m;
154:
155: if (m == 0)
156: continue;
157:
158: a = lcdMap[el].u.s[i].a;
159: if (val & 1)
160: yld->master.b[a] |= m;
161: else
162: yld->master.b[a] &= ~m;
163: val = val >> 1;
164: }
165: return 0;
166: };
SourceFile:drivers/input/misc/yealink.c]
|
| 68/2 |
2026/05/24 05:56 |
llm |
expert |
0m
Model:
Tokens:
input: 112942
output: 43
thoughts: 30
Thoughts: Okay, here's my take on those thoughts, framed as my own mental processing as an expert:
**Internal Review of USB Character Handling**
Right, so `setChar` is just manipulating the `yld->master` structure. That's good, it makes sense as an initial stage. The crucial thing is that it *doesn't* appear to trigger any actual URB submission. We need to confirm that that's the correct approach for the USB character handling - this would mean that the URBs are being handled elsewhere.
Therefore, let's immediately check `store_line3`. That's where I expect the actual data transfer to the USB device to be initiated, if `setChar` is only setting a 'character' in some buffer, or some other such thing. I expect to confirm this with the debugging.
|
| 69/2 |
2026/05/24 05:56 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:store_line3]
Results: map[SourceCode: 664: static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
665: const char *buf, size_t count)
666: {
667: return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE);
668: }
SourceFile:drivers/input/misc/yealink.c]
|
| 70/2 |
2026/05/24 05:56 |
llm |
expert |
0m
Model:
Tokens:
input: 113316
output: 42
thoughts: 9
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Initial Assessment: Verifying Data Storage**
Right, let's take a look at `store_line`. It's crucial, obviously. This variable or function, depending on context, likely represents the core mechanism for⦠well, storing a line of data. My initial thought is to quickly mentally run through the potential bottlenecks. Is it a variable holding a string, a list, or maybe a database call? The name suggests it's related to some kind of persistent storage, which implies further questions: Is there error handling? What's the storage medium? Are we talking about a simple file write, or a more sophisticated approach like a queue with retry mechanisms? Context is everything. I need to understand its role in the greater architecture, particularly the data input, processing, and output pipelines. I'll need to consider performance implications, concurrency issues if applicable, and potential security vulnerabilities related to data persistence. A cursory glance at the surrounding code should provide some context.
|
| 71/2 |
2026/05/24 05:56 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:store_line]
Results: map[SourceCode: 623: /* Writing to /sys/../lineX will set the coresponding LCD line.
624: * - Excess characters are ignored.
625: * - If less characters are written than allowed, the remaining digits are
626: * unchanged.
627: * - The '\n' or '\t' char is a placeholder, it does not overwrite the
628: * original content.
629: */
630: static ssize_t store_line(struct device *dev, const char *buf, size_t count,
631: int el, size_t len)
632: {
633: struct yealink_dev *yld;
634: int i;
635:
636: down_write(&sysfs_rwsema);
637: yld = dev_get_drvdata(dev);
638: if (yld == NULL) {
639: up_write(&sysfs_rwsema);
640: return -ENODEV;
641: }
642:
643: if (len > count)
644: len = count;
645: for (i = 0; i < len; i++)
646: setChar(yld, el++, buf[i]);
647:
648: up_write(&sysfs_rwsema);
649: return count;
650: }
SourceFile:drivers/input/misc/yealink.c]
|
| 72/2 |
2026/05/24 05:56 |
llm |
expert |
1m
Model:
Tokens:
input: 114026
output: 41
thoughts: 2342
Thoughts: **My Analysis of the USB Driver Vulnerability**
Okay, so I'm following this logic, trying to understand how this bug works. It seems that `store_line` calls `setChar`, which updates `yld->master`, but doesn't submit any URBs itself. That means `usb_probe` also doesn't submit URBs, and it's only in `input_open` that URBs are submitted. If this is the case, the device *must* be opened to trigger the bug. I see that `syz_usb_connect` creates a dummy USB device. The question is, does syzkaller open the input device? The reproducer doesn't seem to open the input device explicitly. If the reproducer doesn't open the input device, how are URBs submitted?
Aha! It's likely that a userspace daemon like `systemd-udevd`, `Xorg`, `Wayland`, or `libinput` automatically opens new input devices to probe them. So, the URBs *are* submitted because a userspace daemon is opening the device. When the daemon opens the device, `input_open` is called, which submits `urb_ctl`. This `urb_ctl` completes immediately with `-71` because the dummy HCD returns `-EPROTO` for unconfigured endpoints. Then, the `urb_ctl_callback` is called, and *that* submits `urb_irq`. `urb_irq` also completes immediately with `-71`. Boom, we have an infinite loop! This infinite loop in `dummy_timer` causes an RCU stall. If the device is opened, userspace opens and closes the device, but if the CPU is stalled in `dummy_timer`, the daemon may not be able to close it.
What if we consider a real USB device, a malicious one, maybe a Facedancer, that can return an error for the URBs? The HCD, say xhci, will complete the URB with an error. The `yealink` driver will resubmit the URB. If the HCD completes the resubmitted URB immediately β maybe because the endpoint is halted or the device is disconnected β we'd still get a tight loop.
If xhci is the HCD, does it complete URBs immediately if the endpoint is halted? Yes, if the endpoint is halted, `usb_submit_urb` might succeed but the HCD will immediately complete it with `-EPIPE` in an interrupt handler or tasklet. If the HCD completes the URB in a tasklet, the tasklet will call `urb_ctl_callback`, which will resubmit the URB. The resubmitted URB will be queued, then the tasklet will process the next URB and complete it with `-EPIPE` again. This also would cause an infinite loop in the tasklet, and, boom, another RCU stall.
So, a malicious USB device *can* cause an RCU stall (Denial of Service) by simply halting the endpoint or continuously returning errors. This is a Peripheral Trigger DoS.
Now, the use-after-free... Let's re-evaluate. If the device is disconnected, `usb_disconnect` is called. `usb_disconnect` calls `usb_disable_device`, which unbinds the driver. The driver's `disconnect` function (`usb_cleanup`) frees `yld`. But `urb_ctl` is on endpoint 0, which is *not* disabled before `driver->disconnect`! Wait, `usb_disable_device` calls `device_del(&interface->dev)`. `device_del` calls `bus_remove_device`, which calls `device_release_driver`, which calls `usb_unbind_interface`. `usb_unbind_interface` calls `usb_disable_interface`, which disables the interface endpoints (but NOT endpoint 0). Then it calls `driver->disconnect(intf)`. `driver->disconnect` is `usb_disconnect` in `yealink.c`. `usb_disconnect` calls `usb_cleanup`, which frees `yld`.
At this point, `urb_ctl` is STILL running or queued in the HCD! Because endpoint 0 was NOT disabled! After `driver->disconnect` returns, `usb_disable_device` continues and calls `usb_disable_device_endpoints(dev, skip_ep0)`. `skip_ep0` is 0, so it disables endpoint 0! When endpoint 0 is disabled, `usb_hcd_flush_endpoint` is called for endpoint 0. This cancels `urb_ctl` and waits for it to complete. When it completes, `urb_ctl_callback` is called. `urb_ctl_callback` accesses `yld->ctl_data->cmd` and `yld
|
| 73/2 |
2026/05/24 05:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/input.c IncludeLines:true Name:input_disconnect_device]
Results: map[SourceCode: 749: /*
750: * Prepare device for unregistering
751: */
752: static void input_disconnect_device(struct input_dev *dev)
753: {
754: struct input_handle *handle;
755:
756: /*
757: * Mark device as going away. Note that we take dev->mutex here
758: * not to protect access to dev->going_away but rather to ensure
759: * that there are no threads in the middle of input_open_device()
760: */
761: mutex_lock(&dev->mutex);
762: dev->going_away = true;
763: mutex_unlock(&dev->mutex);
764:
765: spin_lock_irq(&dev->event_lock);
766:
767: /*
768: * Simulate keyup events for all pressed keys so that handlers
769: * are not left with "stuck" keys. The driver may continue
770: * generate events even after we done here but they will not
771: * reach any handlers.
772: */
773: if (input_dev_release_keys(dev))
774: input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
775:
776: list_for_each_entry(handle, &dev->h_list, d_node)
777: handle->open = 0;
778:
779: spin_unlock_irq(&dev->event_lock);
780: }
SourceFile:drivers/input/input.c]
|
| 74/2 |
2026/05/24 05:57 |
llm |
expert |
0m
Model:
Tokens:
input: 117924
output: 41
thoughts: 180
Thoughts: **Dissecting the Device Disconnect Flow**
Okay, so I'm looking at this `input_disconnect_device` function, and it's suddenly struck me: wait a minute, it *doesn't* actually call `dev->close()`! That was a crucial oversight on my part. I need to be absolutely sure about the device teardown sequence.
So, the next question is: Does `__input_unregister_device` handle the `dev->close()` call? Let me quickly scan that function... Aha, no, it looks like that's not the primary function of `__input_unregister_device`. It calls `input_disconnect_device` first, then iterates through the handles using `list_for_each_entry_safe`. And what does it do in that loop? It calls `handle->handler->disconnect(handle)`.
Right, that makes sense. Each handler attached to the input device, like the `evdev` handler, gets a chance to clean up its own resources. Let me make sure I'm following. The call to `handle->handler->disconnect(handle)` is key here.
Now, which is the call for `evdev_disconnect`? I'm going to quickly check how `evdev` handles device disconnection. Let's dig into the `evdev_disconnect` function and see what's actually happening on the handler side. This is crucial for ensuring a complete and clean device teardown.
|
| 75/2 |
2026/05/24 05:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/evdev.c IncludeLines:true Name:evdev_disconnect]
Results: map[SourceCode:1402: static void evdev_disconnect(struct input_handle *handle)
1403: {
1404: struct evdev *evdev = handle->private;
1405:
1406: cdev_device_del(&evdev->cdev, &evdev->dev);
1407: evdev_cleanup(evdev);
1408: input_free_minor(MINOR(evdev->dev.devt));
1409: input_unregister_handle(handle);
1410: put_device(&evdev->dev);
1411: }
SourceFile:drivers/input/evdev.c]
|
| 76/2 |
2026/05/24 05:57 |
llm |
expert |
1m
Model:
Tokens:
input: 118643
output: 42
thoughts: 26
Thoughts: Here's a summary of my thought process:
**Diving into the evdev Shutdown Sequence**
Okay, so `evdev_cleanup` triggers `evdev_hangup`. My immediate reaction is to go straight to the `evdev_hangup` function. Understanding how it handles the shutdown sequence is crucial. I need to see what steps are being taken during the cleanup process, how resources are released, and if there are any potential race conditions or resource leaks within that function. Time to analyze.
|
| 77/2 |
2026/05/24 05:58 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/evdev.c IncludeLines:true Name:evdev_hangup]
Results: map[SourceCode: 419: /*
420: * Wake up users waiting for IO so they can disconnect from
421: * dead device.
422: */
423: static void evdev_hangup(struct evdev *evdev)
424: {
425: struct evdev_client *client;
426:
427: spin_lock(&evdev->client_lock);
428: list_for_each_entry(client, &evdev->client_list, node) {
429: kill_fasync(&client->fasync, SIGIO, POLL_HUP);
430: wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
431: }
432: spin_unlock(&evdev->client_lock);
433: }
SourceFile:drivers/input/evdev.c]
|
| 78/2 |
2026/05/24 05:58 |
llm |
expert |
0m
Model:
Tokens:
input: 119080
output: 41
thoughts: 227
Thoughts: **The Disconnect Dilemma: A USB Use-After-Free**
Okay, hold on a second. I just realized something critical: `evdev_disconnect` *doesn't* actually call `input_close_device`! That function is only triggered when the *last* user releases the file descriptor through `evdev_release`. But if a device is disconnected, that file descriptor might still be sitting open, right? And if the file descriptor is open during a disconnection, then `input_close_device` *isn't* called within the `usb_disconnect` process.
Okay, let's play this out... If `input_close_device` isn't called during `usb_disconnect`, then that means `dev->close` β which I believe maps to `input_close` in `yealink.c` β *also* isn't called. And if `input_close` *isn't* called, then `usb_kill_urb` doesn't happen. Critically, `usb_cleanup` is responsible for freeing `yld`. So, `usb_disable_device_endpoints` is going to cancel `urb_ctl`, and then `urb_ctl_callback` is going to be invoked. The problem here is that `urb_ctl_callback` will attempt to access `yld`... *which has already been freed*!
We have a use-after-free situation, right here! I need to double-check `evdev_release` now to make sure I haven't missed something there.
|
| 79/2 |
2026/05/24 05:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/evdev.c IncludeLines:true Name:evdev_release]
Results: map[SourceCode: 435: static int evdev_release(struct inode *inode, struct file *file)
436: {
437: struct evdev_client *client = file->private_data;
438: struct evdev *evdev = client->evdev;
439: unsigned int i;
440:
441: mutex_lock(&evdev->mutex);
442:
443: if (evdev->exist && !client->revoked)
444: input_flush_device(&evdev->handle, file);
445:
446: evdev_ungrab(evdev, client);
447: mutex_unlock(&evdev->mutex);
448:
449: evdev_detach_client(evdev, client);
450:
451: for (i = 0; i < EV_CNT; ++i)
452: bitmap_free(client->evmasks[i]);
453:
454: kvfree(client);
455:
456: evdev_close_device(evdev);
457:
458: return 0;
459: }
SourceFile:drivers/input/evdev.c]
|
| 80/2 |
2026/05/24 05:59 |
llm |
expert |
0m
Model:
Tokens:
input: 120048
output: 43
thoughts: 16
Thoughts: Here's a summary of my understanding:
**Closing Up Shop: A Look at Device Shutdown**
Okay, so I'm looking at the device shutdown sequence, specifically how `evdev_close_device` handles the close operation. It's pretty straightforward, really. My interpretation of the code tells me that `evdev_close_device` is essentially acting as a wrapper, or an entry point, to gracefully shut down the device. What it actually does internally is call `input_close_device`. That's the core function for device closure within this part of the kernel. It seems like `evdev_close_device` is just providing a more specific context for the `input_close_device` operation within the evdev subsystem. Essentially, this means that handling the specific nuances of an evdev device close can be done elsewhere, while the general mechanism of how to close the input device is handled in one place.
|
| 81/2 |
2026/05/24 05:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/evdev.c IncludeLines:true Name:evdev_close_device]
Results: map[SourceCode: 409: static void evdev_close_device(struct evdev *evdev)
410: {
411: mutex_lock(&evdev->mutex);
412:
413: if (evdev->exist && !--evdev->open)
414: input_close_device(&evdev->handle);
415:
416: mutex_unlock(&evdev->mutex);
417: }
SourceFile:drivers/input/evdev.c]
|
| 82/2 |
2026/05/24 05:59 |
llm |
expert |
0m
Model:
Tokens:
input: 120457
output: 41
thoughts: 54
Thoughts: Here's my analysis of the code, as if I'm the one thinking it:
**Digging into the evdev Lifecycle**
Okay, so `evdev_close_device` is the function we're looking at, and it seems like it's checking `evdev->exist`. That makes sense. It's probably a flag to ensure the device is actually still connected and valid before trying to close it, and before going ahead and doing something with it.
Now, my intuition is telling me that device disconnection will involve cleaning up resources. Let's see... Ah-ha, `evdev_disconnect` *does* indeed call `evdev_cleanup`. Perfect. And the next thought is now screaming... this is where things get interesting. Let's make sure that `evdev_cleanup` sets `evdev->exist = false`. Setting that flag to false is critical, as it indicates a closed file handle, so other threads attempting to operate on an invalid handle do not. Let's verify that's what's happening within `evdev_cleanup`. That's where the critical state transition must be handled.
|
| 83/2 |
2026/05/24 05:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/evdev.c IncludeLines:true Name:evdev_cleanup]
Results: map[SourceCode:1319: static void evdev_cleanup(struct evdev *evdev)
1320: {
1321: struct input_handle *handle = &evdev->handle;
1322:
1323: evdev_mark_dead(evdev);
1324: evdev_hangup(evdev);
1325:
1326: /* evdev is marked dead so no one else accesses evdev->open */
1327: if (evdev->open) {
1328: input_flush_device(handle, NULL);
1329: input_close_device(handle);
1330: }
1331: }
SourceFile:drivers/input/evdev.c]
|
| 84/2 |
2026/05/24 05:59 |
llm |
expert |
1m
Model:
Tokens:
input: 121006
output: 44
thoughts: 2067
Thoughts: **My Analysis of the USB Driver Vulnerability**
Okay, so here's what I've figured out about this potential bug. First, the good news: there's no use-after-free situation, which is a relief. The `evdev_cleanup` function ensures proper resource management by calling `input_close_device` and ultimately `usb_kill_urb` before the relevant memory is freed, thanks to the call chain through `evdev_disconnect` and `input_unregister_device`.
However, there's definitely a Denial of Service vulnerability present. It stems from an infinite loop within the USB driver due to continuous error conditions from a connected USB device. Specifically, if the device persistently returns errors like `-EPROTO` (or similar) on its control and interrupt endpoints, the corresponding callback functions (`urb_ctl_callback` and `urb_irq_callback`) enter an infinite ping-pong of URB submissions. These callbacks submit `urb_irq` and `urb_ctl` respectively back and forth. This is made worse because the error reporting is done with `dev_err` instead of something rate-limited like `dev_err_ratelimited`, which would have helped reduce the impact by not printing every error every time. This flood of printk messages stalls the CPU due to the sheer volume of output, causing an RCU stall and, ultimately, a system hang.
I've determined that a malicious USB device could easily trigger this condition. When the input device is opened in userspace (e.g., by `systemd-udevd`), the initial URB submission sets the stage. If the device then immediately returns errors, the loop begins, running within the HCD's completion handler. This will cause a system-level Denial of Service because the device will not be able to be unregistered without rebooting the system.
Regarding attack vectors, while it can't be triggered remotely or via unprivileged user space, it is a peripheral trigger. It's also not exploitable beyond a DoS, and it cannot be triggered from an unprivileged context.
I've also looked into other potential triggers. There's no stack overflow involved; the callbacks don't directly call each other, and there is no recursion. However, even if `usb_submit_urb` fails synchronously (returning an error code like `-ENODEV`), the error is reported but the submission does not continue, so it does not trigger the loop. However, asynchronous URB completion errors do trigger it. I've double-checked the logic in `yealink_do_idle_tasks`, making sure that no commands can stop the loop, other than `yld->shutdown` or a synchronous `usb_submit_urb` error.
Essentially, there is no way out of the loop and the `yealink_do_idle_tasks` always sets up the next UBR.
My assessment is that this is a straightforward Denial of Service vulnerability triggered by a malicious USB device.
|
| 85/2 |
2026/05/24 06:00 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:yld_attr_group]
Results: map[SourceCode: 786: static const struct attribute_group yld_attr_group = {
787: .attrs = yld_attributes
788: };
SourceFile:drivers/input/misc/yealink.c]
|
| 86/2 |
2026/05/24 06:00 |
llm |
expert |
0m
Model:
Tokens:
input: 123820
output: 42
thoughts: 9
Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:
**Investigating `yld_attributes`**
Alright, time to dive into this. First things first, let's take a quick look at `yld_attributes`. I need to refresh my memory and make sure I'm up-to-date on its current state. Probably there will be little to no new, or useful, information, but, hey, it's always worth a quick check to see if anything jumps out. Gotta ensure I'm solid on the foundation before moving forward. Let's see what we've got.
|
| 87/2 |
2026/05/24 06:00 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:yld_attributes]
Results: map[SourceCode: 774: static struct attribute *yld_attributes[] = {
775: &dev_attr_line1.attr,
776: &dev_attr_line2.attr,
777: &dev_attr_line3.attr,
778: &dev_attr_get_icons.attr,
779: &dev_attr_show_icon.attr,
780: &dev_attr_hide_icon.attr,
781: &dev_attr_map_seg7.attr,
782: &dev_attr_ringtone.attr,
783: NULL
784: };
SourceFile:drivers/input/misc/yealink.c]
|
| 88/2 |
2026/05/24 06:00 |
llm |
expert |
0m
Model:
Tokens:
input: 124218
output: 48
thoughts: 761
Thoughts: **Analyzing the DoS Vulnerability**
Okay, so I've been digging into this, and here's what's clicking. These `sysfs` attributes that *seem* to write directly to the LCD are actually just updating `yld->master`. That's not where the magic happens. The crucial part is when the input device is opened β *that's* when the URBs (USB Request Blocks) get submitted.
Now, who can open these input devices? Standard practice is `root:input` ownership and permissions of `0660`. Unprivileged users outside the `input` group? No dice. But, and this is the kicker, `systemd-udevd` or `libinput`, running with root privileges, automatically open these devices when they're plugged in. Bingo! That's how this is triggered.
`systemd-udevd` opens the device to probe its capabilities, potentially using `EVIOCGBIT` or similar. This triggers `input_open`, which then submits the *first* URB. If the device is malicious and returns errors, we hit the infinite loop. So, *plugging in the device* is enough to trigger the denial of service. Yep, that confirms PeripheralTrigger = Yes. No other apparent trigger points.
Let me quickly do a mental sweep for any memory corruption I might have missed. Looking at `urb_ctl_callback`, the `yld->ctl_data` buffer is DMA allocated. Since `urb_ctl` completes, `yld->ctl_data` contains the data that was sent *out* to the device. The data is read by the HCD. So the HCD receives the information here, not written. Now, `urb_irq` is an *IN* transfer. That means `yld->irq_data` is written by the HCD. And in `urb_irq_callback`, we have the `switch` statement checking the `cmd` field of `yld->irq_data`. Specifically, with the `CMD_KEYPRESS` case, the code is reading from `yld->irq_data`. No obvious out-of-bounds reads there. So it looks like the issue is solely that URB submission loop and the `printks`.
Hold on... what about the `CMD_SCANCODE` case in `urb_irq_callback`? That could be important. Looking at it, the code reads the `data[0]` from the HCD and then passes it to `map_p1k_to_key`. That `data` is a `u8` array. Let's make sure `map_p1k_to_key` is clean and does proper bounds checks. But otherwise, this looks sound. So it looks like the device can trigger this through any of the commands it returns.
|
| 89/2 |
2026/05/24 06:00 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:map_p1k_to_key]
Results: map[SourceCode: 172: /* Map device buttons to internal key events.
173: *
174: * USB-P1K button layout:
175: *
176: * up
177: * IN OUT
178: * down
179: *
180: * pickup C hangup
181: * 1 2 3
182: * 4 5 6
183: * 7 8 9
184: * * 0 #
185: *
186: * The "up" and "down" keys, are symbolised by arrows on the button.
187: * The "pickup" and "hangup" keys are symbolised by a green and red phone
188: * on the button.
189: */
190: static int map_p1k_to_key(int scancode)
191: {
192: switch(scancode) { /* phone key: */
193: case 0x23: return KEY_LEFT; /* IN */
194: case 0x33: return KEY_UP; /* up */
195: case 0x04: return KEY_RIGHT; /* OUT */
196: case 0x24: return KEY_DOWN; /* down */
197: case 0x03: return KEY_ENTER; /* pickup */
198: case 0x14: return KEY_BACKSPACE; /* C */
199: case 0x13: return KEY_ESC; /* hangup */
200: case 0x00: return KEY_1; /* 1 */
201: case 0x01: return KEY_2; /* 2 */
202: case 0x02: return KEY_3; /* 3 */
203: case 0x10: return KEY_4; /* 4 */
204: case 0x11: return KEY_5; /* 5 */
205: case 0x12: return KEY_6; /* 6 */
206: case 0x20: return KEY_7; /* 7 */
207: case 0x21: return KEY_8; /* 8 */
208: case 0x22: return KEY_9; /* 9 */
209: case 0x30: return KEY_KPASTERISK; /* * */
210: case 0x31: return KEY_0; /* 0 */
211: case 0x32: return KEY_LEFTSHIFT |
212: KEY_3 << 8; /* # */
213: }
214: return -EINVAL;
215: }
SourceFile:drivers/input/misc/yealink.c]
|
| 90/2 |
2026/05/24 06:00 |
llm |
expert |
0m
Model:
Tokens:
input: 126479
output: 42
thoughts: 66
Thoughts: Okay, let's break this down.
**Understanding the Scancode Handling**
Right, so the system is returning `-EINVAL` when it encounters an unrecognized scancode. That's good, expected behavior, indicating proper error handling. Now, let's see how the kernel processes these scancodes. Specifically, I need to focus on the `urb_irq_callback` function, and how it translates the scancode into a key event. The snippet of code gives me the heart of the matter:
```c
report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
```
It looks like the `irq_data->data[0]` is where the scancode is stored, and a function called `map_p1k_to_key` is used to translate it into something meaningful for the `report_key` function. So, the crucial link is this `map_p1k_to_key` function. This mapping, presumably, is the core of how the scancodes are interpreted and converted to the proper key codes.
Now, my next step is to examine the `report_key` function, to see how it takes the mapped key and handles the actual event reporting. I need to understand how the key press or release is signalled to the rest of the system, and what data is being used to make this happen. Ultimately, I'm thinking about whether this process is correctly mapping a specific keyboard device.
|
| 91/2 |
2026/05/24 06:01 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/input/misc/yealink.c IncludeLines:true Name:report_key]
Results: map[SourceCode: 217: /* Completes a request by converting the data into events for the
218: * input subsystem.
219: *
220: * The key parameter can be cascaded: key2 << 8 | key1
221: */
222: static void report_key(struct yealink_dev *yld, int key)
223: {
224: struct input_dev *idev = yld->idev;
225:
226: if (yld->key_code >= 0) {
227: /* old key up */
228: input_report_key(idev, yld->key_code & 0xff, 0);
229: if (yld->key_code >> 8)
230: input_report_key(idev, yld->key_code >> 8, 0);
231: }
232:
233: yld->key_code = key;
234: if (key >= 0) {
235: /* new valid key */
236: input_report_key(idev, key & 0xff, 1);
237: if (key >> 8)
238: input_report_key(idev, key >> 8, 1);
239: }
240: input_sync(idev);
241: }
SourceFile:drivers/input/misc/yealink.c]
|
| 92/2 |
2026/05/24 06:01 |
llm |
expert |
0m
Model:
Tokens:
input: 127327
output: 66
thoughts: 623
Thoughts: **My Analysis of the Yealink Driver Bug**
Okay, so I've been digging into this `yealink` driver issue, and here's the breakdown as I see it. Initially, I was concerned about a possible memory corruption issue due to the handling of the `key` variable, specifically the assignment of `-EINVAL`. However, after careful examination of the `input_report_key` calls, and the conditional logic around it, I'm confident that this isn't a vulnerability that leads to memory corruption. The check `yld->key_code >= 0` correctly prevents the reporting of "key up" events when `key` is negative, so that's safe.
The real problem lies elsewhere. It's a textbook Denial of Service, specifically an RCU stall. The driver submits two USB URBs, a control URB (`urb_ctl`) and an interrupt URB (`urb_irq`). The critical issue is what happens in the completion handlers, `urb_ctl_callback` and `urb_irq_callback`. They check the URB status, and if they find an error (like `-EPROTO` or `-71`), they call `dev_err` to print an error message. The problem is that they *don't* handle the error gracefully; they don't abort or stop resubmitting the URBs. Instead, they just immediately resubmit the next URB in the sequence. So, `urb_ctl_callback` submits `urb_irq`, and `urb_irq_callback` submits `urb_ctl`.
Now, if a malicious device or a misconfigured HCD causes these URBs to consistently fail, we have an infinite loop. The driver is stuck in a tight loop of submitting, completing with error, and resubmitting. This happens within the context of the HCD completion handler, meaning it's running in either a hard interrupt or a soft interrupt. The continuous flood of `dev_err` messages from this loop just clogs the kernel log and, worse, the serial console. This flood, being in a hard/soft interrupt context, completely starves the CPU, blocking RCU grace periods from completing, resulting in an RCU stall and a system hang.
The good news is that the vulnerability is purely a Denial of Service. It's not exploitable for any kind of privilege escalation or memory corruption. It requires a physical USB device, so while it's a serious problem, it's not remotely exploitable, nor can it be triggered by an unprivileged process or user namespace. It requires physical access (or root access to `/dev/raw-gadget`).
Okay, with that understanding, I'm ready to formally call `set-results` and provide the final answer.
|
| 93/2 |
2026/05/24 06:01 |
tool |
set-results |
0m
Args: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
Results: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
|
| 94/2 |
2026/05/24 06:01 |
llm |
expert |
1m
Model:
Tokens:
input: 128663
output: 689
thoughts: 13
Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person:
**Finalizing the Analysis & Drafting the Response**
Alright, the data is processed, the analyses are complete, and the results are definitive. There's no further tweaking, no more sensitivity analyses needed. Now it's time to craft the final response. This isn't just about regurgitating the findings; it's about synthesizing the entire process β the methodology, the nuances of the data, the interpretation of the output, and ultimately, articulating the implications with precision and clarity. I need to ensure the language is concise, technically sound, and accessible to the intended audience, while also avoiding any ambiguity. The emphasis needs to be on the robustness of the results, and, of course, the limitations are always in mind. Now, the goal is to make a compelling argument and leave no room for misinterpretation. Time to get to work.
|
| 95/1 |
2026/05/24 06:02 |
action |
format-explanation |
0m
Results: map[Explanation:**Analysis of the Bug**
The bug report indicates an RCU stall (`rcu_preempt detected expedited stalls on
CPUs/tasks`) accompanied by a flood of kernel error messages from the `yealink`
USB driver:
```
yealink 3-1:36.0: unexpected response 0
yealink 3-1:36.0: urb_ctl_callback - urb status -71
yealink 3-1:36.0: urb_irq_callback - urb status -71
```
**Root Cause**
The `yealink` driver uses two URBs to communicate with the USB device: a control
URB (`urb_ctl`) and an interrupt URB (`urb_irq`).
When these URBs complete, their respective completion handlers
(`urb_ctl_callback` and `urb_irq_callback`) are invoked.
In both callbacks, the driver checks if the URB completed with an error (`status
!= 0`). If an error occurred, it prints an error message using `dev_err()`:
```c
if (status)
dev_err(&yld->intf->dev, "%s - urb status %d\n",
__func__, status);
```
Crucially, the driver **does not abort or stop resubmitting the URBs** upon
encountering an error. Instead, it proceeds to submit the next URB in the
sequence (`urb_ctl_callback` submits `urb_irq`, and `urb_irq_callback` submits
`urb_ctl`).
If a malicious USB device (or a dummy HCD, as used in the syzkaller reproducer)
immediately completes these URBs with an error (e.g., `-EPROTO` / `-71`), it
creates an infinite ping-pong loop of URB submissions and completions.
This loop runs in the context of the HCD's completion handler (e.g., a timer
interrupt or tasklet). The continuous stream of `dev_err` messages floods the
kernel log buffer and the serial console. Because the console output is slow and
the loop runs in an interrupt context, it completely stalls the CPU, preventing
RCU grace periods from completing and leading to an RCU stall (Denial of
Service).
**Security Impact**
* **Exploitable:** No. The bug is purely an infinite loop of URB submissions and
printks. There is no memory corruption, out-of-bounds access, or use-after-free
involved.
* **Denial Of Service:** Yes. The infinite loop and printk flood will stall the
CPU, leading to a system hang and RCU stall.
* **Peripheral Trigger:** Yes. A malicious USB device (e.g., a Facedancer) can
trigger this by continuously returning errors for the control and interrupt
endpoints. When the device is plugged in, userspace daemons (like
`systemd-udevd`) will automatically open the input device to probe it, which
starts the URB submission loop.
* **Unprivileged / User Namespace:** No. Triggering this requires either
physical access to plug in a malicious USB device or root privileges to emulate
one via `/dev/raw-gadget`. Unprivileged users cannot trigger this bug.]
|