public inbox for linux-sound@vger.kernel.org
 help / color / mirror / Atom feed
* [Linux Kernel Bug] general protection fault in try_to_register_card
@ 2025-10-12 11:11 Jiaming Zhang
  2025-10-12 11:18 ` Greg KH
  0 siblings, 1 reply; 8+ messages in thread
From: Jiaming Zhang @ 2025-10-12 11:11 UTC (permalink / raw)
  To: linux-sound, perex, tiwai
  Cc: broonie, cryolitia, gregkh, linux-kernel, pierre-louis.bossart,
	quic_wcheng, syzkaller

[-- Attachment #1: Type: text/plain, Size: 6811 bytes --]

Dear Linux kernel developers and maintainers:

We are writing to report a general protection fault discovered in the
kernel with our modified syzkaller. This bug is reproducible on the
latest version (commit 67029a49db6c1f21106a1b5fcdd0ea234a6e0711).

The kernel console output, kernel config, syzkaller reproducer, and C
reproducer are attached to this email to help analysis. The KASAN
report from kernel (commit 67029a49), formatted by syz-symbolize, is
listed below:

==================================================================
e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
usb 1-1: new full-speed USB device number 2 using dummy_hcd
usb 1-1: not running at top speed; connect to a high speed hub
usb 1-1: config 2 has an invalid interface number: 131 but max is 3
usb 1-1: config 2 has an invalid interface number: 160 but max is 3
usb 1-1: config 2 has an invalid descriptor of length 0, skipping
remainder of the config
usb 1-1: config 2 has 2 interfaces, different from the descriptor's value: 4
usb 1-1: config 2 has no interface number 0
usb 1-1: config 2 has no interface number 1
usb 1-1: config 2 interface 160 altsetting 9 has an invalid descriptor
for endpoint zero, skipping
usb 1-1: config 2 interface 160 altsetting 9 has 2 endpoint
descriptors, different from the interface descriptor's value: 16
usb 1-1: config 2 interface 131 has no altsetting 0
usb 1-1: config 2 interface 160 has no altsetting 0
usb 1-1: New USB device found, idVendor=0dba, idProduct=5000, bcdDevice=3a.c9
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: syz
usb 1-1: Manufacturer: syz
usb 1-1: SerialNumber: syz
usb 1-1: MBOX3: Initialized.
Oops: general protection fault, probably for non-canonical address
0xdffffc000000001c: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x00000000000000e0-0x00000000000000e7]
CPU: 1 UID: 0 PID: 793 Comm: kworker/1:2 Not tainted
6.17.0-12904-g67029a49db6c #1 PREEMPT(full)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
Workqueue: usb_hub_wq hub_event
RIP: 0010:usb_interface_claimed include/linux/usb.h:918 [inline]
RIP: 0010:try_to_register_card+0x248/0x300 sound/usb/card.c:896
Code: de cd 30 f9 49 8b 3f 44 89 f6 e8 43 e5 fa fd 49 89 c6 49 81 c6
e0 00 00 00 4c 89 f0 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c
08 00 74 08 4c 89 f7 e8 aa cd 30 f9 49 83 3e 00 74 73 e8 ff
RSP: 0018:ffffc9000462eb80 EFLAGS: 00010202
RAX: 000000000000001c RBX: ffff888049b02a30 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000000000a0
RBP: ffffc9000462ec30 R08: ffffc9000462e9e7 R09: 1ffff920008c5d3c
R10: dffffc0000000000 R11: ffffffff88f59950 R12: 00000000000000f8
R13: 1ffff11009360559 R14: 00000000000000e0 R15: ffff888049b02a38
FS:  0000000000000000(0000) GS:ffff8880ec976000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f86fb0e16f8 CR3: 0000000028a6b000 CR4: 0000000000752ef0
PKRU: 55555554
Call Trace:
 <TASK>
 usb_audio_probe+0x143f/0x1e60 sound/usb/card.c:1039
 usb_probe_interface+0x668/0xc30 drivers/usb/core/driver.c:396
 really_probe+0x26d/0x9f0 drivers/base/dd.c:659
 __driver_probe_device+0x190/0x390 drivers/base/dd.c:801
 driver_probe_device+0x4f/0x430 drivers/base/dd.c:831
 __device_attach_driver+0x2ce/0x530 drivers/base/dd.c:959
 bus_for_each_drv+0x251/0x2e0 drivers/base/bus.c:462
 __device_attach+0x2b7/0x400 drivers/base/dd.c:1031
 bus_probe_device+0x185/0x260 drivers/base/bus.c:537
 device_add+0x7b6/0xb50 drivers/base/core.c:3689
 usb_set_configuration+0x1a5c/0x20b0 drivers/usb/core/message.c:2210
 usb_generic_driver_probe+0x8d/0x150 drivers/usb/core/generic.c:250
 usb_probe_device+0x1c4/0x390 drivers/usb/core/driver.c:291
 really_probe+0x26d/0x9f0 drivers/base/dd.c:659
 __driver_probe_device+0x190/0x390 drivers/base/dd.c:801
 driver_probe_device+0x4f/0x430 drivers/base/dd.c:831
 __device_attach_driver+0x2ce/0x530 drivers/base/dd.c:959
 bus_for_each_drv+0x251/0x2e0 drivers/base/bus.c:462
 __device_attach+0x2b7/0x400 drivers/base/dd.c:1031
 bus_probe_device+0x185/0x260 drivers/base/bus.c:537
 device_add+0x7b6/0xb50 drivers/base/core.c:3689
 usb_new_device+0xb9d/0x1a00 drivers/usb/core/hub.c:2694
 hub_port_connect drivers/usb/core/hub.c:5566 [inline]
 hub_port_connect_change drivers/usb/core/hub.c:5706 [inline]
 port_event drivers/usb/core/hub.c:5870 [inline]
 hub_event+0x290c/0x49a0 drivers/usb/core/hub.c:5952
 process_one_work kernel/workqueue.c:3263 [inline]
 process_scheduled_works+0xae1/0x17b0 kernel/workqueue.c:3346
 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3427
 kthread+0x711/0x8a0 kernel/kthread.c:463
 ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:usb_interface_claimed include/linux/usb.h:918 [inline]
RIP: 0010:try_to_register_card+0x248/0x300 sound/usb/card.c:896
Code: de cd 30 f9 49 8b 3f 44 89 f6 e8 43 e5 fa fd 49 89 c6 49 81 c6
e0 00 00 00 4c 89 f0 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c
08 00 74 08 4c 89 f7 e8 aa cd 30 f9 49 83 3e 00 74 73 e8 ff
RSP: 0018:ffffc9000462eb80 EFLAGS: 00010202
RAX: 000000000000001c RBX: ffff888049b02a30 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000000000a0
RBP: ffffc9000462ec30 R08: ffffc9000462e9e7 R09: 1ffff920008c5d3c
R10: dffffc0000000000 R11: ffffffff88f59950 R12: 00000000000000f8
R13: 1ffff11009360559 R14: 00000000000000e0 R15: ffff888049b02a38
FS:  0000000000000000(0000) GS:ffff8880ec976000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f067e010980 CR3: 0000000024315000 CR4: 0000000000752ef0
PKRU: 55555554
----------------
Code disassembly (best guess):
   0: de cd                fmulp  %st,%st(5)
   2: 30 f9                xor    %bh,%cl
   4: 49 8b 3f              mov    (%r15),%rdi
   7: 44 89 f6              mov    %r14d,%esi
   a: e8 43 e5 fa fd        call   0xfdfae552
   f: 49 89 c6              mov    %rax,%r14
  12: 49 81 c6 e0 00 00 00 add    $0xe0,%r14
  19: 4c 89 f0              mov    %r14,%rax
  1c: 48 c1 e8 03          shr    $0x3,%rax
  20: 48 b9 00 00 00 00 00 movabs $0xdffffc0000000000,%rcx
  27: fc ff df
* 2a: 80 3c 08 00          cmpb   $0x0,(%rax,%rcx,1) <-- trapping instruction
  2e: 74 08                je     0x38
  30: 4c 89 f7              mov    %r14,%rdi
  33: e8 aa cd 30 f9        call   0xf930cde2
  38: 49 83 3e 00          cmpq   $0x0,(%r14)
  3c: 74 73                je     0xb1
  3e: e8                    .byte 0xe8
  3f: ff                    .byte 0xff
==================================================================

Please let me know if any further information is required.

Best Regards,
Jiaming Zhang.

[-- Attachment #2: repro.c --]
[-- Type: text/plain, Size: 17279 bytes --]

// 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=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul,
          /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1,
          /*offset=*/0ul);
  const char* reason;
  (void)reason;
  if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
  }
  memcpy(
      (void*)0x200017c0,
      "\x12\x01\x00\x02\x2f\xf5\x2f\x08\xba\x0d\x00\x50\xc9\x3a\x01\x02\x03\x01"
      "\x09\x02\x43\x0d\x04\x02\x00\x50\x0b\x09\x04\x83\x04\x02\x57\xc1\xe4\x9b"
      "\x09\x05\x0a\x00\x08\x00\x92\xba\x04\x09\x05\x0c\x00\x10\x00\x08\x02\x31"
      "\xbf\x0a\x37\x10\x23\xa0\xd0\xaf\x63\x7b\x85\x1f\x09\xf9\x77\xf8\x57\x4b"
      "\x84\x53\xc7\x58\x98\xe3\xc3\x39\xad\xe9\x09\xc3\xed\xeb\x80\x11\x2d\x57"
      "\xf6\x41\xb3\x9e\x97\x1e\xfa\x0a\x97\x87\xa9\x78\x8c\xd3\xde\xb1\xa1\x74"
      "\x1d\x46\xf1\xae\xcc\x17\xea\x05\x79\xd6\xb3\x7e\x6f\x19\x4c\x0d\xf3\x2f"
      "\x91\xb0\x6a\x69\xce\xab\x57\x1b\x9b\x3d\xee\x32\x51\xa6\xe3\x36\xad\x93"
      "\x1d\x28\xfb\x73\x32\x24\x2e\x8e\x37\x3e\x6c\x30\x80\x6c\x71\x8a\xa6\xe1"
      "\x62\x22\xb8\xb5\x72\x27\x68\xe5\xaa\x95\x2f\xf7\x5a\xef\x60\xbb\xfe\x9a"
      "\x06\x67\x44\x4f\x33\xc5\xc0\xab\xd1\xa3\xf3\xeb\x6c\xc8\x69\x8d\xdb\x8c"
      "\xb3\x18\xea\xb5\x33\xc1\x7d\x3f\x0c\xb0\xe9\x35\xd2\x21\x8a\xd5\x47\xde"
      "\x8c\xc6\xd4\x4e\x38\xf9\xa8\x0d\x7a\x6b\x82\x8c\x47\x0b\xd7\x72\xce\x2d"
      "\x53\x4a\x33\x55\x3a\xf8\xce\x68\x54\x33\xa6\x09\x04\xa0\x09\x10\xbf\x7e"
      "\xb0\x70\x09\x05\x04\x10\x40\x00\x09\x08\x0f\x09\x05\x00\x03\xff\x03\x09"
      "\x00\x01\xd2\x20\x31\xab\x6c\xe3\x6d\xea\xd3\x58\x93\x10\x25\xff\xa7\xd6"
      "\x46\xcd\x5b\x74\x8d\x19",
      294);
  *(uint32_t*)0x20000640 = 0;
  *(uint64_t*)0x20000644 = 0;
  *(uint32_t*)0x2000064c = 0;
  *(uint64_t*)0x20000650 = 0;
  *(uint32_t*)0x20000658 = 0;
  syz_usb_connect(/*speed=USB_SPEED_FULL*/ 2, /*dev_len=*/0xd55,
                  /*dev=*/0x200017c0, /*conn_descs=*/0x20000640);
  return 0;
}

[-- Attachment #3: .config --]
[-- Type: application/xml, Size: 276250 bytes --]

[-- Attachment #4: kernel.log --]
[-- Type: application/octet-stream, Size: 188867 bytes --]

[-- Attachment #5: report --]
[-- Type: application/octet-stream, Size: 6235 bytes --]


e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
usb 1-1: new full-speed USB device number 2 using dummy_hcd
usb 1-1: not running at top speed; connect to a high speed hub
usb 1-1: config 2 has an invalid interface number: 131 but max is 3
usb 1-1: config 2 has an invalid interface number: 160 but max is 3
usb 1-1: config 2 has an invalid descriptor of length 0, skipping remainder of the config
usb 1-1: config 2 has 2 interfaces, different from the descriptor's value: 4
usb 1-1: config 2 has no interface number 0
usb 1-1: config 2 has no interface number 1
usb 1-1: config 2 interface 160 altsetting 9 has an invalid descriptor for endpoint zero, skipping
usb 1-1: config 2 interface 160 altsetting 9 has 2 endpoint descriptors, different from the interface descriptor's value: 16
usb 1-1: config 2 interface 131 has no altsetting 0
usb 1-1: config 2 interface 160 has no altsetting 0
usb 1-1: New USB device found, idVendor=0dba, idProduct=5000, bcdDevice=3a.c9
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: syz
usb 1-1: Manufacturer: syz
usb 1-1: SerialNumber: syz
usb 1-1: MBOX3: Initialized.
Oops: general protection fault, probably for non-canonical address 0xdffffc000000001c: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x00000000000000e0-0x00000000000000e7]
CPU: 1 UID: 0 PID: 793 Comm: kworker/1:2 Not tainted 6.17.0-12904-g67029a49db6c #1 PREEMPT(full) 
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
Workqueue: usb_hub_wq hub_event
RIP: 0010:usb_interface_claimed include/linux/usb.h:918 [inline]
RIP: 0010:try_to_register_card+0x248/0x300 sound/usb/card.c:896
Code: de cd 30 f9 49 8b 3f 44 89 f6 e8 43 e5 fa fd 49 89 c6 49 81 c6 e0 00 00 00 4c 89 f0 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 4c 89 f7 e8 aa cd 30 f9 49 83 3e 00 74 73 e8 ff
RSP: 0018:ffffc9000462eb80 EFLAGS: 00010202
RAX: 000000000000001c RBX: ffff888049b02a30 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000000000a0
RBP: ffffc9000462ec30 R08: ffffc9000462e9e7 R09: 1ffff920008c5d3c
R10: dffffc0000000000 R11: ffffffff88f59950 R12: 00000000000000f8
R13: 1ffff11009360559 R14: 00000000000000e0 R15: ffff888049b02a38
FS:  0000000000000000(0000) GS:ffff8880ec976000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f86fb0e16f8 CR3: 0000000028a6b000 CR4: 0000000000752ef0
PKRU: 55555554
Call Trace:
 <TASK>
 usb_audio_probe+0x143f/0x1e60 sound/usb/card.c:1039
 usb_probe_interface+0x668/0xc30 drivers/usb/core/driver.c:396
 really_probe+0x26d/0x9f0 drivers/base/dd.c:659
 __driver_probe_device+0x190/0x390 drivers/base/dd.c:801
 driver_probe_device+0x4f/0x430 drivers/base/dd.c:831
 __device_attach_driver+0x2ce/0x530 drivers/base/dd.c:959
 bus_for_each_drv+0x251/0x2e0 drivers/base/bus.c:462
 __device_attach+0x2b7/0x400 drivers/base/dd.c:1031
 bus_probe_device+0x185/0x260 drivers/base/bus.c:537
 device_add+0x7b6/0xb50 drivers/base/core.c:3689
 usb_set_configuration+0x1a5c/0x20b0 drivers/usb/core/message.c:2210
 usb_generic_driver_probe+0x8d/0x150 drivers/usb/core/generic.c:250
 usb_probe_device+0x1c4/0x390 drivers/usb/core/driver.c:291
 really_probe+0x26d/0x9f0 drivers/base/dd.c:659
 __driver_probe_device+0x190/0x390 drivers/base/dd.c:801
 driver_probe_device+0x4f/0x430 drivers/base/dd.c:831
 __device_attach_driver+0x2ce/0x530 drivers/base/dd.c:959
 bus_for_each_drv+0x251/0x2e0 drivers/base/bus.c:462
 __device_attach+0x2b7/0x400 drivers/base/dd.c:1031
 bus_probe_device+0x185/0x260 drivers/base/bus.c:537
 device_add+0x7b6/0xb50 drivers/base/core.c:3689
 usb_new_device+0xb9d/0x1a00 drivers/usb/core/hub.c:2694
 hub_port_connect drivers/usb/core/hub.c:5566 [inline]
 hub_port_connect_change drivers/usb/core/hub.c:5706 [inline]
 port_event drivers/usb/core/hub.c:5870 [inline]
 hub_event+0x290c/0x49a0 drivers/usb/core/hub.c:5952
 process_one_work kernel/workqueue.c:3263 [inline]
 process_scheduled_works+0xae1/0x17b0 kernel/workqueue.c:3346
 worker_thread+0x8a0/0xda0 kernel/workqueue.c:3427
 kthread+0x711/0x8a0 kernel/kthread.c:463
 ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:usb_interface_claimed include/linux/usb.h:918 [inline]
RIP: 0010:try_to_register_card+0x248/0x300 sound/usb/card.c:896
Code: de cd 30 f9 49 8b 3f 44 89 f6 e8 43 e5 fa fd 49 89 c6 49 81 c6 e0 00 00 00 4c 89 f0 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 4c 89 f7 e8 aa cd 30 f9 49 83 3e 00 74 73 e8 ff
RSP: 0018:ffffc9000462eb80 EFLAGS: 00010202
RAX: 000000000000001c RBX: ffff888049b02a30 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000000000a0
RBP: ffffc9000462ec30 R08: ffffc9000462e9e7 R09: 1ffff920008c5d3c
R10: dffffc0000000000 R11: ffffffff88f59950 R12: 00000000000000f8
R13: 1ffff11009360559 R14: 00000000000000e0 R15: ffff888049b02a38
FS:  0000000000000000(0000) GS:ffff8880ec976000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f067e010980 CR3: 0000000024315000 CR4: 0000000000752ef0
PKRU: 55555554
----------------
Code disassembly (best guess):
   0:	de cd                	fmulp  %st,%st(5)
   2:	30 f9                	xor    %bh,%cl
   4:	49 8b 3f             	mov    (%r15),%rdi
   7:	44 89 f6             	mov    %r14d,%esi
   a:	e8 43 e5 fa fd       	call   0xfdfae552
   f:	49 89 c6             	mov    %rax,%r14
  12:	49 81 c6 e0 00 00 00 	add    $0xe0,%r14
  19:	4c 89 f0             	mov    %r14,%rax
  1c:	48 c1 e8 03          	shr    $0x3,%rax
  20:	48 b9 00 00 00 00 00 	movabs $0xdffffc0000000000,%rcx
  27:	fc ff df
* 2a:	80 3c 08 00          	cmpb   $0x0,(%rax,%rcx,1) <-- trapping instruction
  2e:	74 08                	je     0x38
  30:	4c 89 f7             	mov    %r14,%rdi
  33:	e8 aa cd 30 f9       	call   0xf930cde2
  38:	49 83 3e 00          	cmpq   $0x0,(%r14)
  3c:	74 73                	je     0xb1
  3e:	e8                   	.byte 0xe8
  3f:	ff                   	.byte 0xff

[-- Attachment #6: repro.syz --]
[-- Type: application/octet-stream, Size: 693 bytes --]

syz_usb_connect(0x2, 0xd55, &(0x7f00000017c0)=ANY=[@ANYBLOB="120100022ff52f08ba0d0050c93a010203010902430d040200500b090483040257c1e49b09050a00080092ba0409050c001000080231bf0a371023a0d0af637b851f09f977f8574b8453c75898e3c339ade909c3edeb80112d57f641b39e971efa0a9787a9788cd3deb1a1741d46f1aecc17ea0579d6b37e6f194c0df32f91b06a69ceab571b9b3dee3251a6e336ad931d28fb7332242e8e373e6c30806c718aa6e16222b8b5722768e5aa952ff75aef60bbfe9a0667444f33c5c0abd1a3f3eb6cc8698ddb8cb318eab533c17d3f0cb0e935d2218ad547de8cc6d44e38f9a80d7a6b828c470bd772ce2d534a33553af8ce685433a60904a00910bf7eb07009050410400009080f09050003ff03090001d22031ab6ce36dead358931025ffa7d646cd5b748d19"], &(0x7f0000000640)={0x0, 0x0, 0x0, 0x0})

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Linux Kernel Bug] general protection fault in try_to_register_card
  2025-10-12 11:11 [Linux Kernel Bug] general protection fault in try_to_register_card Jiaming Zhang
@ 2025-10-12 11:18 ` Greg KH
  2025-10-14  4:01   ` [PATCH] ALSA: usb-audio: Fix NULL pointer deference " Jiaming Zhang
  0 siblings, 1 reply; 8+ messages in thread
From: Greg KH @ 2025-10-12 11:18 UTC (permalink / raw)
  To: Jiaming Zhang
  Cc: linux-sound, perex, tiwai, broonie, cryolitia, linux-kernel,
	pierre-louis.bossart, quic_wcheng, syzkaller

On Sun, Oct 12, 2025 at 07:11:53PM +0800, Jiaming Zhang wrote:
> Dear Linux kernel developers and maintainers:
> 
> We are writing to report a general protection fault discovered in the
> kernel with our modified syzkaller. This bug is reproducible on the
> latest version (commit 67029a49db6c1f21106a1b5fcdd0ea234a6e0711).
> 
> The kernel console output, kernel config, syzkaller reproducer, and C
> reproducer are attached to this email to help analysis. The KASAN
> report from kernel (commit 67029a49), formatted by syz-symbolize, is
> listed below:
> 
> ==================================================================
> e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
> usb 1-1: new full-speed USB device number 2 using dummy_hcd
> usb 1-1: not running at top speed; connect to a high speed hub
> usb 1-1: config 2 has an invalid interface number: 131 but max is 3
> usb 1-1: config 2 has an invalid interface number: 160 but max is 3
> usb 1-1: config 2 has an invalid descriptor of length 0, skipping
> remainder of the config
> usb 1-1: config 2 has 2 interfaces, different from the descriptor's value: 4
> usb 1-1: config 2 has no interface number 0
> usb 1-1: config 2 has no interface number 1
> usb 1-1: config 2 interface 160 altsetting 9 has an invalid descriptor
> for endpoint zero, skipping
> usb 1-1: config 2 interface 160 altsetting 9 has 2 endpoint
> descriptors, different from the interface descriptor's value: 16
> usb 1-1: config 2 interface 131 has no altsetting 0
> usb 1-1: config 2 interface 160 has no altsetting 0
> usb 1-1: New USB device found, idVendor=0dba, idProduct=5000, bcdDevice=3a.c9
> usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> usb 1-1: Product: syz
> usb 1-1: Manufacturer: syz
> usb 1-1: SerialNumber: syz
> usb 1-1: MBOX3: Initialized.
> Oops: general protection fault, probably for non-canonical address
> 0xdffffc000000001c: 0000 [#1] SMP KASAN NOPTI
> KASAN: null-ptr-deref in range [0x00000000000000e0-0x00000000000000e7]
> CPU: 1 UID: 0 PID: 793 Comm: kworker/1:2 Not tainted
> 6.17.0-12904-g67029a49db6c #1 PREEMPT(full)
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
> Workqueue: usb_hub_wq hub_event
> RIP: 0010:usb_interface_claimed include/linux/usb.h:918 [inline]
> RIP: 0010:try_to_register_card+0x248/0x300 sound/usb/card.c:896
> Code: de cd 30 f9 49 8b 3f 44 89 f6 e8 43 e5 fa fd 49 89 c6 49 81 c6
> e0 00 00 00 4c 89 f0 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c
> 08 00 74 08 4c 89 f7 e8 aa cd 30 f9 49 83 3e 00 74 73 e8 ff
> RSP: 0018:ffffc9000462eb80 EFLAGS: 00010202
> RAX: 000000000000001c RBX: ffff888049b02a30 RCX: dffffc0000000000
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000000000a0
> RBP: ffffc9000462ec30 R08: ffffc9000462e9e7 R09: 1ffff920008c5d3c
> R10: dffffc0000000000 R11: ffffffff88f59950 R12: 00000000000000f8
> R13: 1ffff11009360559 R14: 00000000000000e0 R15: ffff888049b02a38
> FS:  0000000000000000(0000) GS:ffff8880ec976000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00007f86fb0e16f8 CR3: 0000000028a6b000 CR4: 0000000000752ef0
> PKRU: 55555554
> Call Trace:
>  <TASK>
>  usb_audio_probe+0x143f/0x1e60 sound/usb/card.c:1039


So you are probably creating an invalid usb audio device without a
proper interface here, right?  Care to make up a simple patch for this
so that you get the credit for fixing the issue as you can test it
easily?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH] ALSA: usb-audio: Fix NULL pointer deference in try_to_register_card
  2025-10-12 11:18 ` Greg KH
@ 2025-10-14  4:01   ` Jiaming Zhang
  2025-10-14  5:26     ` Greg KH
  0 siblings, 1 reply; 8+ messages in thread
From: Jiaming Zhang @ 2025-10-14  4:01 UTC (permalink / raw)
  To: gregkh
  Cc: broonie, cryolitia, linux-kernel, linux-sound, perex,
	pierre-louis.bossart, quic_wcheng, r772577952, syzkaller, tiwai

Hi Greg,

Thanks for the guidance. You're right, the root cause of this issue is
that a USB audio device is created without a proper interface.

To fix this issue, I added a check for the NULL return value in
try_to_register_card() before calling usb_interface_claimed().
I have tested patch with the reproducer on the latest version (v6.18-rc1),
the issue was not triggered again.

Please let me know if any changes are needed.

Best regards,
Jiaming Zhang
---

In try_to_register_card(), the return value of usb_ifnum_to_if() is
passed directly to usb_interface_claimed() without a NULL check, which
will lead to a NULL pointer dereference when creating an invalid
USB audio device. Fix this by adding a check to ensure the interface
pointer is valid before passing it to usb_interface_claimed().

Reported-by: Jiaming Zhang <r772577952@gmail.com>
Signed-off-by: Jiaming Zhang <r772577952@gmail.com>
---
 sound/usb/card.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 1d5a65eac933..270dad84d825 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -891,10 +891,16 @@ get_alias_quirk(struct usb_device *dev, unsigned int id)
  */
 static int try_to_register_card(struct snd_usb_audio *chip, int ifnum)
 {
+	struct usb_interface *iface;
+
 	if (check_delayed_register_option(chip) == ifnum ||
-	    chip->last_iface == ifnum ||
-	    usb_interface_claimed(usb_ifnum_to_if(chip->dev, chip->last_iface)))
+	    chip->last_iface == ifnum)
+		return snd_card_register(chip->card);
+
+	iface = usb_ifnum_to_if(chip->dev, chip->last_iface);
+	if (iface && usb_interface_claimed(iface))
 		return snd_card_register(chip->card);
+
 	return 0;
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] ALSA: usb-audio: Fix NULL pointer deference in try_to_register_card
  2025-10-14  4:01   ` [PATCH] ALSA: usb-audio: Fix NULL pointer deference " Jiaming Zhang
@ 2025-10-14  5:26     ` Greg KH
  2025-10-14  5:53       ` Takashi Iwai
  0 siblings, 1 reply; 8+ messages in thread
From: Greg KH @ 2025-10-14  5:26 UTC (permalink / raw)
  To: Jiaming Zhang
  Cc: broonie, cryolitia, linux-kernel, linux-sound, perex,
	pierre-louis.bossart, quic_wcheng, syzkaller, tiwai

On Tue, Oct 14, 2025 at 12:01:49PM +0800, Jiaming Zhang wrote:
> Hi Greg,
> 
> Thanks for the guidance. You're right, the root cause of this issue is
> that a USB audio device is created without a proper interface.
> 
> To fix this issue, I added a check for the NULL return value in
> try_to_register_card() before calling usb_interface_claimed().
> I have tested patch with the reproducer on the latest version (v6.18-rc1),
> the issue was not triggered again.
> 
> Please let me know if any changes are needed.
> 
> Best regards,
> Jiaming Zhang

Can you resend this without this text above the changelog comment?

> ---
> 
> In try_to_register_card(), the return value of usb_ifnum_to_if() is
> passed directly to usb_interface_claimed() without a NULL check, which
> will lead to a NULL pointer dereference when creating an invalid
> USB audio device. Fix this by adding a check to ensure the interface
> pointer is valid before passing it to usb_interface_claimed().
> 
> Reported-by: Jiaming Zhang <r772577952@gmail.com>
> Signed-off-by: Jiaming Zhang <r772577952@gmail.com>

And as you authored this, no need for "Reported-by:" :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ALSA: usb-audio: Fix NULL pointer deference in try_to_register_card
  2025-10-14  5:26     ` Greg KH
@ 2025-10-14  5:53       ` Takashi Iwai
  2025-10-15  5:16         ` [PATCH v2 0/1] " Jiaming Zhang
  0 siblings, 1 reply; 8+ messages in thread
From: Takashi Iwai @ 2025-10-14  5:53 UTC (permalink / raw)
  To: Jiaming Zhang
  Cc: Greg KH, broonie, cryolitia, linux-kernel, linux-sound, perex,
	pierre-louis.bossart, quic_wcheng, syzkaller, tiwai

On Tue, 14 Oct 2025 07:26:41 +0200,
Greg KH wrote:
> 
> On Tue, Oct 14, 2025 at 12:01:49PM +0800, Jiaming Zhang wrote:
> > Hi Greg,
> > 
> > Thanks for the guidance. You're right, the root cause of this issue is
> > that a USB audio device is created without a proper interface.
> > 
> > To fix this issue, I added a check for the NULL return value in
> > try_to_register_card() before calling usb_interface_claimed().
> > I have tested patch with the reproducer on the latest version (v6.18-rc1),
> > the issue was not triggered again.
> > 
> > Please let me know if any changes are needed.
> > 
> > Best regards,
> > Jiaming Zhang
> 
> Can you resend this without this text above the changelog comment?
> 
> > ---
> > 
> > In try_to_register_card(), the return value of usb_ifnum_to_if() is
> > passed directly to usb_interface_claimed() without a NULL check, which
> > will lead to a NULL pointer dereference when creating an invalid
> > USB audio device. Fix this by adding a check to ensure the interface
> > pointer is valid before passing it to usb_interface_claimed().
> > 
> > Reported-by: Jiaming Zhang <r772577952@gmail.com>
> > Signed-off-by: Jiaming Zhang <r772577952@gmail.com>
> 
> And as you authored this, no need for "Reported-by:" :)

Also try to point to a breaker commit via Fixes tag.
And, pointing to the bug report thread via Closes tag would be nicer,
too.

The code change itself looks good, so only those cosmetic things.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 0/1] ALSA: usb-audio: Fix NULL pointer deference in try_to_register_card
  2025-10-14  5:53       ` Takashi Iwai
@ 2025-10-15  5:16         ` Jiaming Zhang
  2025-10-15  5:16           ` [PATCH v2 1/1] " Jiaming Zhang
  0 siblings, 1 reply; 8+ messages in thread
From: Jiaming Zhang @ 2025-10-15  5:16 UTC (permalink / raw)
  To: tiwai, gregkh
  Cc: broonie, cryolitia, linux-kernel, linux-sound, perex,
	pierre-louis.bossart, quic_wcheng, r772577952, syzkaller, tiwai

Hi Greg, Takashi,

Thanks for your suggestions. I have updated the commit message.

Please let me know if any changes are needed.

Best regards,
Jiaming Zhang

Jiaming Zhang (1):
  ALSA: usb-audio: Fix NULL pointer deference in try_to_register_card

 sound/usb/card.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/1] ALSA: usb-audio: Fix NULL pointer deference in try_to_register_card
  2025-10-15  5:16         ` [PATCH v2 0/1] " Jiaming Zhang
@ 2025-10-15  5:16           ` Jiaming Zhang
  2025-10-15  8:18             ` Takashi Iwai
  0 siblings, 1 reply; 8+ messages in thread
From: Jiaming Zhang @ 2025-10-15  5:16 UTC (permalink / raw)
  To: tiwai, gregkh
  Cc: broonie, cryolitia, linux-kernel, linux-sound, perex,
	pierre-louis.bossart, quic_wcheng, r772577952, syzkaller, tiwai

In try_to_register_card(), the return value of usb_ifnum_to_if() is
passed directly to usb_interface_claimed() without a NULL check, which
will lead to a NULL pointer dereference when creating an invalid
USB audio device. Fix this by adding a check to ensure the interface
pointer is valid before passing it to usb_interface_claimed().

Fixes: 39efc9c ("ALSA: usb-audio: Fix last interface check for registration")
Closes: https://lore.kernel.org/all/CANypQFYtQxHL5ghREs-BujZG413RPJGnO5TH=xjFBKpPts33tA@mail.gmail.com/
Signed-off-by: Jiaming Zhang <r772577952@gmail.com>
---
 sound/usb/card.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 1d5a65eac933..270dad84d825 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -891,10 +891,16 @@ get_alias_quirk(struct usb_device *dev, unsigned int id)
  */
 static int try_to_register_card(struct snd_usb_audio *chip, int ifnum)
 {
+	struct usb_interface *iface;
+
 	if (check_delayed_register_option(chip) == ifnum ||
-	    chip->last_iface == ifnum ||
-	    usb_interface_claimed(usb_ifnum_to_if(chip->dev, chip->last_iface)))
+	    chip->last_iface == ifnum)
+		return snd_card_register(chip->card);
+
+	iface = usb_ifnum_to_if(chip->dev, chip->last_iface);
+	if (iface && usb_interface_claimed(iface))
 		return snd_card_register(chip->card);
+
 	return 0;
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/1] ALSA: usb-audio: Fix NULL pointer deference in try_to_register_card
  2025-10-15  5:16           ` [PATCH v2 1/1] " Jiaming Zhang
@ 2025-10-15  8:18             ` Takashi Iwai
  0 siblings, 0 replies; 8+ messages in thread
From: Takashi Iwai @ 2025-10-15  8:18 UTC (permalink / raw)
  To: Jiaming Zhang
  Cc: tiwai, gregkh, broonie, cryolitia, linux-kernel, linux-sound,
	perex, pierre-louis.bossart, quic_wcheng, syzkaller, tiwai

On Wed, 15 Oct 2025 07:16:45 +0200,
Jiaming Zhang wrote:
> 
> In try_to_register_card(), the return value of usb_ifnum_to_if() is
> passed directly to usb_interface_claimed() without a NULL check, which
> will lead to a NULL pointer dereference when creating an invalid
> USB audio device. Fix this by adding a check to ensure the interface
> pointer is valid before passing it to usb_interface_claimed().
> 
> Fixes: 39efc9c ("ALSA: usb-audio: Fix last interface check for registration")
> Closes: https://lore.kernel.org/all/CANypQFYtQxHL5ghREs-BujZG413RPJGnO5TH=xjFBKpPts33tA@mail.gmail.com/
> Signed-off-by: Jiaming Zhang <r772577952@gmail.com>

Thanks, applied now.
The Fixes tag should have 12 letter IDs, and I corrected it.


Takashi

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-10-15  8:18 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-12 11:11 [Linux Kernel Bug] general protection fault in try_to_register_card Jiaming Zhang
2025-10-12 11:18 ` Greg KH
2025-10-14  4:01   ` [PATCH] ALSA: usb-audio: Fix NULL pointer deference " Jiaming Zhang
2025-10-14  5:26     ` Greg KH
2025-10-14  5:53       ` Takashi Iwai
2025-10-15  5:16         ` [PATCH v2 0/1] " Jiaming Zhang
2025-10-15  5:16           ` [PATCH v2 1/1] " Jiaming Zhang
2025-10-15  8:18             ` Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox