Greeting,
FYI, we noticed BUG:KASAN:slab-out-of-bounds_in_kmemdup due to commit (built with gcc-11):
commit: 885b4af99f79cf1e1f3afb0323f9b6cb8b265fee ("[PATCH hid v11 09/14] HID: bpf: allow to change the report descriptor")
url: https://github.com/intel-lab-lkp/linux/commits/Benjamin-Tissoires/Introduce-eBPF-support-for-HID-devices/20221025-173852
base: https://git.kernel.org/cgit/linux/kernel/git/hid/hid.git master
patch link: https://lore.kernel.org/lkml/20221025093458.457089-10-benjamin.tissoires@redhat.com
patch subject: [PATCH hid v11 09/14] HID: bpf: allow to change the report descriptor
in testcase: kernel-selftests
version: kernel-selftests-x86_64-9313ba54-1_20221017
with following parameters:
sc_nr_hugepages: 2
group: vm
test-description: The kernel contains a set of "self tests" under the tools/testing/selftests/ directory. These are intended to be small unit tests to exercise individual code paths in the kernel.
test-url: https://www.kernel.org/doc/Documentation/kselftest.txt
on test machine: 128 threads 2 sockets Intel(R) Xeon(R) Platinum 8358 CPU @ 2.60GHz (Ice Lake) with 128G memory
caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace):
If you fix the issue, kindly add following tag
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Link: https://lore.kernel.org/oe-lkp/202210312248.4040feba-oliver.sang@intel.com
[ 52.216359][ T712] BUG: KASAN: slab-out-of-bounds in kmemdup (??:?)
[ 52.216359][ T712] Read of size 4096 at addr ff11001095bf1600 by task kworker/0:2/712
[ 52.216359][ T712]
[ 52.216359][ T712] CPU: 0 PID: 712 Comm: kworker/0:2 Not tainted 6.1.0-rc1-00225-g885b4af99f79 #1
[ 52.233046][ T1] pin0d, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] Workqueue: usb_hub_wq hub_event
[ 52.216359][ T712] Call Trace:
[ 52.216359][ T712] <TASK>
[ 52.216359][ T712] dump_stack_lvl (??:?)
[ 52.216359][ T712] print_address_description+0x87/0x2a1
[ 52.247482][ T1] pin0e, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] print_report (report.c:?)
[ 52.216359][ T712] ? kasan_addr_to_slab (??:?)
[ 52.258662][ T1] pin0f, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? kmemdup (??:?)
[ 52.216359][ T712] kasan_report (??:?)
[ 52.272200][ T1] pin10, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? kmemdup (??:?)
[ 52.216359][ T712] kasan_check_range (??:?)
[ 52.278146][ T1] pin11, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] memcpy (??:?)
[ 52.216359][ T712] kmemdup (??:?)
[ 52.288942][ T1] pin12, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] call_hid_bpf_rdesc_fixup (??:?)
[ 52.216359][ T712] ? hid_bpf_disconnect_device (??:?)
[ 52.302011][ T1] pin13, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? hid_lookup_quirk (??:?)
[ 52.216359][ T712] ? lock_release (??:?)
[ 52.216359][ T712] ? __mutex_unlock_slowpath (mutex.c:?)
[ 52.216359][ T712] ? mutex_lock_io_nested (??:?)
[ 52.315484][ T1] pin14, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] hid_open_report (??:?)
[ 52.216359][ T712] ? hid_process_report (??:?)
[ 52.323592][ T1] pin15, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] hid_generic_probe (hid-generic.c:?)
[ 52.216359][ T712] hid_device_probe (hid-core.c:?)
[ 52.216359][ T712] really_probe (dd.c:?)
[ 52.336327][ T1] pin16, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] __driver_probe_device (dd.c:?)
[ 52.216359][ T712] driver_probe_device (dd.c:?)
[ 52.216359][ T712] __device_attach_driver (dd.c:?)
[ 52.216359][ T712] ? driver_allows_async_probing (dd.c:?)
[ 52.216359][ T712] bus_for_each_drv (??:?)
[ 52.349636][ T1] pin17, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? bus_for_each_dev (??:?)
[ 52.216359][ T712] ? lockdep_hardirqs_on_prepare (lockdep.c:?)
[ 52.357053][ T1] pin18, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? lockdep_hardirqs_on (??:?)
[ 52.216359][ T712] ? _raw_spin_unlock_irqrestore (??:?)
[ 52.371058][ T1] pin19, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] __device_attach (dd.c:?)
[ 52.216359][ T712] ? device_driver_attach (dd.c:?)
[ 52.385237][ T1] pin1a, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] bus_probe_device (??:?)
[ 52.394562][ T1] pin1b, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] device_add (??:?)
[ 52.216359][ T712] ? __up_write (rwsem.c:?)
[ 52.405466][ T1] pin1c, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? __debugfs_create_file (inode.c:?)
[ 52.216359][ T712] ? __fw_devlink_link_to_suppliers (??:?)
[ 52.216359][ T712] ? __debugfs_create_file (inode.c:?)
[ 52.216359][ T712] hid_add_device (??:?)
[ 52.418760][ T1] pin1d, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? lockdep_init_map_type (??:?)
[ 52.216359][ T712] ? modalias_show (pci-sysfs.c:?)
[ 52.432504][ T1] pin1e, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? lockdep_count_forward_deps (??:?)
[ 52.216359][ T712] usbhid_probe (hid-core.c:?)
[ 52.441830][ T1] pin1f, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] usb_probe_interface (driver.c:?)
[ 52.454895][ T1] pin20, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] really_probe (dd.c:?)
[ 52.216359][ T712] __driver_probe_device (dd.c:?)
[ 52.465003][ T1] pin21, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? usb_match_id (driver.c:?)
[ 52.216359][ T712] driver_probe_device (dd.c:?)
[ 52.216359][ T712] __device_attach_driver (dd.c:?)
[ 52.216359][ T712] ? driver_allows_async_probing (dd.c:?)
[ 52.216359][ T712] bus_for_each_drv (??:?)
[ 52.216359][ T712] ? bus_for_each_dev (??:?)
[ 52.475962][ T1] pin22, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? lockdep_hardirqs_on_prepare (lockdep.c:?)
[ 52.216359][ T712] ? lockdep_hardirqs_on (??:?)
[ 52.489358][ T1] pin23, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? _raw_spin_unlock_irqrestore (??:?)
[ 52.216359][ T712] __device_attach (dd.c:?)
[ 52.500677][ T1] pin24, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? device_driver_attach (dd.c:?)
[ 52.216359][ T712] bus_probe_device (??:?)
[ 52.514423][ T1] pin25, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] device_add (??:?)
[ 52.216359][ T712] ? __fw_devlink_link_to_suppliers (??:?)
[ 52.528774][ T1] pin26, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? usb_cache_string (??:?)
[ 52.216359][ T712] usb_set_configuration (??:?)
[ 52.538619][ T1] pin27, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? kernfs_create_link (??:?)
[ 52.552017][ T1] pin28, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
[ 52.216359][ T712] ? do_raw_spin_unlock (??:?)
[ 52.216359][ T712] usb_generic_driver_probe (??:?)
[ 52.564984][ T1] pin29, disabled, edge , high, V(00), IRR(0), S(0), physical, D(0000), M(0)
To reproduce:
git clone https://github.com/intel/lkp-tests.git
cd lkp-tests
sudo bin/lkp install job.yaml # job file is attached in this email
bin/lkp split-job --compatible job.yaml # generate the yaml file for lkp run
sudo bin/lkp run generated-yaml-file
# if come across any failure that blocks the test,
# please remove ~/.lkp and /lkp dir to run from a clean state.
@@ -85,6 +85,63 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
}
EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
+/**
+ * hid_bpf_rdesc_fixup - Called when the probe function parses the report
+ * descriptor of the HID device
+ *
+ * @ctx: The HID-BPF context
+ *
+ * @return 0 on success and keep processing; a positive value to change the
+ * incoming size buffer; a negative error code to interrupt the processing
+ * of this event
+ *
+ * Declare an %fmod_ret tracing bpf program to this function and attach this
+ * program through hid_bpf_attach_prog() to have this helper called before any
+ * parsing of the report descriptor by HID.
+ */
+/* never used by the kernel but declared so we can load and attach a tracepoint */
+__weak noinline int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+ALLOW_ERROR_INJECTION(hid_bpf_rdesc_fixup, ERRNO);
+
+u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size)
+{
+ int ret;
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .size = *size,
+ .allocated_size = HID_MAX_DESCRIPTOR_SIZE,
+ },
+ };
+
+ ctx_kern.data = kmemdup(rdesc, ctx_kern.ctx.allocated_size, GFP_KERNEL);
+ if (!ctx_kern.data)
+ goto ignore_bpf;
+
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern);
+ if (ret < 0)
+ goto ignore_bpf;
+
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ goto ignore_bpf;
+
+ *size = ret;
+ }
+
+ rdesc = krealloc(ctx_kern.data, *size, GFP_KERNEL);
+
+ return rdesc;
+
+ ignore_bpf:
+ kfree(ctx_kern.data);
+ return kmemdup(rdesc, *size, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
+
/**
* hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
*
@@ -176,6 +233,14 @@ static int hid_bpf_allocate_event_data(struct hid_device *hdev)
return __hid_bpf_allocate_data(hdev, &hdev->bpf.device_data, &hdev->bpf.allocated_data);
}
+int hid_bpf_reconnect(struct hid_device *hdev)
+{
+ if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status))
+ return device_reprobe(&hdev->dev);
+
+ return 0;
+}
+
/**
* hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
*
@@ -217,7 +282,17 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
return err;
}
- return __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
+ err = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
+ if (err)
+ return err;
+
+ if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) {
+ err = hid_bpf_reconnect(hdev);
+ if (err)
+ return err;
+ }
+
+ return 0;
}
/**
@@ -18,6 +18,7 @@ int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_t
void __hid_bpf_destroy_device(struct hid_device *hdev);
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
struct hid_bpf_ctx_kern *ctx_kern);
+int hid_bpf_reconnect(struct hid_device *hdev);
struct bpf_prog;
@@ -58,12 +58,15 @@ static DECLARE_WORK(release_work, hid_bpf_release_progs);
BTF_ID_LIST(hid_bpf_btf_ids)
BTF_ID(func, hid_bpf_device_event) /* HID_BPF_PROG_TYPE_DEVICE_EVENT */
+BTF_ID(func, hid_bpf_rdesc_fixup) /* HID_BPF_PROG_TYPE_RDESC_FIXUP */
static int hid_bpf_max_programs(enum hid_bpf_prog_type type)
{
switch (type) {
case HID_BPF_PROG_TYPE_DEVICE_EVENT:
return HID_BPF_MAX_PROGS_PER_DEV;
+ case HID_BPF_PROG_TYPE_RDESC_FIXUP:
+ return 1;
default:
return -EINVAL;
}
@@ -233,6 +236,10 @@ static void hid_bpf_release_progs(struct work_struct *work)
if (next->hdev == hdev && next->type == type)
next->hdev = NULL;
}
+
+ /* if type was rdesc fixup, reconnect device */
+ if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP)
+ hid_bpf_reconnect(hdev);
}
}
@@ -1218,7 +1218,8 @@ int hid_open_report(struct hid_device *device)
return -ENODEV;
size = device->dev_rsize;
- buf = kmemdup(start, size, GFP_KERNEL);
+ /* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */
+ buf = call_hid_bpf_rdesc_fixup(device, start, &size);
if (buf == NULL)
return -ENOMEM;
@@ -59,6 +59,7 @@ struct hid_bpf_ctx {
/* Following functions are tracepoints that BPF programs can attach to */
int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
+int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
/* Following functions are kfunc that we export to BPF programs */
/* available everywhere in HID-BPF */
@@ -85,6 +86,7 @@ int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx);
enum hid_bpf_prog_type {
HID_BPF_PROG_TYPE_UNDEF = -1,
HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */
+ HID_BPF_PROG_TYPE_RDESC_FIXUP,
HID_BPF_PROG_TYPE_MAX,
};
@@ -128,6 +130,7 @@ int hid_bpf_connect_device(struct hid_device *hdev);
void hid_bpf_disconnect_device(struct hid_device *hdev);
void hid_bpf_destroy_device(struct hid_device *hid);
void hid_bpf_device_init(struct hid_device *hid);
+u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
#else /* CONFIG_HID_BPF */
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
u8 *data, u32 *size, int interrupt) { return 0; }
@@ -135,6 +138,11 @@ static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
static inline void hid_bpf_device_init(struct hid_device *hid) {}
+static inline u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size)
+{
+ return kmemdup(rdesc, *size, GFP_KERNEL);
+}
+
#endif /* CONFIG_HID_BPF */
#endif /* __HID_BPF_H */