Linux kernel staging patches
 help / color / mirror / Atom feed
* [BUG] KASAN: slab-out-of-bounds Write in gb_hid_raw_request
@ 2026-09-10  1:38 Farhad Alemi
  2026-09-10  6:10 ` Greg Kroah-Hartman
  0 siblings, 1 reply; 2+ messages in thread
From: Farhad Alemi @ 2026-09-10  1:38 UTC (permalink / raw)
  To: Viresh Kumar, Johan Hovold, Alex Elder, Greg Kroah-Hartman
  Cc: Farhad Alemi, greybus-dev, linux-staging, linux-kernel

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

Hello,

We are reporting the following crash (reproducer and a proposed patch attached):
Linux version 7.3.0-rc2 50d05c7c76c96b90462f24debacca971d2e86713
Build Config: UpstreamAppArmorKASAN (KASAN + UBSAN, panic_on_warn=1)

[   44.000772][  T804] usb 3-1: new high-speed USB device number 2
using dummy_hcd
[   44.163699][  T804] usb 3-1: New USB device found, idVendor=18d1,
idProduct=1eaf, bcdDevice= 1.00
[   44.169786][  T804] usb 3-1: New USB device strings: Mfr=0,
Product=0, SerialNumber=0
[   44.212054][   T12] greybus 1-svc: set power mode = 0
[   44.212064][   T12] greybus 1-svc: power mode change failed on AP
to switch link: -5
[   44.213758][    C1] greybus greybus1: 0/0:0: short response 0x94
received (8 < 9)
[   44.215179][ T9337] greybus greybus1: 0/0:0: synchronous operation
id 0x0003 of type 0x14 failed: -90
[   44.215216][ T9337] greybus 1-svc: failed to get rail count: -90
[   44.234071][ T9337] greybus 1-2.2: Interface added (greybus)
[   44.234080][ T9337] greybus 1-2.2: GMP VID=0x00000001, PID=0x00000001
[   44.234087][ T9337] greybus 1-2.2: DDBL1 Manufacturer=0x00000126,
Product=0x00000001
[   44.256005][ T9337] hid-generic 0000:0001:0002.0001: hidraw0:
<UNKNOWN> HID v1.11 Device [1-2.2.1 0001:0002] on
[   44.295710][ T9495]
==================================================================
[   44.295718][ T9495] BUG: KASAN: slab-out-of-bounds in
gb_hid_raw_request+0x29c/0x860
[   44.295741][ T9495] Write of size 2 at addr ffff88810d471a0a by
task repro/9495
[   44.295747][ T9495]
[   44.295758][ T9495] CPU: 1 UID: 0 PID: 9495 Comm: repro Not tainted
7.3.0-rc2-00099-g50d05c7c76c9 #1 PREEMPT(full)
[   44.295767][ T9495] Hardware name: QEMU Standard PC (Q35 + ICH9,
2009), BIOS 1.17.0-debian-1.17.0-1ubuntu1 04/01/2014
[   44.295775][ T9495] Call Trace:
[   44.295779][ T9495]  <TASK>
[   44.295784][ T9495]  dump_stack_lvl+0xe8/0x150
[   44.295794][ T9495]  print_address_description+0x55/0x1e0
[   44.295802][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.295809][ T9495]  print_report+0x58/0x70
[   44.295815][ T9495]  kasan_report+0x117/0x150
[   44.295826][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.295834][ T9495]  kasan_check_range+0x264/0x2c0
[   44.295843][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.295849][ T9495]  __asan_memcpy+0x40/0x70
[   44.295858][ T9495]  gb_hid_raw_request+0x29c/0x860
[   44.295865][ T9495]  ? __pfx_gb_hid_raw_request+0x10/0x10
[   44.295873][ T9495]  ? __hid_hw_raw_request+0xa7/0x140
[   44.295883][ T9495]  hidraw_send_report+0x2bf/0x540
[   44.295892][ T9495]  ? bpf_lsm_file_permission+0x9/0x20
[   44.295901][ T9495]  hidraw_write+0x91/0xd0
[   44.295908][ T9495]  ? __pfx_hidraw_write+0x10/0x10
[   44.295916][ T9495]  vfs_write+0x29a/0xb90
[   44.295924][ T9495]  ? __pfx_vfs_write+0x10/0x10
[   44.295931][ T9495]  ? __fget_files+0x2a/0x420
[   44.295939][ T9495]  ? __fget_files+0x2a/0x420
[   44.295944][ T9495]  ? __fget_files+0x3a0/0x420
[   44.295950][ T9495]  ? __fget_files+0x2a/0x420
[   44.295958][ T9495]  ksys_write+0x150/0x270
[   44.295965][ T9495]  ? __pfx_ksys_write+0x10/0x10
[   44.295973][ T9495]  do_syscall_64+0x155/0x510
[   44.295984][ T9495]  ? trace_irq_disable+0x3b/0x140
[   44.295993][ T9495]  ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   44.296000][ T9495]  ? clear_bhb_loop+0x30/0x80
[   44.296007][ T9495]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   44.296014][ T9495] RIP: 0033:0x4521d2
[   44.296024][ T9495] Code: 08 0f 85 e1 df ff ff 49 89 fb 48 89 f0 48
89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89
5c 24 08 0f 05 <c3> 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 f3 0f 1e fa
55 48 89 e5
[   44.296032][ T9495] RSP: 002b:00007ffcc5937968 EFLAGS: 00000246
ORIG_RAX: 0000000000000001
[   44.296042][ T9495] RAX: ffffffffffffffda RBX: 0000000000000001
RCX: 00000000004521d2
[   44.296046][ T9495] RDX: 0000000000000002 RSI: 00007ffcc5937af6
RDI: 0000000000000004
[   44.296051][ T9495] RBP: 00007ffcc5937990 R08: 0000000000000000
R09: 0000000000000000
[   44.296055][ T9495] R10: 0000000000000000 R11: 0000000000000246
R12: 00007ffcc5937c28
[   44.296059][ T9495] R13: 00007ffcc5937c38 R14: 0000000000000002
R15: 00000000004cba40
[   44.296066][ T9495]  </TASK>
[   44.296068][ T9495]
[   44.296071][ T9495] Allocated by task 9495:
[   44.296075][ T9495]  kasan_save_track+0x3e/0x80
[   44.296082][ T9495]  __kasan_kmalloc+0x93/0xb0
[   44.296090][ T9495]  __kmalloc_noprof+0x36f/0x720
[   44.296097][ T9495]  gb_operation_message_alloc+0x8c/0x280
[   44.296104][ T9495]  gb_operation_create_common+0xa9/0x650
[   44.296111][ T9495]  gb_operation_create_flags+0xa2/0x2d0
[   44.296117][ T9495]  gb_hid_raw_request+0x1e6/0x860
[   44.296123][ T9495]  hidraw_send_report+0x2bf/0x540
[   44.296130][ T9495]  hidraw_write+0x91/0xd0
[   44.296137][ T9495]  vfs_write+0x29a/0xb90
[   44.296142][ T9495]  ksys_write+0x150/0x270
[   44.296148][ T9495]  do_syscall_64+0x155/0x510
[   44.296156][ T9495]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   44.296162][ T9495]
[   44.296163][ T9495] The buggy address belongs to the object at
ffff88810d471a00
[   44.296163][ T9495]  which belongs to the cache kmalloc-16 of size 16
[   44.296170][ T9495] The buggy address is located 10 bytes inside of
[   44.296170][ T9495]  allocated 11-byte region [ffff88810d471a00,
ffff88810d471a0b)
[   44.296177][ T9495]
[   44.296179][ T9495] The buggy address belongs to the physical page:
[   44.296186][ T9495] page: refcount:0 mapcount:0
mapping:0000000000000000 index:0x0 pfn:0x10d471
[   44.296193][ T9495] flags: 0x57ff00000000000(node=1|zone=2|lastcpupid=0x7ff)
[   44.296202][ T9495] page_type: f5(slab)
[   44.296212][ T9495] raw: 057ff00000000000 ffff88801b041640
dead000000000100 dead000000000122
[   44.296217][ T9495] raw: 0000000000000000 0000000000800080
00000000f5000000 0000000000000000
[   44.296220][ T9495] page dumped because: kasan: bad access detected
[   44.296226][ T9495] page_owner tracks the page as allocated
[   44.296229][ T9495] page last allocated via order 0, migratetype
Unmovable, gfp_mask
0xd2c00(GFP_NOIO|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC),
pid 1, tgid 1 (swapper/0), ts 3657058998
[   44.296240][ T9495]  post_alloc_hook+0x1f9/0x250
[   44.296247][ T9495]  get_page_from_freelist+0x235a/0x23e0
[   44.296255][ T9495]  __alloc_frozen_pages_noprof+0x217/0x5a0
[   44.296262][ T9495]  allocate_slab+0x7d/0x610
[   44.296267][ T9495]  refill_objects+0x2d6/0x350
[   44.296272][ T9495]  __pcs_replace_empty_main+0x2c9/0x6c0
[   44.296281][ T9495]  __kmalloc_noprof+0x48b/0x720
[   44.296288][ T9495]  usb_hcd_submit_urb+0x7a3/0x1b40
[   44.296301][ T9495]  usb_start_wait_urb+0x13f/0x5b0
[   44.296308][ T9495]  usb_control_msg+0x234/0x3e0
[   44.296314][ T9495]  hub_power_on+0x1b6/0x460
[   44.296320][ T9495]  hub_activate+0x345/0x1a80
[   44.296327][ T9495]  hub_probe+0x291e/0x3c10
[   44.296334][ T9495]  usb_probe_interface+0x71f/0xe00
[   44.296342][ T9495]  really_probe+0x267/0xaf0
[   44.296366][ T9495]  __driver_probe_device+0x1e2/0x350
[   44.296372][ T9495] page_owner free stack trace missing
[   44.296375][ T9495]
[   44.296377][ T9495] Memory state around the buggy address:
[   44.296381][ T9495]  ffff88810d471900: 00 04 fc fc 00 07 fc fc 00
00 fc fc 00 01 fc fc
[   44.296385][ T9495]  ffff88810d471980: 00 01 fc fc 00 01 fc fc fa
fb fc fc 00 01 fc fc
[   44.296389][ T9495] >ffff88810d471a00: 00 03 fc fc fa fb fc fc fa
fb fc fc 00 01 fc fc
[   44.296393][ T9495]                       ^
[   44.296396][ T9495]  ffff88810d471a80: fa fb fc fc fa fb fc fc 00
00 fc fc 00 01 fc fc
[   44.296400][ T9495]  ffff88810d471b00: 00 01 fc fc 00 01 fc fc 00
05 fc fc 00 05 fc fc
[   44.296404][ T9495]
==================================================================
[   44.297569][ T9495] Kernel panic - not syncing: KASAN: panic_on_warn set ...
[   44.352486][ T9495] CPU: 1 UID: 0 PID: 9495 Comm: repro Not tainted
7.3.0-rc2-00099-g50d05c7c76c9 #1 PREEMPT(full)
[   44.353650][ T9495] Hardware name: QEMU Standard PC (Q35 + ICH9,
2009), BIOS 1.17.0-debian-1.17.0-1ubuntu1 04/01/2014
[   44.354609][ T9495] Call Trace:
[   44.354919][ T9495]  <TASK>
[   44.355192][ T9495]  vpanic+0x56d/0xa60
[   44.355639][ T9495]  ? __pfx_vpanic+0x10/0x10
[   44.356061][ T9495]  panic+0xc5/0xd0
[   44.356407][ T9495]  ? __pfx_panic+0x10/0x10
[   44.356831][ T9495]  ? preempt_schedule_thunk+0x16/0x40
[   44.357323][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.357800][ T9495]  ? preempt_schedule_thunk+0x16/0x40
[   44.358291][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.358771][ T9495]  check_panic_on_warn+0x89/0xb0
[   44.359225][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.359702][ T9495]  end_report+0x73/0x170
[   44.360095][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.360566][ T9495]  kasan_report+0x128/0x150
[   44.360998][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.361471][ T9495]  kasan_check_range+0x264/0x2c0
[   44.361929][ T9495]  ? gb_hid_raw_request+0x29c/0x860
[   44.362430][ T9495]  __asan_memcpy+0x40/0x70
[   44.362863][ T9495]  gb_hid_raw_request+0x29c/0x860
[   44.363348][ T9495]  ? __pfx_gb_hid_raw_request+0x10/0x10
[   44.363865][ T9495]  ? __hid_hw_raw_request+0xa7/0x140
[   44.364348][ T9495]  hidraw_send_report+0x2bf/0x540
[   44.364825][ T9495]  ? bpf_lsm_file_permission+0x9/0x20
[   44.365314][ T9495]  hidraw_write+0x91/0xd0
[   44.365786][ T9495]  ? __pfx_hidraw_write+0x10/0x10
[   44.366245][ T9495]  vfs_write+0x29a/0xb90
[   44.366636][ T9495]  ? __pfx_vfs_write+0x10/0x10
[   44.367076][ T9495]  ? __fget_files+0x2a/0x420
[   44.367500][ T9495]  ? __fget_files+0x2a/0x420
[   44.367924][ T9495]  ? __fget_files+0x3a0/0x420
[   44.368352][ T9495]  ? __fget_files+0x2a/0x420
[   44.368791][ T9495]  ksys_write+0x150/0x270
[   44.369188][ T9495]  ? __pfx_ksys_write+0x10/0x10
[   44.369633][ T9495]  do_syscall_64+0x155/0x510
[   44.370063][ T9495]  ? trace_irq_disable+0x3b/0x140
[   44.370523][ T9495]  ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   44.371077][ T9495]  ? clear_bhb_loop+0x30/0x80
[   44.371509][ T9495]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   44.372046][ T9495] RIP: 0033:0x4521d2
[   44.372407][ T9495] Code: 08 0f 85 e1 df ff ff 49 89 fb 48 89 f0 48
89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89
5c 24 08 0f 05 <c3> 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 f3 0f 1e fa
55 48 89 e5
[   44.374131][ T9495] RSP: 002b:00007ffcc5937968 EFLAGS: 00000246
ORIG_RAX: 0000000000000001
[   44.374887][ T9495] RAX: ffffffffffffffda RBX: 0000000000000001
RCX: 00000000004521d2
[   44.375673][ T9495] RDX: 0000000000000002 RSI: 00007ffcc5937af6
RDI: 0000000000000004
[   44.376381][ T9495] RBP: 00007ffcc5937990 R08: 0000000000000000
R09: 0000000000000000
[   44.377101][ T9495] R10: 0000000000000000 R11: 0000000000000246
R12: 00007ffcc5937c28
[   44.377812][ T9495] R13: 00007ffcc5937c38 R14: 0000000000000002
R15: 00000000004cba40
[   44.378522][ T9495]  </TASK>
[   44.379100][ T9495] Kernel Offset: disabled
[   44.379644][ T9495] Rebooting in 86400 seconds..

Regards,
SEFCOM Lab @ ASU

[-- Attachment #2: 211.patch --]
[-- Type: application/octet-stream, Size: 399 bytes --]

--- a/drivers/staging/greybus/hid.c
+++ b/drivers/staging/greybus/hid.c
@@ -97,7 +97,7 @@ static int gb_hid_set_report(struct gb_hid *ghid, u8 report_type, u8 report_id,
 {
 	struct gb_hid_set_report_request *request;
 	struct gb_operation *operation;
-	int ret, size = sizeof(*request) + len - 1;
+	int ret, size = sizeof(*request) + len;
 
 	ret = gb_pm_runtime_get_sync(ghid->bundle);
 	if (ret)

[-- Attachment #3: reproducer.c --]
[-- Type: application/octet-stream, Size: 16705 bytes --]

/*
 * 211-kasan-slab-out-of-bounds-write-in-gb-hid-raw-request
 */
#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>

#include <linux/usb/ch9.h>
#include <linux/usb/raw_gadget.h>

#define GREYBUS_HEADER_SIZE		8
#define GREYBUS_TYPE_RESPONSE_FLAG	0x80
#define GREYBUS_SVC_CPORT		0

#define GB_SVC_TYPE_PROTOCOL_VERSION	0x01
#define GB_SVC_TYPE_SVC_HELLO		0x02
#define GB_SVC_TYPE_CONN_CREATE		0x07
#define GB_SVC_TYPE_DME_PEER_GET	0x09
#define GB_SVC_TYPE_DME_PEER_SET	0x0a
#define GB_SVC_TYPE_INTF_SET_PWRM	0x10
#define GB_SVC_TYPE_MODULE_INSERTED	0x1f
#define GB_SVC_TYPE_INTF_VSYS_ENABLE	0x21
#define GB_SVC_TYPE_INTF_REFCLK_ENABLE	0x23
#define GB_SVC_TYPE_INTF_REFCLK_DISABLE	0x24
#define GB_SVC_TYPE_INTF_UNIPRO_ENABLE	0x25
#define GB_SVC_TYPE_INTF_ACTIVATE	0x27
#define GB_SVC_TYPE_INTF_RESUME		0x28

#define GB_CONTROL_TYPE_VERSION			0x01
#define GB_CONTROL_TYPE_GET_MANIFEST_SIZE	0x03
#define GB_CONTROL_TYPE_GET_MANIFEST		0x04
#define GB_CONTROL_TYPE_BUNDLE_SUSPEND		0x0f
#define GB_CONTROL_TYPE_BUNDLE_RESUME		0x10
#define GB_CONTROL_TYPE_BUNDLE_ACTIVATE		0x12
#define GB_CONTROL_TYPE_INTF_SUSPEND_PREPARE	0x13

#define GB_HID_TYPE_GET_DESC		0x02
#define GB_HID_TYPE_GET_REPORT_DESC	0x03

#define GB_APB_REQUEST_CPORT_COUNT	0x04
#define GB_APB_REQUEST_ARPC_RUN		0x12

#define AP_INTERFACE_ID			1
#define MODULE_INTERFACE_ID		2
#define MODULE_CPORT_HID		1	/* remote cport our manifest uses */

/* the three bulk endpoints es2_ap_probe() insists on, in descriptor order */
#define EP_ADDR_CPORT_IN		0x81
#define EP_ADDR_ARPC_IN			0x86
#define EP_ADDR_CPORT_OUT		0x02

static int raw_gadget_fd = -1;
static int cport_in_endpoint = -1, arpc_in_endpoint = -1, cport_out_endpoint = -1;

/* AP-side cport the SVC bound to our HID cport; -1 until CONN_CREATE says so */
static int hid_ap_cport = -1;
static uint16_t next_operation_id = 1;

static void die(const char *what)
{
	fprintf(stderr, "%s: %s\n", what, strerror(errno));
	_exit(1);
}

static void msleep(int milliseconds)
{
	struct timespec duration = { milliseconds / 1000,
				     (long)(milliseconds % 1000) * 1000000L };
	nanosleep(&duration, NULL);
}

/*
 * One helper for all four raw-gadget transfers: EP0_WRITE / EP0_READ and
 * EP_WRITE / EP_READ share the usb_raw_ep_io layout and differ only in the
 * direction the payload travels.
 */
static int raw_gadget_ep_io(unsigned long ioctl_request, int endpoint,
			    void *data, uint32_t length, int is_read)
{
	uint8_t buffer[sizeof(struct usb_raw_ep_io) + 4096];
	struct usb_raw_ep_io *io = (void *)buffer;
	int ret;

	if (length > 4096)
		length = 4096;
	io->ep = endpoint;
	io->flags = 0;
	io->length = length;
	if (!is_read && length)
		memcpy(io->data, data, length);
	ret = ioctl(raw_gadget_fd, ioctl_request, io);
	if (is_read && ret > 0 && data)
		memcpy(data, io->data, ret < (int)length ? ret : length);
	return ret;
}

#define ep0_write(data, length) \
	raw_gadget_ep_io(USB_RAW_IOCTL_EP0_WRITE, 0, (void *)(data), (length), 0)
#define ep0_read(data, length) \
	raw_gadget_ep_io(USB_RAW_IOCTL_EP0_READ, 0, (data), (length), 1)
#define ep_write(endpoint, data, length) \
	raw_gadget_ep_io(USB_RAW_IOCTL_EP_WRITE, (endpoint), (void *)(data), (length), 0)
#define ep_read(endpoint, data, length) \
	raw_gadget_ep_io(USB_RAW_IOCTL_EP_READ, (endpoint), (data), (length), 1)

static int enable_bulk_endpoint(uint8_t address)
{
	struct usb_endpoint_descriptor descriptor = {
		.bLength = USB_DT_ENDPOINT_SIZE,
		.bDescriptorType = USB_DT_ENDPOINT,
		.bEndpointAddress = address,
		.bmAttributes = USB_ENDPOINT_XFER_BULK,
		.wMaxPacketSize = 512,
	};

	return ioctl(raw_gadget_fd, USB_RAW_IOCTL_EP_ENABLE, &descriptor);
}

/* the es2 driver binds 18d1:1eaf ("APBridge") */
static struct usb_device_descriptor apbridge_device_descriptor = {
	.bLength = sizeof(struct usb_device_descriptor),
	.bDescriptorType = USB_DT_DEVICE,
	.bcdUSB = 0x0200,
	.bMaxPacketSize0 = 64,
	.idVendor = 0x18d1,
	.idProduct = 0x1eaf,
	.bcdDevice = 0x0100,
	.bNumConfigurations = 1,
};

static const uint8_t apbridge_config_descriptor[] = {
	9, USB_DT_CONFIG, (9 + 9 + 7 * 3) & 0xff, 0, 1, 1, 0, 0xa0, 0x32,
	9, USB_DT_INTERFACE, 0, 0, 3, 0xff, 0xff, 0xff, 0,
	7, USB_DT_ENDPOINT, EP_ADDR_CPORT_IN, USB_ENDPOINT_XFER_BULK, 0x00, 0x02, 0,
	7, USB_DT_ENDPOINT, EP_ADDR_ARPC_IN, USB_ENDPOINT_XFER_BULK, 0x00, 0x02, 0,
	7, USB_DT_ENDPOINT, EP_ADDR_CPORT_OUT, USB_ENDPOINT_XFER_BULK, 0x00, 0x02, 0,
};

/* the module-side manifest: one interface, one HID bundle, one cport */
static const uint8_t hid_module_manifest[] = {
	28, 0, 0x00, 0x01,			/* size, version 0.1 */
	8, 0, 0x01 /* INTERFACE */, 0,   0, 0, 0, 0,
	8, 0, 0x03 /* BUNDLE */, 0,      1, 0x05 /* class HID */, 0, 0,
	8, 0, 0x04 /* CPORT */, 0,       MODULE_CPORT_HID, 0, 1, 0x05,
};

/*
 * One vendor-defined output report and nothing else. An input or feature
 * report would make gb_hid_start() issue a GB_HID_TYPE_GET_REPORT per report
 * before the hidraw node appears; with neither, that round trip never happens.
 */
static const uint8_t hid_report_descriptor[] = {
	0x06, 0x00, 0xff,	/* Usage Page (Vendor Defined 0xff00)	*/
	0x09, 0x01,		/* Usage (0x01)				*/
	0xa1, 0x01,		/* Collection (Application)		*/
	0x09, 0x02,		/*   Usage (0x02)			*/
	0x15, 0x00,		/*   Logical Minimum (0)		*/
	0x26, 0xff, 0x00,	/*   Logical Maximum (255)		*/
	0x75, 0x08,		/*   Report Size (8)			*/
	0x95, 0x08,		/*   Report Count (8)			*/
	0x91, 0x02,		/*   Output (Data,Var,Abs)		*/
	0xc0,			/* End Collection			*/
};

static void greybus_send(uint8_t hd_cport, uint8_t type, uint16_t operation_id,
			 const void *payload, uint16_t payload_len)
{
	uint8_t buffer[2048];
	uint16_t size = GREYBUS_HEADER_SIZE + payload_len;

	if (size > sizeof(buffer))
		return;
	buffer[0] = size & 0xff;
	buffer[1] = size >> 8;
	buffer[2] = operation_id & 0xff;
	buffer[3] = operation_id >> 8;
	buffer[4] = type;
	buffer[5] = 0;		/* result */
	buffer[6] = hd_cport;	/* es2 packs the cport id into pad[0] */
	buffer[7] = 0;
	if (payload_len)
		memcpy(buffer + GREYBUS_HEADER_SIZE, payload, payload_len);
	ep_write(cport_in_endpoint, buffer, size);
}

static void greybus_send_request(uint8_t hd_cport, uint8_t type,
				 const void *payload, uint16_t payload_len)
{
	greybus_send(hd_cport, type, next_operation_id++, payload, payload_len);
}

static void greybus_send_response(uint8_t hd_cport, uint16_t operation_id,
				  uint8_t type, const void *payload,
				  uint16_t payload_len)
{
	greybus_send(hd_cport, type | GREYBUS_TYPE_RESPONSE_FLAG, operation_id,
		     payload, payload_len);
}

static void handle_svc_request(uint16_t operation_id, uint8_t type,
			       const uint8_t *payload, int payload_len)
{
	uint8_t response[8] = { 0 };
	uint16_t response_len = 0;

	switch (type) {
	case GB_SVC_TYPE_CONN_CREATE:
		/* intf1, cport1(le16), intf2, cport2(le16), tc, flags */
		if (payload_len >= 8 &&
		    (payload[4] | (payload[5] << 8)) == MODULE_CPORT_HID)
			hid_ap_cport = payload[1] | (payload[2] << 8);
		break;
	case GB_SVC_TYPE_DME_PEER_GET: {
		/*
		 * gb_interface_read_dme() rejects any DDBL1_MANUFACTURERID
		 * other than TOSHIBA_DMID, so 0x5003 must read back 0x126.
		 * GMP_INIT_STATUS (0x6101) must be nonzero and its top byte is
		 * the init status; 0x02 selects the ES3-bootrom quirk set.
		 * Every other attribute the AP reads is cosmetic but nonzero.
		 */
		uint16_t attribute = payload_len >= 3 ?
			(payload[1] | (payload[2] << 8)) : 0;
		uint32_t value = attribute == 0x5003 ? 0x0126 :
				 attribute == 0x6101 ? 0x02000000 : 1;

		response[2] = value;		/* [0..1] is result_code == 0 */
		response[3] = value >> 8;
		response[4] = value >> 16;
		response[5] = value >> 24;
		response_len = 6;
		break;
	}
	case GB_SVC_TYPE_DME_PEER_SET:
		response_len = 2;		/* le16 result_code */
		break;
	case GB_SVC_TYPE_INTF_ACTIVATE:
		response[1] = 0x03;		/* GB_SVC_INTF_TYPE_GREYBUS */
		response_len = 2;		/* status, intf_type */
		break;
	case GB_SVC_TYPE_INTF_VSYS_ENABLE:
	case GB_SVC_TYPE_INTF_REFCLK_ENABLE:
	case GB_SVC_TYPE_INTF_REFCLK_DISABLE:
	case GB_SVC_TYPE_INTF_UNIPRO_ENABLE:
	case GB_SVC_TYPE_INTF_SET_PWRM:
	case GB_SVC_TYPE_INTF_RESUME:
		response_len = 1;		/* bare status byte */
		break;
	default:
		break;			/* device-id, route-create, ping, ... */
	}
	greybus_send_response(GREYBUS_SVC_CPORT, operation_id, type,
			      response, response_len);
}

static void handle_control_request(uint8_t hd_cport, uint16_t operation_id,
				   uint8_t type)
{
	uint8_t response[2] = { 0 };
	const uint8_t *payload = response;
	uint16_t payload_len = 0;

	switch (type) {
	case GB_CONTROL_TYPE_VERSION:
		response[1] = 1;		/* major 0, minor 1 */
		payload_len = 2;
		break;
	case GB_CONTROL_TYPE_GET_MANIFEST_SIZE:
		response[0] = sizeof(hid_module_manifest);
		payload_len = 2;
		break;
	case GB_CONTROL_TYPE_GET_MANIFEST:
		payload = hid_module_manifest;
		payload_len = sizeof(hid_module_manifest);
		break;
	case GB_CONTROL_TYPE_BUNDLE_SUSPEND:
	case GB_CONTROL_TYPE_BUNDLE_RESUME:
	case GB_CONTROL_TYPE_BUNDLE_ACTIVATE:
	case GB_CONTROL_TYPE_INTF_SUSPEND_PREPARE:
		payload_len = 1;		/* bare status byte */
		break;
	default:
		break;			/* connected, disconnected, ... */
	}
	greybus_send_response(hd_cport, operation_id, type, payload, payload_len);
}

static void handle_hid_request(uint8_t hd_cport, uint16_t operation_id,
			       uint8_t type)
{
	uint8_t descriptor_response[10] = { 0 };
	const uint8_t *payload = descriptor_response;
	uint16_t payload_len = 0;

	switch (type) {
	case GB_HID_TYPE_GET_DESC:
		descriptor_response[0] = 10;				/* bLength */
		descriptor_response[1] = sizeof(hid_report_descriptor);	/* wReportDescLength */
		descriptor_response[3] = 0x11;				/* bcdHID 0x0111 */
		descriptor_response[4] = 0x01;
		descriptor_response[5] = 0x02;				/* wProductID */
		descriptor_response[7] = 0x01;				/* wVendorID */
		payload_len = 10;
		break;
	case GB_HID_TYPE_GET_REPORT_DESC:
		payload = hid_report_descriptor;
		payload_len = sizeof(hid_report_descriptor);
		break;
	default:
		break;			/* power on/off, ... */
	}
	greybus_send_response(hd_cport, operation_id, type, payload, payload_len);
}

static void *cport_out_reader_thread(void *unused)
{
	uint8_t buffer[2048];
	uint8_t svc_version[2] = { 0x00, 0x01 };

	/* kick the SVC handshake off */
	greybus_send_request(GREYBUS_SVC_CPORT, GB_SVC_TYPE_PROTOCOL_VERSION,
			     svc_version, 2);

	for (;;) {
		int nbytes = ep_read(cport_out_endpoint, buffer, sizeof(buffer));
		uint16_t operation_id;
		uint8_t type, hd_cport;

		if (nbytes < GREYBUS_HEADER_SIZE) {
			if (nbytes < 0 && (errno == ESHUTDOWN || errno == ENODEV))
				break;
			if (nbytes < 0)
				msleep(5);
			continue;
		}
		operation_id = buffer[2] | (buffer[3] << 8);
		type = buffer[4];
		hd_cport = buffer[6];

		if (type & GREYBUS_TYPE_RESPONSE_FLAG) {
			/* the only responses we act on chain the SVC handshake */
			if (hd_cport != GREYBUS_SVC_CPORT)
				continue;
			if (type == (GB_SVC_TYPE_PROTOCOL_VERSION |
				     GREYBUS_TYPE_RESPONSE_FLAG)) {
				uint8_t hello[3] = { 0x55, 0x47, AP_INTERFACE_ID };

				greybus_send_request(GREYBUS_SVC_CPORT,
						     GB_SVC_TYPE_SVC_HELLO,
						     hello, 3);
			} else if (type == (GB_SVC_TYPE_SVC_HELLO |
					    GREYBUS_TYPE_RESPONSE_FLAG)) {
				uint8_t module_inserted[4] = {
					MODULE_INTERFACE_ID, 1, 0, 0
				};

				greybus_send_request(GREYBUS_SVC_CPORT,
						     GB_SVC_TYPE_MODULE_INSERTED,
						     module_inserted, 4);
			}
			continue;
		}

		if (hd_cport == GREYBUS_SVC_CPORT)
			handle_svc_request(operation_id, type,
					   buffer + GREYBUS_HEADER_SIZE,
					   nbytes - GREYBUS_HEADER_SIZE);
		else if (hd_cport == hid_ap_cport)
			handle_hid_request(hd_cport, operation_id, type);
		else
			handle_control_request(hd_cport, operation_id, type);
	}
	return NULL;
}

static void handle_ep0_control_request(const struct usb_ctrlrequest *ctrl)
{
	uint8_t data[4096];
	uint16_t wLength = ctrl->wLength;
	int length = -1;

	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			if ((ctrl->wValue >> 8) == USB_DT_DEVICE) {
				length = sizeof(apbridge_device_descriptor);
				memcpy(data, &apbridge_device_descriptor, length);
			} else if ((ctrl->wValue >> 8) == USB_DT_CONFIG) {
				length = sizeof(apbridge_config_descriptor);
				memcpy(data, apbridge_config_descriptor, length);
			}
			break;
		case USB_REQ_SET_CONFIGURATION:
			ioctl(raw_gadget_fd, USB_RAW_IOCTL_CONFIGURE, 0);
			cport_in_endpoint = enable_bulk_endpoint(EP_ADDR_CPORT_IN);
			arpc_in_endpoint = enable_bulk_endpoint(EP_ADDR_ARPC_IN);
			cport_out_endpoint = enable_bulk_endpoint(EP_ADDR_CPORT_OUT);
			length = 0;
			break;
		}
	} else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
		if (ctrl->bRequestType & USB_DIR_IN) {
			/* CPORT_COUNT is the only vendor IN request es2 makes */
			if (ctrl->bRequest == GB_APB_REQUEST_CPORT_COUNT) {
				data[0] = 32;	/* plenty; must exceed 17 */
				data[1] = 0;
				length = 2;
			}
		} else {
			memset(data, 0, sizeof(data));
			ep0_read(data, wLength);
			if (ctrl->bRequest == GB_APB_REQUEST_ARPC_RUN &&
			    wLength >= 5) {
				/* echo the le16 ARPC id back, then ARPC_SUCCESS */
				uint8_t arpc_response[3] = { data[0], data[1], 0 };

				ep_write(arpc_in_endpoint, arpc_response, 3);
			}
			return;		/* data stage already consumed */
		}
	}

	if (length < 0) {
		ioctl(raw_gadget_fd, USB_RAW_IOCTL_EP0_STALL, 0);
		return;
	}
	/*
	 * raw-gadget marks a transfer with no IN data stage as "out pending",
	 * so the status stage of a 0-length request is acknowledged with
	 * EP0_READ, not EP0_WRITE.
	 */
	if ((ctrl->bRequestType & USB_DIR_IN) && wLength) {
		if (length > wLength)
			length = wLength;
		ep0_write(data, length);
	} else {
		ep0_read(data, wLength);
	}
}

static void *ep0_control_thread(void *unused)
{
	uint8_t buffer[sizeof(struct usb_raw_event) + 4096];
	struct usb_raw_event *event = (void *)buffer;

	for (;;) {
		event->type = 0;
		event->length = 4096;
		if (ioctl(raw_gadget_fd, USB_RAW_IOCTL_EVENT_FETCH, event) < 0) {
			if (errno == EINTR)
				continue;
			break;
		}
		if (event->type == USB_RAW_EVENT_CONTROL)
			handle_ep0_control_request(
				(struct usb_ctrlrequest *)event->data);
		else if (event->type == USB_RAW_EVENT_DISCONNECT)
			break;
	}
	return NULL;
}

int main(void)
{
	struct usb_raw_init init;
	struct dirent *udc_entry;
	DIR *udc_dir;
	pthread_t thread;
	unsigned char report[2];
	char *udc_index;
	int hidraw_fd = -1, i;

	/* dummy_hcd numbers its UDCs, so the name must be discovered:
	 * device "dummy_udc.2" belongs to driver "dummy_udc". */
	udc_dir = opendir("/sys/class/udc");
	while (udc_dir && (udc_entry = readdir(udc_dir)) && udc_entry->d_name[0] == '.')
		;
	if (!udc_dir || !udc_entry)
		die("no UDC in /sys/class/udc (dummy_hcd missing?)");
	memset(&init, 0, sizeof(init));
	snprintf((char *)init.device_name, UDC_NAME_LENGTH_MAX, "%s", udc_entry->d_name);
	snprintf((char *)init.driver_name, UDC_NAME_LENGTH_MAX, "%s", udc_entry->d_name);
	closedir(udc_dir);
	udc_index = strrchr((char *)init.driver_name, '.');
	if (udc_index)
		*udc_index = 0;
	init.speed = USB_SPEED_HIGH;

	raw_gadget_fd = open("/dev/raw-gadget", O_RDWR);
	if (raw_gadget_fd < 0)
		die("open(/dev/raw-gadget)");
	if (ioctl(raw_gadget_fd, USB_RAW_IOCTL_INIT, &init) < 0)
		die("USB_RAW_IOCTL_INIT");
	if (ioctl(raw_gadget_fd, USB_RAW_IOCTL_RUN, 0) < 0)
		die("USB_RAW_IOCTL_RUN");

	pthread_create(&thread, NULL, ep0_control_thread, NULL);
	for (i = 0; i < 500 && cport_out_endpoint < 0; i++)
		msleep(10);
	if (cport_in_endpoint < 0 || arpc_in_endpoint < 0 || cport_out_endpoint < 0)
		die("gadget never got configured");

	pthread_create(&thread, NULL, cport_out_reader_thread, NULL);

	/* wait for gb-hid to enumerate the bundle and register a hidraw node */
	for (i = 0; i < 300 && hidraw_fd < 0; i++) {
		hidraw_fd = open("/dev/hidraw0", O_RDWR);
		if (hidraw_fd < 0)
			msleep(100);
	}
	if (hidraw_fd < 0)
		die("no hidraw device appeared");

	/*
	 * Report id 0, 2 bytes. gb_hid_set_report() sizes the greybus request
	 * as sizeof(struct gb_hid_set_report_request) + len - 1, but that
	 * struct ends in a true flexible array, so the payload has room for
	 * only len - 1 report bytes while the memcpy copies len of them.
	 * hidraw_write() rejects anything shorter than 2 bytes, and buf[0]
	 * must equal the report number for gb_hid_raw_request() to take the
	 * HID_REQ_SET_REPORT path.
	 */
	report[0] = 0x00;
	report[1] = 0x41;
	write(hidraw_fd, report, sizeof(report));
	return 0;
}

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

* Re: [BUG] KASAN: slab-out-of-bounds Write in gb_hid_raw_request
  2026-09-10  1:38 [BUG] KASAN: slab-out-of-bounds Write in gb_hid_raw_request Farhad Alemi
@ 2026-09-10  6:10 ` Greg Kroah-Hartman
  0 siblings, 0 replies; 2+ messages in thread
From: Greg Kroah-Hartman @ 2026-09-10  6:10 UTC (permalink / raw)
  To: Farhad Alemi
  Cc: Viresh Kumar, Johan Hovold, Alex Elder, Farhad Alemi, greybus-dev,
	linux-staging, linux-kernel

On Wed, Sep 09, 2026 at 06:38:02PM -0700, Farhad Alemi wrote:
> Hello,
> 
> We are reporting the following crash (reproducer and a proposed patch attached):

Great, please submit the patch properly so that we can review and apply
it if it works.

> Linux version 7.3.0-rc2 50d05c7c76c96b90462f24debacca971d2e86713
> Build Config: UpstreamAppArmorKASAN (KASAN + UBSAN, panic_on_warn=1)
> 
> [   44.000772][  T804] usb 3-1: new high-speed USB device number 2
> using dummy_hcd
> [   44.163699][  T804] usb 3-1: New USB device found, idVendor=18d1,
> idProduct=1eaf, bcdDevice= 1.00
> [   44.169786][  T804] usb 3-1: New USB device strings: Mfr=0,
> Product=0, SerialNumber=0
> [   44.212054][   T12] greybus 1-svc: set power mode = 0
> [   44.212064][   T12] greybus 1-svc: power mode change failed on AP
> to switch link: -5
> [   44.213758][    C1] greybus greybus1: 0/0:0: short response 0x94
> received (8 < 9)
> [   44.215179][ T9337] greybus greybus1: 0/0:0: synchronous operation
> id 0x0003 of type 0x14 failed: -90
> [   44.215216][ T9337] greybus 1-svc: failed to get rail count: -90
> [   44.234071][ T9337] greybus 1-2.2: Interface added (greybus)
> [   44.234080][ T9337] greybus 1-2.2: GMP VID=0x00000001, PID=0x00000001
> [   44.234087][ T9337] greybus 1-2.2: DDBL1 Manufacturer=0x00000126,

I'm guessing this is an emulated device, not a real one?

thanks,

greg k-h

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

end of thread, other threads:[~2026-09-10  6:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-10  1:38 [BUG] KASAN: slab-out-of-bounds Write in gb_hid_raw_request Farhad Alemi
2026-09-10  6:10 ` Greg Kroah-Hartman

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