* [PATCH v2 0/2] HID: bpf: fix device destruction races @ 2026-11-03 2:45 Yifan Zhang 2026-11-03 2:45 ` [PATCH v2 2/2] HID: bpf: reject struct_ops registration during device destruction Yifan Zhang 2026-11-03 2:45 ` [PATCH v2 1/2] HID: bpf: synchronize hardware operations with " Yifan Zhang 0 siblings, 2 replies; 5+ messages in thread From: Yifan Zhang @ 2026-11-03 2:45 UTC (permalink / raw) To: Jiri Kosina, Benjamin Tissoires, linux-input Cc: Greg Kroah-Hartman, Alexei Starovoitov, bpf, linux-kernel These patches fix two HID-BPF races with device destruction. The first keeps report metadata and transport-private state alive across hardware operations. The second prevents struct_ops registration from publishing an entry after destruction has started. Changes in v2: - use a short lifetime admission lock and SRCU instead of holding prog_list_lock across low-level driver calls - acquire lifetime protection before looking up the HID report - clear ops->hdev on registration errors before dropping the device ref Yifan Zhang (2): HID: bpf: synchronize hardware operations with device destruction HID: bpf: reject struct_ops registration during device destruction drivers/hid/bpf/hid_bpf_dispatch.c | 73 ++++++++++++++++++++-------- drivers/hid/bpf/hid_bpf_struct_ops.c | 12 ++++- include/linux/hid_bpf.h | 1 + 3 files changed, 65 insertions(+), 21 deletions(-) -- 2.39.5 (Apple Git-154) ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] HID: bpf: reject struct_ops registration during device destruction 2026-11-03 2:45 [PATCH v2 0/2] HID: bpf: fix device destruction races Yifan Zhang @ 2026-11-03 2:45 ` Yifan Zhang 2026-11-03 3:00 ` sashiko-bot 2026-11-03 2:45 ` [PATCH v2 1/2] HID: bpf: synchronize hardware operations with " Yifan Zhang 1 sibling, 1 reply; 5+ messages in thread From: Yifan Zhang @ 2026-11-03 2:45 UTC (permalink / raw) To: Jiri Kosina, Benjamin Tissoires, linux-input Cc: Greg Kroah-Hartman, Alexei Starovoitov, bpf, linux-kernel hid_bpf_reg() can obtain a device reference before hid_destroy_device() removes the device from the bus, then block on prog_list_lock while HID-BPF destruction cleans the device's SRCU state. The registration path does not check the destroyed flag after taking the lock, so it can publish a new struct_ops entry and call synchronize_srcu() on the cleaned SRCU object. KASAN reports: BUG: KASAN: slab-use-after-free in check_init_srcu_struct Read of size 8 check_init_srcu_struct synchronize_srcu hid_bpf_reg bpf_struct_ops_link_create Check destroyed while holding prog_list_lock. Device destruction sets the flag while holding the same lock, so a registration either completes before destruction starts or fails with -ENODEV without accessing the SRCU state. Also clear ops->hdev on every registration error before dropping the device reference. This keeps a failed struct_ops instance reusable and prevents a dangling device pointer from reaching a later unregister operation. Fixes: ebc0d8093e8c ("HID: bpf: implement HID-BPF through bpf_struct_ops") Closes: https://lore.kernel.org/linux-input/179317460937.87455.1799017093083467190@stu.pku.edu.cn/ Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn> --- drivers/hid/bpf/hid_bpf_struct_ops.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index c90b68956cb3b..31e2cb146b92c 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -201,6 +201,11 @@ static int hid_bpf_reg(void *kdata, struct bpf_link *link) mutex_lock(&hdev->bpf.prog_list_lock); + if (READ_ONCE(hdev->bpf.destroyed)) { + err = -ENODEV; + goto out_unlock; + } + count = list_count_nodes(&hdev->bpf.prog_list); if (count >= HID_BPF_MAX_PROGS_PER_DEV) { err = -E2BIG; @@ -229,11 +234,14 @@ static int hid_bpf_reg(void *kdata, struct bpf_link *link) synchronize_srcu(&hdev->bpf.srcu); out_unlock: - mutex_unlock(&hdev->bpf.prog_list_lock); - if (err) { if (hdev->bpf.rdesc_ops == ops) hdev->bpf.rdesc_ops = NULL; + ops->hdev = NULL; + } + mutex_unlock(&hdev->bpf.prog_list_lock); + + if (err) { hid_put_device(hdev); } else if (ops->hid_rdesc_fixup) { hid_bpf_reconnect(hdev); -- 2.39.5 (Apple Git-154) ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] HID: bpf: reject struct_ops registration during device destruction 2026-11-03 2:45 ` [PATCH v2 2/2] HID: bpf: reject struct_ops registration during device destruction Yifan Zhang @ 2026-11-03 3:00 ` sashiko-bot 0 siblings, 0 replies; 5+ messages in thread From: sashiko-bot @ 2026-11-03 3:00 UTC (permalink / raw) To: Yifan Zhang, linux-input; +Cc: bpf, dmitry.torokhov Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Critical] HID: bpf: premature ops->hdev assignment before lock in hid_bpf_reg() -- commit 652bc4fabe060de525612119c444207ef100747a Author: Yifan Zhang <yfzhang23@stu.pku.edu.cn> HID: bpf: reject struct_ops registration during device destruction This commit checks hdev->bpf.destroyed while holding prog_list_lock in hid_bpf_reg() to avoid registering a struct_ops program and calling synchronize_srcu() after HID-BPF device destruction has cleaned up the device's SRCU state. It also clears ops->hdev under prog_list_lock on registration failure before dropping the device reference. > diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c > index c90b68956cb3b..31e2cb146b92c 100644 > --- a/drivers/hid/bpf/hid_bpf_struct_ops.c > +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c > @@ -201,6 +201,11 @@ static int hid_bpf_reg(void *kdata, struct bpf_link *link) > > mutex_lock(&hdev->bpf.prog_list_lock); > > + if (READ_ONCE(hdev->bpf.destroyed)) { > + err = -ENODEV; > + goto out_unlock; > + } > + > count = list_count_nodes(&hdev->bpf.prog_list); > if (count >= HID_BPF_MAX_PROGS_PER_DEV) { > err = -E2BIG; > @@ -229,11 +234,14 @@ static int hid_bpf_reg(void *kdata, struct bpf_link *link) > synchronize_srcu(&hdev->bpf.srcu); > > out_unlock: > - mutex_unlock(&hdev->bpf.prog_list_lock); > - > if (err) { > if (hdev->bpf.rdesc_ops == ops) > hdev->bpf.rdesc_ops = NULL; > + ops->hdev = NULL; > + } > + mutex_unlock(&hdev->bpf.prog_list_lock); > + > + if (err) { > hid_put_device(hdev); [Severity: Critical] In drivers/hid/bpf/hid_bpf_struct_ops.c, hid_bpf_reg() still assigns ops->hdev = hdev before acquiring hdev->bpf.prog_list_lock: drivers/hid/bpf/hid_bpf_struct_ops.c:hid_bpf_reg() { ... hdev = hid_get_device(ops->hid_id); if (IS_ERR(hdev)) return PTR_ERR(hdev); ops->hdev = hdev; mutex_lock(&hdev->bpf.prog_list_lock); } When a HID device with an attached struct_ops link is destroyed in hid_destroy_device() -> hid_bpf_destroy_device(), __hid_bpf_ops_destroy_device() clears ops->hdev = NULL under prog_list_lock and drops the link's device reference while leaving the existing bpf_link alive, and hid_bpf_destroy_device() then calls cleanup_srcu_struct(&hdev->bpf.srcu). Because hid_remove_device() has not called device_del(&hdev->dev) yet, hid_get_device() can still find hdev on hid_bus_type. If a concurrent bpf_struct_ops_link_create() on the same struct_ops map calls hid_bpf_reg(), it sees ops->hdev == NULL and writes ops->hdev = hdev before taking prog_list_lock. If the original struct_ops link is closed at the same time, bpf_struct_ops_map_link_dealloc() -> hid_bpf_unreg() runs without holding the map's update_mutex: drivers/hid/bpf/hid_bpf_struct_ops.c:hid_bpf_unreg() { ... hdev = ops->hdev; /* check if __hid_bpf_ops_destroy_device() has been called */ if (!hdev) return; mutex_lock(&hdev->bpf.prog_list_lock); if (!ops->hdev) { mutex_unlock(&hdev->bpf.prog_list_lock); return; } list_del_rcu(&ops->list); synchronize_srcu(&hdev->bpf.srcu); ops->hdev = NULL; ... hid_put_device(hdev); } Can hid_bpf_unreg() observe the newly written ops->hdev, acquire prog_list_lock before hid_bpf_reg(), bypass the !ops->hdev check, and call synchronize_srcu(&hdev->bpf.srcu) on the cleaned-up srcu_struct followed by a duplicate hid_put_device(hdev) when hid_bpf_reg() also drops its reference in the error path? Should ops->hdev only be checked and assigned after acquiring hdev->bpf.prog_list_lock and verifying that hdev->bpf.destroyed is false? -- Sashiko AI review · https://sashiko.dev/#/patchset/179367391951.8187.14164894863012056170@stu.pku.edu.cn?part=2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] HID: bpf: synchronize hardware operations with device destruction 2026-11-03 2:45 [PATCH v2 0/2] HID: bpf: fix device destruction races Yifan Zhang 2026-11-03 2:45 ` [PATCH v2 2/2] HID: bpf: reject struct_ops registration during device destruction Yifan Zhang @ 2026-11-03 2:45 ` Yifan Zhang 2026-11-03 3:00 ` Alexei Starovoitov 1 sibling, 1 reply; 5+ messages in thread From: Yifan Zhang @ 2026-11-03 2:45 UTC (permalink / raw) To: Jiri Kosina, Benjamin Tissoires, linux-input Cc: Greg Kroah-Hartman, Alexei Starovoitov, bpf, linux-kernel A HID-BPF syscall context pins struct hid_device, but it does not pin the transport-private data referenced by the low-level driver. A hardware request can therefore sleep in the UHID report-wait path while closing the UHID file destroys the HID device, wakes the waiter, and frees struct uhid_device. The awakened request then accesses the freed object. KASAN reports: BUG: KASAN: use-after-free in __uhid_report_queue_and_wait Read of size 1 uhid_hid_raw_request __hid_hw_raw_request hid_bpf_hw_request bpf_prog_test_run_syscall Add a lifetime lock that serializes admission of HID-BPF hardware operations with device destruction. Take an SRCU read lock while holding the lifetime lock before accessing the report tables or the low-level driver. Destruction marks the device destroyed under the same lock and waits for the SRCU readers before cleaning up the SRCU state. The lifetime lock is released before calling the low-level driver. This avoids reacquiring the same mutex through a reentrant low-level path and does not introduce a lock dependency on driver_input_lock. Fixes: 91a7f802d185 ("HID: bpf: introduce hid_hw_request()") Closes: https://lore.kernel.org/linux-input/179317460423.87432.1451672332362541157@stu.pku.edu.cn/ Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn> --- drivers/hid/bpf/hid_bpf_dispatch.c | 73 ++++++++++++++++++++++-------- include/linux/hid_bpf.h | 1 + 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 6b467c74601cb..0c0c8e9939f05 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -398,6 +398,18 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, return 0; } +static int hid_bpf_hw_operation_lock(struct hid_device *hdev) +{ + int idx = -ENODEV; + + mutex_lock(&hdev->bpf.lifetime_lock); + if (!READ_ONCE(hdev->bpf.destroyed)) + idx = srcu_read_lock(&hdev->bpf.srcu); + mutex_unlock(&hdev->bpf.lifetime_lock); + + return idx; +} + /** * hid_bpf_hw_request - Communicate with a HID device * @@ -416,17 +428,21 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, struct hid_bpf_ctx_kern *ctx_kern; size_t size = buf__sz; u8 *dma_data; - int ret; + int idx, ret; ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); if (ctx_kern->from_bpf) return -EDEADLOCK; + idx = hid_bpf_hw_operation_lock(ctx->hid); + if (idx < 0) + return idx; + /* check arguments */ ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype, true); if (ret) - return ret; + goto out_unlock; switch (reqtype) { case HID_REQ_GET_REPORT: @@ -437,21 +453,24 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, case HID_REQ_SET_PROTOCOL: break; default: - return -EINVAL; + ret = -EINVAL; + goto out_unlock; } dma_data = kmemdup(buf, size, GFP_KERNEL); - if (!dma_data) - return -ENOMEM; + if (!dma_data) { + ret = -ENOMEM; + goto out_unlock; + } ret = hid_ops->hid_hw_raw_request(ctx->hid, - dma_data[0], - dma_data, - size, - rtype, - reqtype, - (u64)(long)ctx, - true); /* prevent infinite recursions */ + dma_data[0], + dma_data, + size, + rtype, + reqtype, + (u64)(long)ctx, + true); /* prevent infinite recursions */ if (ret > (ssize_t)size) ret = size; @@ -459,6 +478,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, memcpy(buf, dma_data, ret); kfree(dma_data); +out_unlock: + srcu_read_unlock(&ctx->hid->bpf.srcu, idx); return ret; } @@ -477,24 +498,33 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) struct hid_bpf_ctx_kern *ctx_kern; size_t size = buf__sz; u8 *dma_data; - int ret; + int idx, ret; ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); if (ctx_kern->from_bpf) return -EDEADLOCK; + idx = hid_bpf_hw_operation_lock(ctx->hid); + if (idx < 0) + return idx; + /* check arguments */ ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT, true); if (ret) - return ret; + goto out_unlock; dma_data = kmemdup(buf, size, GFP_KERNEL); - if (!dma_data) - return -ENOMEM; + if (!dma_data) { + ret = -ENOMEM; + goto out_unlock; + } - ret = hid_ops->hid_hw_output_report(ctx->hid, dma_data, size, (u64)(long)ctx, true); + ret = hid_ops->hid_hw_output_report(ctx->hid, dma_data, size, + (u64)(long)ctx, true); kfree(dma_data); +out_unlock: + srcu_read_unlock(&ctx->hid->bpf.srcu, idx); return ret; } @@ -641,8 +671,12 @@ void hid_bpf_destroy_device(struct hid_device *hdev) if (!hdev) return; - /* mark the device as destroyed in bpf so we don't reattach it */ - hdev->bpf.destroyed = true; + /* Block new BPF hardware operations before transport teardown. */ + mutex_lock(&hdev->bpf.prog_list_lock); + mutex_lock(&hdev->bpf.lifetime_lock); + WRITE_ONCE(hdev->bpf.destroyed, true); + mutex_unlock(&hdev->bpf.lifetime_lock); + mutex_unlock(&hdev->bpf.prog_list_lock); __hid_bpf_ops_destroy_device(hdev); @@ -655,6 +689,7 @@ int hid_bpf_device_init(struct hid_device *hdev) { INIT_LIST_HEAD(&hdev->bpf.prog_list); mutex_init(&hdev->bpf.prog_list_lock); + mutex_init(&hdev->bpf.lifetime_lock); return init_srcu_struct(&hdev->bpf.srcu); } EXPORT_SYMBOL_GPL(hid_bpf_device_init); diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 19fffa4574a47..3624937d340b3 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -195,6 +195,7 @@ struct hid_bpf { struct hid_bpf_ops *rdesc_ops; struct list_head prog_list; struct mutex prog_list_lock; /* protects prog_list update */ + struct mutex lifetime_lock; /* protects destroyed and SRCU admission */ struct srcu_struct srcu; /* protects prog_list read-only access */ }; -- 2.39.5 (Apple Git-154) ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] HID: bpf: synchronize hardware operations with device destruction 2026-11-03 2:45 ` [PATCH v2 1/2] HID: bpf: synchronize hardware operations with " Yifan Zhang @ 2026-11-03 3:00 ` Alexei Starovoitov 0 siblings, 0 replies; 5+ messages in thread From: Alexei Starovoitov @ 2026-11-03 3:00 UTC (permalink / raw) To: Yifan Zhang, Jiri Kosina, Benjamin Tissoires, linux-input Cc: Greg Kroah-Hartman, bpf, linux-kernel On Mon, Nov 02, 2026 at 06:45 PM Yifan Zhang <yfzhang23@stu.pku.edu.cn> wrote: > Add a lifetime lock that serializes admission of HID-BPF hardware > operations with device destruction. Take an SRCU read lock while holding > the lifetime lock before accessing the report tables or the low-level > driver. Destruction marks the device destroyed under the same lock and > waits for the SRCU readers before cleaning up the SRCU state. The lifetime lock is needed only because hid_bpf_destroy_device() calls cleanup_srcu_struct(). After that a reference to hid_device is not enough to call srcu_read_lock(). The splat in patch 2 has the same cause. So does commit 578e1b96fad7 ("HID: bpf: abort dispatch if device destroyed"). Lets keep hdev->bpf.srcu valid until hiddev_free(). Then the check of 'destroyed' goes inside the SRCU section. No need for the 2nd mutex. The dispatchers have the same race and this patch leaves it. hid_bpf_destroy_device() runs before hidraw_disconnect(): hidraw ioctl hid_destroy_device() dispatch_hid_bpf_raw_requests() destroyed == false destroyed = true synchronize_srcu() cleanup_srcu_struct() srcu_read_lock() <- use after free hid_close_report() also runs on unbind and on device_reprobe(). SRCU doesn't cover that. Neither this patch nor the diff below fixes it. Instead of patches 1 and 2: and Pls wait for Benjamin before sending v3. diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 6b467c7..6c2b136 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -99,13 +99,15 @@ int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, struct hid_bpf_ops *e; int ret, idx; - if (unlikely(hdev->bpf.destroyed)) - return -ENODEV; - if (rtype >= HID_REPORT_TYPES) return -EINVAL; idx = srcu_read_lock(&hdev->bpf.srcu); + if (unlikely(hdev->bpf.destroyed)) { + ret = -ENODEV; + goto out; + } + list_for_each_entry_srcu(e, &hdev->bpf.prog_list, list, srcu_read_lock_held(&hdev->bpf.srcu)) { if (!e->hid_hw_request) @@ -139,10 +141,12 @@ int dispatch_hid_bpf_output_report(struct hid_device *hdev, struct hid_bpf_ops *e; int ret, idx; - if (unlikely(hdev->bpf.destroyed)) - return -ENODEV; - idx = srcu_read_lock(&hdev->bpf.srcu); + if (unlikely(hdev->bpf.destroyed)) { + ret = -ENODEV; + goto out; + } + list_for_each_entry_srcu(e, &hdev->bpf.prog_list, list, srcu_read_lock_held(&hdev->bpf.srcu)) { if (!e->hid_hw_output_report) @@ -423,6 +427,11 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, if (ctx_kern->from_bpf) return -EDEADLOCK; + /* hid_bpf_destroy_device() waits for us before the transport goes away */ + guard(srcu)(&ctx->hid->bpf.srcu); + if (ctx->hid->bpf.destroyed) + return -ENODEV; + /* check arguments */ ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype, true); if (ret) @@ -483,6 +492,10 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) if (ctx_kern->from_bpf) return -EDEADLOCK; + guard(srcu)(&ctx->hid->bpf.srcu); + if (ctx->hid->bpf.destroyed) + return -ENODEV; + /* check arguments */ ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT, true); if (ret) @@ -641,13 +654,9 @@ void hid_bpf_destroy_device(struct hid_device *hdev) if (!hdev) return; - /* mark the device as destroyed in bpf so we don't reattach it */ - hdev->bpf.destroyed = true; - __hid_bpf_ops_destroy_device(hdev); synchronize_srcu(&hdev->bpf.srcu); - cleanup_srcu_struct(&hdev->bpf.srcu); } EXPORT_SYMBOL_GPL(hid_bpf_destroy_device); @@ -659,6 +668,13 @@ int hid_bpf_device_init(struct hid_device *hdev) } EXPORT_SYMBOL_GPL(hid_bpf_device_init); +/* A reference to hdev is enough to use hdev->bpf.srcu */ +void hid_bpf_device_free(struct hid_device *hdev) +{ + cleanup_srcu_struct(&hdev->bpf.srcu); +} +EXPORT_SYMBOL_GPL(hid_bpf_device_free); + static int __init hid_bpf_init(void) { int err; diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index c90b689..f3bbe11 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -197,10 +197,13 @@ static int hid_bpf_reg(void *kdata, struct bpf_link *link) if (IS_ERR(hdev)) return PTR_ERR(hdev); - ops->hdev = hdev; - mutex_lock(&hdev->bpf.prog_list_lock); + if (hdev->bpf.destroyed) { + err = -ENODEV; + goto out_unlock; + } + count = list_count_nodes(&hdev->bpf.prog_list); if (count >= HID_BPF_MAX_PROGS_PER_DEV) { err = -E2BIG; @@ -222,6 +225,7 @@ static int hid_bpf_reg(void *kdata, struct bpf_link *link) goto out_unlock; } + ops->hdev = hdev; if (ops->flags & BPF_F_BEFORE) list_add_rcu(&ops->list, &hdev->bpf.prog_list); else @@ -324,6 +328,8 @@ void __hid_bpf_ops_destroy_device(struct hid_device *hdev) int count = 0; mutex_lock(&hdev->bpf.prog_list_lock); + /* mark the device as destroyed in bpf so we don't reattach it */ + hdev->bpf.destroyed = true; list_for_each_entry(e, &hdev->bpf.prog_list, list) { e->hdev = NULL; count++; diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b4fd482..827a0ee 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -768,6 +768,7 @@ void hiddev_free(struct kref *ref) hid_close_report(hid); hid_free_bpf_rdesc(hid); + hid_bpf_device_free(hid); kfree(hid->dev_rdesc); kfree(hid); } diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 19fffa4..0db7f67 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -213,6 +213,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); int hid_bpf_device_init(struct hid_device *hid); +void hid_bpf_device_free(struct hid_device *hid); const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const 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, @@ -232,6 +233,7 @@ 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 int hid_bpf_device_init(struct hid_device *hid) { return 0; } +static inline void hid_bpf_device_free(struct hid_device *hid) {} static inline const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size) { return rdesc; } pw-bot: cr ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-03 3:00 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-11-03 2:45 [PATCH v2 0/2] HID: bpf: fix device destruction races Yifan Zhang 2026-11-03 2:45 ` [PATCH v2 2/2] HID: bpf: reject struct_ops registration during device destruction Yifan Zhang 2026-11-03 3:00 ` sashiko-bot 2026-11-03 2:45 ` [PATCH v2 1/2] HID: bpf: synchronize hardware operations with " Yifan Zhang 2026-11-03 3:00 ` Alexei Starovoitov
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.