From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: 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>,
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>
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,
Benjamin Tissoires <benjamin.tissoires@redhat.com>
Subject: [PATCH bpf-next v1 4/6] HID: bpf: add new BPF type to trigger commands from userspace
Date: Thu, 24 Feb 2022 12:08:26 +0100 [thread overview]
Message-ID: <20220224110828.2168231-5-benjamin.tissoires@redhat.com> (raw)
In-Reply-To: <20220224110828.2168231-1-benjamin.tissoires@redhat.com>
Given that we can not call bpf_hid_raw_request() from within an IRQ,
userspace needs to have a way to communicate with the device when
it needs.
Implement a new type that the caller can run at will without being in
an IRQ context.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
include/linux/bpf-hid.h | 3 +
include/uapi/linux/bpf.h | 1 +
include/uapi/linux/bpf_hid.h | 9 ++
kernel/bpf/hid.c | 117 +++++++++++++++++++
kernel/bpf/syscall.c | 2 +
tools/include/uapi/linux/bpf.h | 1 +
tools/lib/bpf/libbpf.c | 1 +
tools/testing/selftests/bpf/prog_tests/hid.c | 56 +++++++++
tools/testing/selftests/bpf/progs/hid.c | 10 ++
9 files changed, 200 insertions(+)
diff --git a/include/linux/bpf-hid.h b/include/linux/bpf-hid.h
index 07cbd5cf595c..00ac4555aa5b 100644
--- a/include/linux/bpf-hid.h
+++ b/include/linux/bpf-hid.h
@@ -15,6 +15,7 @@ enum bpf_hid_attach_type {
BPF_HID_ATTACH_INVALID = -1,
BPF_HID_ATTACH_DEVICE_EVENT = 0,
BPF_HID_ATTACH_RDESC_FIXUP,
+ BPF_HID_ATTACH_USER_EVENT,
MAX_BPF_HID_ATTACH_TYPE
};
@@ -34,6 +35,8 @@ to_bpf_hid_attach_type(enum bpf_attach_type attach_type)
return BPF_HID_ATTACH_DEVICE_EVENT;
case BPF_HID_RDESC_FIXUP:
return BPF_HID_ATTACH_RDESC_FIXUP;
+ case BPF_HID_USER_EVENT:
+ return BPF_HID_ATTACH_USER_EVENT;
default:
return BPF_HID_ATTACH_INVALID;
}
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0571d9b954c9..a374cc4aade6 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1000,6 +1000,7 @@ enum bpf_attach_type {
BPF_PERF_EVENT,
BPF_HID_DEVICE_EVENT,
BPF_HID_RDESC_FIXUP,
+ BPF_HID_USER_EVENT,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/include/uapi/linux/bpf_hid.h b/include/uapi/linux/bpf_hid.h
index c0801d7174c3..7a263568e132 100644
--- a/include/uapi/linux/bpf_hid.h
+++ b/include/uapi/linux/bpf_hid.h
@@ -19,6 +19,7 @@ enum hid_bpf_event {
HID_BPF_UNDEF = 0,
HID_BPF_DEVICE_EVENT,
HID_BPF_RDESC_FIXUP,
+ HID_BPF_USER_EVENT,
};
/* type is HID_BPF_DEVICE_EVENT */
@@ -33,6 +34,13 @@ struct hid_bpf_ctx_rdesc_fixup {
unsigned long size;
};
+/* type is HID_BPF_USER_EVENT */
+struct hid_bpf_ctx_user_event {
+ __u8 data[HID_BPF_MAX_BUFFER_SIZE];
+ unsigned long size;
+ int retval;
+};
+
struct hid_bpf_ctx {
enum hid_bpf_event type;
struct hid_device *hdev;
@@ -40,6 +48,7 @@ struct hid_bpf_ctx {
union {
struct hid_bpf_ctx_device_event device;
struct hid_bpf_ctx_rdesc_fixup rdesc;
+ struct hid_bpf_ctx_user_event user;
} u;
};
diff --git a/kernel/bpf/hid.c b/kernel/bpf/hid.c
index 9eb7bd6ac6c8..3714413e1eb6 100644
--- a/kernel/bpf/hid.c
+++ b/kernel/bpf/hid.c
@@ -52,6 +52,9 @@ BPF_CALL_3(bpf_hid_get_data, void*, ctx, u64, offset, u8, n)
case HID_BPF_RDESC_FIXUP:
buf = bpf_ctx->u.rdesc.data;
break;
+ case HID_BPF_USER_EVENT:
+ buf = bpf_ctx->u.user.data;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -83,6 +86,9 @@ BPF_CALL_4(bpf_hid_set_data, void*, ctx, u64, offset, u8, n, u32, data)
case HID_BPF_RDESC_FIXUP:
buf = bpf_ctx->u.rdesc.data;
break;
+ case HID_BPF_USER_EVENT:
+ buf = bpf_ctx->u.user.data;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -385,6 +391,8 @@ static int bpf_hid_max_progs(enum bpf_hid_attach_type type)
return 64;
case BPF_HID_ATTACH_RDESC_FIXUP:
return 1;
+ case BPF_HID_ATTACH_USER_EVENT:
+ return 64;
default:
return 0;
}
@@ -479,7 +487,116 @@ int bpf_hid_link_create(const union bpf_attr *attr, struct bpf_prog *prog)
return bpf_link_settle(&link_primer);
}
+static int hid_bpf_prog_test_run(struct bpf_prog *prog,
+ const union bpf_attr *attr,
+ union bpf_attr __user *uattr)
+{
+ struct hid_device *hdev = NULL;
+ struct bpf_prog_array *progs;
+ struct hid_bpf_ctx *ctx = NULL;
+ bool valid_prog = false;
+ int i;
+ int target_fd, ret;
+ void __user *data_out = u64_to_user_ptr(attr->test.data_out);
+ void __user *data_in = u64_to_user_ptr(attr->test.data_in);
+ u32 user_size = attr->test.data_size_in;
+
+ if (!hid_hooks.hdev_from_fd)
+ return -EOPNOTSUPP;
+
+ if (attr->test.ctx_size_in != sizeof(int))
+ return -EINVAL;
+
+ if (copy_from_user(&target_fd, (void *)attr->test.ctx_in, attr->test.ctx_size_in))
+ return -EFAULT;
+
+ hdev = hid_hooks.hdev_from_fd(target_fd);
+ if (IS_ERR(hdev))
+ return PTR_ERR(hdev);
+
+ ret = mutex_lock_interruptible(&bpf_hid_mutex);
+ if (ret)
+ return ret;
+
+ /* check if the given program is of correct type and registered */
+ progs = rcu_dereference_protected(hdev->bpf.run_array[BPF_HID_ATTACH_USER_EVENT],
+ lockdep_is_held(&bpf_hid_mutex));
+ if (!progs) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ for (i = 0; i < bpf_prog_array_length(progs); i++) {
+ if (progs->items[i].prog == prog) {
+ valid_prog = true;
+ break;
+ }
+ }
+
+ if (!valid_prog) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ ctx->hdev = hdev;
+ ctx->type = HID_BPF_USER_EVENT;
+
+ /* copy data_in from userspace */
+ if (user_size) {
+ if (user_size > HID_BPF_MAX_BUFFER_SIZE)
+ user_size = HID_BPF_MAX_BUFFER_SIZE;
+
+ if (copy_from_user(ctx->u.user.data, data_in, user_size)) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ ctx->u.user.size = user_size;
+ }
+
+ migrate_disable();
+
+ ret = bpf_prog_run(prog, ctx);
+
+ migrate_enable();
+
+ user_size = attr->test.data_size_out;
+
+ if (user_size && data_out) {
+ if (user_size > ctx->u.user.size)
+ user_size = ctx->u.user.size;
+
+ if (copy_to_user(data_out, ctx->u.user.data, user_size)) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ if (copy_to_user(&uattr->test.data_size_out, &user_size, sizeof(user_size))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+ }
+
+ if (copy_to_user(&uattr->test.retval, &ctx->u.user.retval, sizeof(ctx->u.user.retval))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+unlock:
+ kfree(ctx);
+
+ mutex_unlock(&bpf_hid_mutex);
+ return ret;
+}
+
const struct bpf_prog_ops hid_prog_ops = {
+ .test_run = hid_bpf_prog_test_run,
};
int bpf_hid_init(struct hid_device *hdev)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 62889cc71a02..0a6d08dabe59 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3192,6 +3192,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
return BPF_PROG_TYPE_XDP;
case BPF_HID_DEVICE_EVENT:
case BPF_HID_RDESC_FIXUP:
+ case BPF_HID_USER_EVENT:
return BPF_PROG_TYPE_HID;
default:
return BPF_PROG_TYPE_UNSPEC;
@@ -3338,6 +3339,7 @@ static int bpf_prog_query(const union bpf_attr *attr,
return sock_map_bpf_prog_query(attr, uattr);
case BPF_HID_DEVICE_EVENT:
case BPF_HID_RDESC_FIXUP:
+ case BPF_HID_USER_EVENT:
return bpf_hid_prog_query(attr, uattr);
default:
return -EINVAL;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0571d9b954c9..a374cc4aade6 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1000,6 +1000,7 @@ enum bpf_attach_type {
BPF_PERF_EVENT,
BPF_HID_DEVICE_EVENT,
BPF_HID_RDESC_FIXUP,
+ BPF_HID_USER_EVENT,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b7af873116fb..290864d2f865 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -8678,6 +8678,7 @@ static const struct bpf_sec_def section_defs[] = {
SEC_DEF("sk_lookup", SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE | SEC_SLOPPY_PFX),
SEC_DEF("hid/device_event", HID, BPF_HID_DEVICE_EVENT, SEC_ATTACHABLE_OPT | SEC_SLOPPY_PFX),
SEC_DEF("hid/rdesc_fixup", HID, BPF_HID_RDESC_FIXUP, SEC_ATTACHABLE_OPT | SEC_SLOPPY_PFX),
+ SEC_DEF("hid/user_event", HID, BPF_HID_USER_EVENT, SEC_ATTACHABLE_OPT | SEC_SLOPPY_PFX),
};
#define MAX_TYPE_NAME_SIZE 32
diff --git a/tools/testing/selftests/bpf/prog_tests/hid.c b/tools/testing/selftests/bpf/prog_tests/hid.c
index 7d4f740a0a08..d297a571e910 100644
--- a/tools/testing/selftests/bpf/prog_tests/hid.c
+++ b/tools/testing/selftests/bpf/prog_tests/hid.c
@@ -336,6 +336,59 @@ static int test_hid_set_get_data(struct hid *hid_skel, int uhid_fd, int sysfs_fd
return ret;
}
+/*
+ * Attach hid_user to the given uhid device,
+ * call the bpf program from userspace
+ * check that the program is called and does the expected.
+ */
+static int test_hid_user_call(struct hid *hid_skel, int uhid_fd, int sysfs_fd)
+{
+ int err, prog_fd;
+ u8 buf[10] = {0};
+ int ret = -1;
+
+ LIBBPF_OPTS(bpf_test_run_opts, run_attrs,
+ .repeat = 1,
+ .ctx_in = &sysfs_fd,
+ .ctx_size_in = sizeof(sysfs_fd),
+ .data_in = buf,
+ .data_size_in = sizeof(buf),
+ .data_out = buf,
+ .data_size_out = sizeof(buf),
+ );
+
+ /* attach hid_user program */
+ hid_skel->links.hid_user = bpf_program__attach_hid(hid_skel->progs.hid_user, sysfs_fd);
+ if (!ASSERT_OK_PTR(hid_skel->links.hid_user,
+ "attach_hid(hid_user)"))
+ return PTR_ERR(hid_skel->links.hid_user);
+
+ buf[0] = 39;
+
+ prog_fd = bpf_program__fd(hid_skel->progs.hid_user);
+
+ err = bpf_prog_test_run_opts(prog_fd, &run_attrs);
+ if (!ASSERT_EQ(err, 0, "bpf_prog_test_run_xattr"))
+ goto cleanup;
+
+ if (!ASSERT_EQ(run_attrs.retval, 72, "bpf_prog_test_run_xattr_retval"))
+ goto cleanup;
+
+ if (!ASSERT_EQ(buf[1], 42, "hid_user_check_in"))
+ goto cleanup;
+
+ if (!ASSERT_EQ(buf[2], 4, "hid_user_check_static_out"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+
+ hid__detach(hid_skel);
+
+ return ret;
+}
+
/*
* Attach hid_rdesc_fixup to the given uhid device,
* retrieve and open the matching hidraw node,
@@ -437,6 +490,9 @@ void serial_test_hid_bpf(void)
err = test_hid_set_get_data(hid_skel, uhid_fd, sysfs_fd);
ASSERT_OK(err, "hid_set_get_data");
+ err = test_hid_user_call(hid_skel, uhid_fd, sysfs_fd);
+ ASSERT_OK(err, "hid_user");
+
err = test_rdesc_fixup(hid_skel, uhid_fd, sysfs_fd);
ASSERT_OK(err, "hid_rdesc_fixup");
diff --git a/tools/testing/selftests/bpf/progs/hid.c b/tools/testing/selftests/bpf/progs/hid.c
index 01d9c556a3a1..b2db809b3367 100644
--- a/tools/testing/selftests/bpf/progs/hid.c
+++ b/tools/testing/selftests/bpf/progs/hid.c
@@ -80,3 +80,13 @@ int hid_set_get_data(struct hid_bpf_ctx *ctx)
return 0;
}
+
+SEC("hid/user_event")
+int hid_user(struct hid_bpf_ctx *ctx)
+{
+ ctx->u.user.data[1] = ctx->u.user.data[0] + 3;
+ ctx->u.user.data[2] = 4;
+ ctx->u.user.retval = 72;
+
+ return 0;
+}
--
2.35.1
next prev parent reply other threads:[~2022-02-24 11:09 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-24 11:08 [PATCH bpf-next v1 0/6] Introduce eBPF support for HID devices Benjamin Tissoires
2022-02-24 11:08 ` [PATCH bpf-next v1 1/6] HID: initial BPF implementation Benjamin Tissoires
2022-02-24 11:34 ` Greg KH
2022-02-24 13:52 ` Benjamin Tissoires
2022-02-28 17:30 ` Benjamin Tissoires
2022-02-26 7:19 ` Song Liu
2022-02-28 17:38 ` Benjamin Tissoires
2022-02-24 11:08 ` [PATCH bpf-next v1 2/6] HID: bpf: allow to change the report descriptor from an eBPF program Benjamin Tissoires
2022-02-26 7:25 ` Song Liu
2022-02-28 17:41 ` Benjamin Tissoires
2022-02-24 11:08 ` [PATCH bpf-next v1 3/6] HID: bpf: add hid_{get|set}_data helpers Benjamin Tissoires
2022-02-24 11:08 ` Benjamin Tissoires [this message]
2022-02-24 11:08 ` [PATCH bpf-next v1 5/6] HID: bpf: tests: rely on uhid event to know if a test device is ready Benjamin Tissoires
2022-02-24 11:08 ` [PATCH bpf-next v1 6/6] HID: bpf: add bpf_hid_raw_request helper function Benjamin Tissoires
2022-02-24 11:31 ` [PATCH bpf-next v1 0/6] Introduce eBPF support for HID devices Greg KH
2022-02-24 13:49 ` Benjamin Tissoires
2022-02-24 17:20 ` Yonghong Song
2022-02-25 16:06 ` Benjamin Tissoires
2022-02-25 16:19 ` Greg KH
2022-02-25 16:30 ` Yonghong Song
2022-02-25 13:38 ` Greg KH
2022-02-25 16:00 ` Benjamin Tissoires
2022-02-25 16:23 ` Greg KH
2022-02-25 16:32 ` Greg KH
2022-02-26 7:36 ` Song Liu
2022-02-26 9:19 ` Benjamin Tissoires
2022-02-28 16:33 ` Jiri Kosina
2022-02-24 17:41 ` Bastien Nocera
2022-02-24 18:20 ` Greg KH
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=20220224110828.2168231-5-benjamin.tissoires@redhat.com \
--to=benjamin.tissoires@redhat.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davemarchevsky@fb.com \
--cc=jikos@kernel.org \
--cc=joe@cilium.io \
--cc=john.fastabend@gmail.com \
--cc=kafai@fb.com \
--cc=kpsingh@kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--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 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.