From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Greg KH <gregkh@linuxfoundation.org>,
Jiri Kosina <jikos@kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Martin KaFai Lau <kafai@fb.com>, Song Liu <songliubraving@fb.com>,
Yonghong Song <yhs@fb.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
John Fastabend <john.fastabend@gmail.com>,
KP Singh <kpsingh@kernel.org>, Shuah Khan <shuah@kernel.org>,
Dave Marchevsky <davemarchevsky@fb.com>,
Joe Stringer <joe@cilium.io>, Jonathan Corbet <corbet@lwn.net>
Cc: Tero Kristo <tero.kristo@linux.intel.com>,
linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
netdev@vger.kernel.org, bpf@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
Benjamin Tissoires <benjamin.tissoires@redhat.com>
Subject: [PATCH bpf-next v9 14/23] HID: bpf: allocate data memory for device_event BPF programs
Date: Wed, 24 Aug 2022 15:40:44 +0200 [thread overview]
Message-ID: <20220824134055.1328882-15-benjamin.tissoires@redhat.com> (raw)
In-Reply-To: <20220824134055.1328882-1-benjamin.tissoires@redhat.com>
We need to also be able to change the size of the report.
Reducing it is easy, because we already have the incoming buffer that is
big enough, but extending it is harder.
Pre-allocate a buffer that is big enough to handle all reports of the
device, and use that as the primary buffer for BPF programs.
To be able to change the size of the buffer, we change the device_event
API and request it to return the size of the buffer.
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v9
no changes in v8
no changes in v7
no changes in v6
new-ish in v5
---
drivers/hid/bpf/hid_bpf_dispatch.c | 116 +++++++++++++++++++++++++---
drivers/hid/bpf/hid_bpf_jmp_table.c | 4 +-
drivers/hid/hid-core.c | 12 ++-
include/linux/hid_bpf.h | 37 +++++++--
4 files changed, 151 insertions(+), 18 deletions(-)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 600b00fdf6c1..33c6b3df6472 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -28,8 +28,9 @@ EXPORT_SYMBOL(hid_bpf_ops);
*
* @ctx: The HID-BPF context
*
- * @return %0 on success and keep processing; a negative error code to interrupt
- * the processing of this event
+ * @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 for
@@ -44,23 +45,43 @@ __weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx)
}
ALLOW_ERROR_INJECTION(hid_bpf_device_event, ERRNO);
-int
+u8 *
dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
- u32 size, int interrupt)
+ u32 *size, int interrupt)
{
struct hid_bpf_ctx_kern ctx_kern = {
.ctx = {
.hid = hdev,
.report_type = type,
- .size = size,
+ .allocated_size = hdev->bpf.allocated_data,
+ .size = *size,
},
- .data = data,
+ .data = hdev->bpf.device_data,
};
+ int ret;
if (type >= HID_REPORT_TYPES)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
+
+ /* no program has been attached yet */
+ if (!hdev->bpf.device_data)
+ return data;
+
+ memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
+ memcpy(ctx_kern.data, data, *size);
+
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ return ERR_PTR(-EINVAL);
- return hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern);
+ *size = ret;
+ }
+
+ return ctx_kern.data;
}
EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
@@ -83,7 +104,7 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr
ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
- if (rdwr_buf_size + offset > ctx->size)
+ if (rdwr_buf_size + offset > ctx->allocated_size)
return NULL;
return ctx_kern->data + offset;
@@ -110,6 +131,51 @@ static int device_match_id(struct device *dev, const void *id)
return hdev->id == *(int *)id;
}
+static int __hid_bpf_allocate_data(struct hid_device *hdev, u8 **data, u32 *size)
+{
+ u8 *alloc_data;
+ unsigned int i, j, max_report_len = 0;
+ size_t alloc_size = 0;
+
+ /* compute the maximum report length for this device */
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ struct hid_report_enum *report_enum = hdev->report_enum + i;
+
+ for (j = 0; j < HID_MAX_IDS; j++) {
+ struct hid_report *report = report_enum->report_id_hash[j];
+
+ if (report)
+ max_report_len = max(max_report_len, hid_report_len(report));
+ }
+ }
+
+ /*
+ * Give us a little bit of extra space and some predictability in the
+ * buffer length we create. This way, we can tell users that they can
+ * work on chunks of 64 bytes of memory without having the bpf verifier
+ * scream at them.
+ */
+ alloc_size = DIV_ROUND_UP(max_report_len, 64) * 64;
+
+ alloc_data = kzalloc(alloc_size, GFP_KERNEL);
+ if (!alloc_data)
+ return -ENOMEM;
+
+ *data = alloc_data;
+ *size = alloc_size;
+
+ return 0;
+}
+
+static int hid_bpf_allocate_event_data(struct hid_device *hdev)
+{
+ /* hdev->bpf.device_data is already allocated, abort */
+ if (hdev->bpf.device_data)
+ return 0;
+
+ return __hid_bpf_allocate_data(hdev, &hdev->bpf.device_data, &hdev->bpf.allocated_data);
+}
+
/**
* hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
*
@@ -125,7 +191,7 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
{
struct hid_device *hdev;
struct device *dev;
- int prog_type = hid_bpf_get_prog_attach_type(prog_fd);
+ int err, prog_type = hid_bpf_get_prog_attach_type(prog_fd);
if (!hid_bpf_ops)
return -EINVAL;
@@ -145,6 +211,12 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
hdev = to_hid_device(dev);
+ if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) {
+ err = hid_bpf_allocate_event_data(hdev);
+ if (err)
+ return err;
+ }
+
return __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
}
@@ -158,6 +230,30 @@ static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
.set = &hid_bpf_syscall_kfunc_ids,
};
+int hid_bpf_connect_device(struct hid_device *hdev)
+{
+ struct hid_bpf_prog_list *prog_list;
+
+ rcu_read_lock();
+ prog_list = rcu_dereference(hdev->bpf.progs[HID_BPF_PROG_TYPE_DEVICE_EVENT]);
+ rcu_read_unlock();
+
+ /* only allocate BPF data if there are programs attached */
+ if (!prog_list)
+ return 0;
+
+ return hid_bpf_allocate_event_data(hdev);
+}
+EXPORT_SYMBOL_GPL(hid_bpf_connect_device);
+
+void hid_bpf_disconnect_device(struct hid_device *hdev)
+{
+ kfree(hdev->bpf.device_data);
+ hdev->bpf.device_data = NULL;
+ hdev->bpf.allocated_data = 0;
+}
+EXPORT_SYMBOL_GPL(hid_bpf_disconnect_device);
+
void hid_bpf_destroy_device(struct hid_device *hdev)
{
if (!hdev)
diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c
index 05225ff3cc27..0f20deab81ff 100644
--- a/drivers/hid/bpf/hid_bpf_jmp_table.c
+++ b/drivers/hid/bpf/hid_bpf_jmp_table.c
@@ -123,8 +123,10 @@ int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
ctx_kern->ctx.index = idx;
err = __hid_bpf_tail_call(&ctx_kern->ctx);
- if (err)
+ if (err < 0)
break;
+ if (err)
+ ctx_kern->ctx.retval = err;
}
out_unlock:
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 0d0bd8fc69c7..cadd21a6f995 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2040,9 +2040,11 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
report_enum = hid->report_enum + type;
hdrv = hid->driver;
- ret = dispatch_hid_bpf_device_event(hid, type, data, size, interrupt);
- if (ret)
+ data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
goto unlock;
+ }
if (!size) {
dbg_hid("empty report\n");
@@ -2157,6 +2159,10 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
int len;
int ret;
+ ret = hid_bpf_connect_device(hdev);
+ if (ret)
+ return ret;
+
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE)
@@ -2258,6 +2264,8 @@ void hid_disconnect(struct hid_device *hdev)
if (hdev->claimed & HID_CLAIMED_HIDRAW)
hidraw_disconnect(hdev);
hdev->claimed = 0;
+
+ hid_bpf_disconnect_device(hdev);
}
EXPORT_SYMBOL_GPL(hid_disconnect);
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 5d53b12c6ea0..1707e4492d7a 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -29,15 +29,32 @@ struct hid_device;
* a bigger index).
* @hid: the ``struct hid_device`` representing the device itself
* @report_type: used for ``hid_bpf_device_event()``
+ * @allocated_size: Allocated size of data.
+ *
+ * This is how much memory is available and can be requested
+ * by the HID program.
+ * Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to
+ * ``4096`` (4 KB)
* @size: Valid data in the data field.
*
* Programs can get the available valid size in data by fetching this field.
+ * Programs can also change this value by returning a positive number in the
+ * program.
+ * To discard the event, return a negative error code.
+ *
+ * ``size`` must always be less or equal than ``allocated_size`` (it is enforced
+ * once all BPF programs have been run).
+ * @retval: Return value of the previous program.
*/
struct hid_bpf_ctx {
__u32 index;
const struct hid_device *hid;
+ __u32 allocated_size;
enum hid_report_type report_type;
- __s32 size;
+ union {
+ __s32 retval;
+ __s32 size;
+ };
};
/* Following functions are tracepoints that BPF programs can attach to */
@@ -81,6 +98,12 @@ struct hid_bpf_prog_list {
/* stored in each device */
struct hid_bpf {
+ u8 *device_data; /* allocated when a bpf program of type
+ * SEC(f.../hid_bpf_device_event) has been attached
+ * to this HID device
+ */
+ u32 allocated_data;
+
struct hid_bpf_prog_list __rcu *progs[HID_BPF_PROG_TYPE_MAX]; /* attached BPF progs */
bool destroyed; /* prevents the assignment of any progs */
@@ -88,13 +111,17 @@ struct hid_bpf {
};
#ifdef CONFIG_HID_BPF
-int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
- u32 size, int interrupt);
+u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
+ u32 *size, int interrupt);
+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);
#else /* CONFIG_HID_BPF */
-static inline int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
- u32 size, int interrupt) { return 0; }
+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; }
+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) {}
#endif /* CONFIG_HID_BPF */
--
2.36.1
next prev parent reply other threads:[~2022-08-24 13:44 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-24 13:40 [PATCH bpf-next v9 00/23] Introduce eBPF support for HID devices Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 01/23] bpf/verifier: allow all functions to read user provided context Benjamin Tissoires
2022-08-26 1:41 ` Alexei Starovoitov
2022-08-26 1:50 ` Kumar Kartikeya Dwivedi
2022-08-30 14:29 ` Benjamin Tissoires
2022-08-31 16:37 ` Alexei Starovoitov
2022-08-31 17:56 ` Benjamin Tissoires
2022-09-01 4:15 ` Alexei Starovoitov
2022-09-01 16:47 ` Benjamin Tissoires
2022-09-02 3:50 ` Kumar Kartikeya Dwivedi
2022-09-02 13:11 ` Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 02/23] bpf/verifier: do not clear meta in check_mem_size Benjamin Tissoires
2022-08-26 1:54 ` Kumar Kartikeya Dwivedi
2022-08-30 13:51 ` Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 03/23] selftests/bpf: add test for accessing ctx from syscall program type Benjamin Tissoires
2022-08-26 2:07 ` Kumar Kartikeya Dwivedi
2022-08-24 13:40 ` [PATCH bpf-next v9 04/23] bpf/verifier: allow kfunc to return an allocated mem Benjamin Tissoires
2022-08-26 1:24 ` Kumar Kartikeya Dwivedi
2022-08-31 5:50 ` Benjamin Tissoires
2022-08-31 11:06 ` Kumar Kartikeya Dwivedi
2022-08-24 13:40 ` [PATCH bpf-next v9 05/23] selftests/bpf: Add tests for kfunc returning a memory pointer Benjamin Tissoires
2022-08-26 2:26 ` Kumar Kartikeya Dwivedi
2022-08-24 13:40 ` [PATCH bpf-next v9 06/23] bpf: prepare for more bpf syscall to be used from kernel and user space Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 07/23] libbpf: add map_get_fd_by_id and map_delete_elem in light skeleton Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 08/23] HID: core: store the unique system identifier in hid_device Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 09/23] HID: export hid_report_type to uapi Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 10/23] HID: convert defines of HID class requests into a proper enum Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 11/23] HID: Kconfig: split HID support and hid-core compilation Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 12/23] HID: initial BPF implementation Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 13/23] selftests/bpf: add tests for the HID-bpf initial implementation Benjamin Tissoires
2022-08-24 13:40 ` Benjamin Tissoires [this message]
2022-08-24 13:40 ` [PATCH bpf-next v9 15/23] selftests/bpf/hid: add test to change the report size Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 16/23] HID: bpf: introduce hid_hw_request() Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 17/23] selftests/bpf: add tests for bpf_hid_hw_request Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 18/23] HID: bpf: allow to change the report descriptor Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 19/23] selftests/bpf: add report descriptor fixup tests Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 20/23] selftests/bpf: Add a test for BPF_F_INSERT_HEAD Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 21/23] samples/bpf: add new hid_mouse example Benjamin Tissoires
2022-08-24 19:30 ` Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 21/23] samples/bpf: HID: " Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 22/23] HID: bpf: add Surface Dial example Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 22/23] samples/bpf: HID: " Benjamin Tissoires
2022-08-24 13:40 ` [PATCH bpf-next v9 23/23] Documentation: add HID-BPF docs Benjamin Tissoires
2022-08-26 2:00 ` [PATCH bpf-next v9 00/23] Introduce eBPF support for HID devices patchwork-bot+netdevbpf
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=20220824134055.1328882-15-benjamin.tissoires@redhat.com \
--to=benjamin.tissoires@redhat.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=corbet@lwn.net \
--cc=daniel@iogearbox.net \
--cc=davemarchevsky@fb.com \
--cc=gregkh@linuxfoundation.org \
--cc=jikos@kernel.org \
--cc=joe@cilium.io \
--cc=john.fastabend@gmail.com \
--cc=kafai@fb.com \
--cc=kpsingh@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=memxor@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=shuah@kernel.org \
--cc=songliubraving@fb.com \
--cc=tero.kristo@linux.intel.com \
--cc=yhs@fb.com \
/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;
as well as URLs for NNTP newsgroup(s).