From: Bill Wendling <morbo@google.com>
To: Jiri Kosina <jikos@kernel.org>, Benjamin Tissoires <bentiss@kernel.org>
Cc: Ihor Solodrai <ihor.solodrai@linux.dev>,
Puranjay Mohan <puranjay@kernel.org>,
Johan Hovold <johan@kernel.org>,
Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Kees Cook <kees@kernel.org>,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
bpf@vger.kernel.org, Bill Wendling <morbo@google.com>
Subject: [PATCH] HID: bpf: fix lockless race on device_data allocation
Date: Wed, 23 Sep 2026 21:42:46 +0000 [thread overview]
Message-ID: <20260923214246.3098156-1-morbo@google.com> (raw)
When attaching a hid_device_event BPF program to an already-connected
HID device, hid_bpf_reg() calls hid_bpf_allocate_event_data() while
holding only hdev->bpf.prog_list_lock. Concurrently, incoming HID
reports invoke dispatch_hid_bpf_device_event() while holding only
hdev->driver_input_lock.
Previously, __hid_bpf_allocate_data() assigned *data (device_data)
before *size (allocated_data) without release semantics, and
dispatch_hid_bpf_device_event() loaded hdev->bpf.allocated_data and
initialized ctx_kern before checking whether hdev->bpf.device_data was
non-NULL. A concurrent reader could therefore observe device_data != NULL
with allocated_data == 0, skipping the memset() clear and dropping the
report with -EINVAL (or dereferencing NULL if device_data was reloaded
for the NULL check).
Use WRITE_ONCE() and smp_store_release() in __hid_bpf_allocate_data() so
allocated_data and the zeroed buffer are visible before device_data becomes
non-NULL, and pair it with smp_load_acquire() in
dispatch_hid_bpf_device_event() before reading allocated_data and
initializing ctx_kern.
Fixes: 658ee5a64fcf ("HID: bpf: allocate data memory for device_event BPF programs")
Assisted-by: LLM
Signed-off-by: Bill Wendling <morbo@google.com>
---
drivers/hid/bpf/hid_bpf_dispatch.c | 38 +++++++++++++++++++-----------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index d46779b63660..1a0c4fa6ed86 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -28,16 +28,10 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
size_t *buf_size, u32 *size, int interrupt, u64 source,
bool from_bpf)
{
- struct hid_bpf_ctx_kern ctx_kern = {
- .ctx = {
- .hid = hdev,
- .allocated_size = hdev->bpf.allocated_data,
- .size = *size,
- },
- .data = hdev->bpf.device_data,
- .from_bpf = from_bpf,
- };
+ struct hid_bpf_ctx_kern ctx_kern;
struct hid_bpf_ops *e;
+ u8 *device_data;
+ u32 allocated_data;
int ret;
if (unlikely(hdev->bpf.destroyed))
@@ -46,11 +40,26 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
if (type >= HID_REPORT_TYPES)
return ERR_PTR(-EINVAL);
- /* no program has been attached yet */
- if (!hdev->bpf.device_data)
+ /*
+ * No program has been attached yet. Pairs with smp_store_release()
+ * in __hid_bpf_allocate_data().
+ */
+ device_data = smp_load_acquire(&hdev->bpf.device_data);
+ if (!device_data)
return data;
- memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
+ allocated_data = READ_ONCE(hdev->bpf.allocated_data);
+ ctx_kern = (struct hid_bpf_ctx_kern){
+ .ctx = {
+ .hid = hdev,
+ .allocated_size = allocated_data,
+ .size = *size,
+ },
+ .data = device_data,
+ .from_bpf = from_bpf,
+ };
+
+ memset(ctx_kern.data, 0, allocated_data);
memcpy(ctx_kern.data, data, *size);
rcu_read_lock();
@@ -255,8 +264,9 @@ static int __hid_bpf_allocate_data(struct hid_device *hdev, u8 **data, u32 *size
if (!alloc_data)
return -ENOMEM;
- *data = alloc_data;
- *size = alloc_size;
+ WRITE_ONCE(*size, alloc_size);
+ /* Pairs with smp_load_acquire() in dispatch_hid_bpf_device_event() */
+ smp_store_release(data, alloc_data);
return 0;
}
--
2.56.0.rc1.310.g51773c2048-goog
reply other threads:[~2026-09-23 21:42 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260923214246.3098156-1-morbo@google.com \
--to=morbo@google.com \
--cc=bentiss@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=chenyy23@mails.tsinghua.edu.cn \
--cc=gregkh@linuxfoundation.org \
--cc=ihor.solodrai@linux.dev \
--cc=jikos@kernel.org \
--cc=johan@kernel.org \
--cc=kees@kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=puranjay@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®