mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] HID: bpf: close device teardown races
@ 2026-11-02 11:58 Yifan Zhang
  2026-11-02 11:58 ` [PATCH 1/2] HID: bpf: serialize hardware operations with device destruction Yifan Zhang
  2026-11-02 11:58 ` [PATCH 2/2] HID: bpf: reject struct_ops registration during " Yifan Zhang
  0 siblings, 2 replies; 4+ messages in thread
From: Yifan Zhang @ 2026-11-02 11:58 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires, linux-input
  Cc: Greg Kroah-Hartman, Alexei Starovoitov, bpf, linux-kernel

HID-BPF can race device destruction in two paths.  A hardware request can
outlive transport-private state, and a struct_ops registration can resume
after destruction has cleaned the device's SRCU state.

Serialize HID-BPF hardware operations with the destruction transition, then
reject registrations that acquire prog_list_lock after that transition.

Yifan Zhang (2):
  HID: bpf: serialize hardware operations with device destruction
  HID: bpf: reject struct_ops registration during device destruction

 drivers/hid/bpf/hid_bpf_dispatch.c   | 36 +++++++++++++++++++---------
 drivers/hid/bpf/hid_bpf_struct_ops.c |  5 ++++
 2 files changed, 30 insertions(+), 11 deletions(-)

-- 
2.39.5 (Apple Git-154)

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

* [PATCH 1/2] HID: bpf: serialize hardware operations with device destruction
  2026-11-02 11:58 [PATCH 0/2] HID: bpf: close device teardown races Yifan Zhang
@ 2026-11-02 11:58 ` Yifan Zhang
  2026-11-02 16:21   ` Alexei Starovoitov
  2026-11-02 11:58 ` [PATCH 2/2] HID: bpf: reject struct_ops registration during " Yifan Zhang
  1 sibling, 1 reply; 4+ messages in thread
From: Yifan Zhang @ 2026-11-02 11:58 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

Hold prog_list_lock across HID-BPF hardware operations.  Device destruction
sets destroyed while holding the same lock, so it waits for an operation
that has already started.  Later operations return -ENODEV before reaching
the low-level driver.  Apply the same lifetime rule to output reports.

The reproducer completed 100 close-versus-request trials without a KASAN
report with this change.

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 | 36 +++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 6b467c74601cb..4fea42dd2f392 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -444,14 +444,20 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
 	if (!dma_data)
 		return -ENOMEM;
 
-	ret = hid_ops->hid_hw_raw_request(ctx->hid,
-					      dma_data[0],
-					      dma_data,
-					      size,
-					      rtype,
-					      reqtype,
-					      (u64)(long)ctx,
-					      true); /* prevent infinite recursions */
+	mutex_lock(&ctx->hid->bpf.prog_list_lock);
+	if (READ_ONCE(ctx->hid->bpf.destroyed)) {
+		ret = -ENODEV;
+	} else {
+		ret = hid_ops->hid_hw_raw_request(ctx->hid,
+						  dma_data[0],
+						  dma_data,
+						  size,
+						  rtype,
+						  reqtype,
+						  (u64)(long)ctx,
+						  true); /* prevent infinite recursions */
+	}
+	mutex_unlock(&ctx->hid->bpf.prog_list_lock);
 
 	if (ret > (ssize_t)size)
 		ret = size;
@@ -492,7 +498,13 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
 	if (!dma_data)
 		return -ENOMEM;
 
-	ret = hid_ops->hid_hw_output_report(ctx->hid, dma_data, size, (u64)(long)ctx, true);
+	mutex_lock(&ctx->hid->bpf.prog_list_lock);
+	if (READ_ONCE(ctx->hid->bpf.destroyed))
+		ret = -ENODEV;
+	else
+		ret = hid_ops->hid_hw_output_report(ctx->hid, dma_data, size,
+						    (u64)(long)ctx, true);
+	mutex_unlock(&ctx->hid->bpf.prog_list_lock);
 
 	kfree(dma_data);
 	return ret;
@@ -641,8 +653,10 @@ 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);
+	WRITE_ONCE(hdev->bpf.destroyed, true);
+	mutex_unlock(&hdev->bpf.prog_list_lock);
 
 	__hid_bpf_ops_destroy_device(hdev);
 
-- 
2.39.5 (Apple Git-154)

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

* [PATCH 2/2] HID: bpf: reject struct_ops registration during device destruction
  2026-11-02 11:58 [PATCH 0/2] HID: bpf: close device teardown races Yifan Zhang
  2026-11-02 11:58 ` [PATCH 1/2] HID: bpf: serialize hardware operations with device destruction Yifan Zhang
@ 2026-11-02 11:58 ` Yifan Zhang
  1 sibling, 0 replies; 4+ messages in thread
From: Yifan Zhang @ 2026-11-02 11:58 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.  The preceding teardown
serialization change sets the flag while holding the same lock, so either a
registration completes before destruction starts or it fails with -ENODEV
without accessing SRCU.

The reproducer no longer triggers a KASAN report with this change.

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 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c
index c90b68956cb3b..4c433f419c85e 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;
-- 
2.39.5 (Apple Git-154)

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

* Re: [PATCH 1/2] HID: bpf: serialize hardware operations with device destruction
  2026-11-02 11:58 ` [PATCH 1/2] HID: bpf: serialize hardware operations with device destruction Yifan Zhang
@ 2026-11-02 16:21   ` Alexei Starovoitov
  0 siblings, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2026-11-02 16:21 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 03:58 AM Yifan Zhang <yfzhang23@stu.pku.edu.cn> wrote:
> Hold prog_list_lock across HID-BPF hardware operations.  Device destruction
> sets destroyed while holding the same lock, so it waits for an operation
> that has already started.  Later operations return -ENODEV before reaching
> the low-level driver.  Apply the same lifetime rule to output reports.

sashiko is right. This will deadlock.

pw-bot: cr

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

end of thread, other threads:[~2026-11-02 16:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-02 11:58 [PATCH 0/2] HID: bpf: close device teardown races Yifan Zhang
2026-11-02 11:58 ` [PATCH 1/2] HID: bpf: serialize hardware operations with device destruction Yifan Zhang
2026-11-02 16:21   ` Alexei Starovoitov
2026-11-02 11:58 ` [PATCH 2/2] HID: bpf: reject struct_ops registration during " Yifan Zhang

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

all inboxes | Powered by JetHome®