diff mbox series

[RFC,HID,6/7] WIP: selftests/hid: add tests for hid_hw_raw_request HID-BPF hooks

Message ID 20240508-hid_bpf_async_fun-v1-6-558375a25657@kernel.org
State New
Headers show
Series Use the new __s_async for HID-BPF | expand

Commit Message

Benjamin Tissoires May 8, 2024, 10:26 a.m. UTC
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
 tools/testing/selftests/hid/hid_bpf.c              | 55 ++++++++++++++++++++++
 tools/testing/selftests/hid/progs/hid.c            | 51 ++++++++++++++++++++
 .../testing/selftests/hid/progs/hid_bpf_helpers.h  | 39 +++++++++------
 3 files changed, 130 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c
index 7fed9f599b62..522fc32a5c38 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -469,6 +469,8 @@  static void detach_bpf(FIXTURE_DATA(hid_bpf) * self)
 		close(self->hidraw_fd);
 	self->hidraw_fd = 0;
 
+	// hid__detach(self->skel);
+
 	for (i = 0; i < ARRAY_SIZE(self->hid_links); i++) {
 		if (self->hid_links[i])
 			close(self->hid_links[i]);
@@ -572,6 +574,8 @@  static void load_programs(const struct test_program programs[],
 		self->hid_links[i] = args.retval;
 	}
 
+	// hid__attach(self->skel);
+
 	self->hidraw_fd = open_hidraw(self->dev_id);
 	ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
 }
@@ -871,6 +875,57 @@  TEST_F(hid_bpf, test_hid_user_raw_request_call)
 	ASSERT_EQ(args.data[1], 2);
 }
 
+/*
+ * Call hid_hw_raw_request against the given uhid device,
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_filter_raw_request_call)
+{
+	const struct test_program progs[] = {
+		{ .name = "hid_test_filter_raw_request" },
+		{ .name = "hid_test_raw_request" },
+	};
+	__u8 buf[10] = {0};
+	int err;
+
+	LOAD_PROGRAMS(progs);
+
+	/* first check that we did not attach to device_event */
+
+	/* inject one event */
+	buf[0] = 1;
+	buf[1] = 42;
+	uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+	/* read the data from hidraw */
+	memset(buf, 0, sizeof(buf));
+	err = read(self->hidraw_fd, buf, sizeof(buf));
+	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+	ASSERT_EQ(buf[0], 1);
+	ASSERT_EQ(buf[1], 42);
+	ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");
+
+	/* now check that our program is preventing hid_hw_raw_request() */
+
+	/* emit hid_hw_raw_request from hidraw */
+	/* Get Feature */
+	memset(buf, 0, sizeof(buf));
+	buf[0] = 0x1; /* Report Number */
+	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+	ASSERT_LT(err, 0) TH_LOG("unexpected success while reading HIDIOCGFEATURE: %d", err);
+
+	/* remove our bpf program and check that we can now emit commands */
+
+	/* detach the program */
+	detach_bpf(self);
+
+	self->hidraw_fd = open_hidraw(self->dev_id);
+	ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
+
+	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+	ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGFEATURE: %d", err);
+}
+
 /*
  * Attach hid_insert{0,1,2} to the given uhid device,
  * retrieve and open the matching hidraw node,
diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c
index b721d1256836..64aaa279bec4 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -226,3 +226,54 @@  HID_BPF_DEVICE_EVENT(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
 
 	return 0;
 }
+
+// SEC("fentry/hidraw_open")
+// int BPF_PROG(hidraw_open, struct inode *inode, struct file *file)
+// {
+// 	bpf_printk("inode: %llx, file: %llx", (u64)inode, (u64)file);
+// 	return 0;
+// }
+
+HID_BPF_RAW_REQUEST(hid_test_filter_raw_request, struct hid_bpf_ctx *hctx)
+{
+	bpf_printk("in %s:%d", __func__, __LINE__);
+	return 0;
+}
+
+HID_BPF_SLEEPABLE_RAW_REQUEST(hid_test_raw_request, struct hid_bpf_ctx *hctx)
+{
+	struct test_report buf = {
+		.data = {2, 3, 4, 5, 6, 7},
+	};
+	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 2 /* size */);
+	int ret;
+
+	bpf_printk("in %s, hctx: %llx source: %llx", __func__, (u64)hctx, hctx->source);
+
+	if (!data)
+		return 0; /* EPERM check */
+	bpf_printk("in %s:%d", __func__, __LINE__);
+
+	if (hctx->source) {
+		hid_bpf_input_report(hctx, HID_INPUT_REPORT, buf.data, sizeof(buf.data));
+
+		/* still forward the request as-is to the device, hid-bpf will not
+		 * call us again.
+		 */
+
+		data[0] = hctx->reportnum;
+
+		ret = hid_bpf_hw_request(hctx,
+					 data,
+					 2,
+					 hctx->report_type,
+					 hctx->reqtype);
+		bpf_printk("ret: %d", ret);
+		if (ret)
+			return ret;
+		return -1;
+	}
+
+	bpf_printk("in %s:%d", __func__, __LINE__);
+	return 0;
+}
diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
index 9826880e88d1..779ec151c717 100644
--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
+++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
@@ -56,17 +56,6 @@  enum hid_report_type {
 	HID_REPORT_TYPES,
 };
 
-struct hid_bpf_ctx {
-	__u32 index;
-	const struct hid_device *hid;
-	__u32 allocated_size;
-	enum hid_report_type report_type;
-	union {
-		__s32 retval;
-		__s32 size;
-	};
-} __attribute__((preserve_access_index));
-
 enum hid_class_request {
 	HID_REQ_GET_REPORT		= 0x01,
 	HID_REQ_GET_IDLE		= 0x02,
@@ -88,6 +77,20 @@  struct attach_prog_args {
 	int insert_head;
 };
 
+struct hid_bpf_ctx {
+	__u32 index;
+	__u32 allocated_size;
+	__u64 source;
+	const struct hid_device *hid;
+	enum hid_report_type report_type;
+	enum hid_class_request reqtype; /* for HID_BPF_PROG_TYPE_RAW_REQUEST */
+	union {
+		__s32 retval;
+		__s32 size;
+	};
+	__u8 reportnum;
+} __attribute__((preserve_access_index));
+
 /* following are kfuncs exported by HID for HID-BPF */
 extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
 			      unsigned int offset,
@@ -96,6 +99,10 @@  extern int hid_bpf_attach_prog_impl(unsigned int hid_id,
 				    enum hid_bpf_prog_type type,
 				    int (prog_fn)(struct hid_bpf_ctx *hid_ctx),
 				    u32 flags, void *aux) __ksym;
+extern int hid_bpf_attach_sleepable_prog_impl(unsigned int hid_id,
+					      enum hid_bpf_prog_type type,
+					      int (prog_fn)(struct hid_bpf_ctx *hid_ctx),
+					      u32 flags, void *aux) __ksym;
 extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
 extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
 extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
@@ -110,12 +117,12 @@  extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
 				__u8 *data,
 				size_t buf__sz) __ksym;
 
-#define __HID_BPF_PROG(type, name, arg)                                                            \
+#define __HID_BPF_PROG(type, name, arg, sleepable)                                                 \
 	static int __##name(arg);                                                                  \
 	SEC("syscall")                                                                             \
 	int name(struct attach_prog_args *ctx)                                                     \
 	{                                                                                          \
-		ctx->retval = hid_bpf_attach_prog_impl(ctx->hid,                                   \
+		ctx->retval = hid_bpf_attach_##sleepable##prog_impl(ctx->hid,                      \
 						  type,                                            \
 						  __##name,                                        \
 						  ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD :    \
@@ -125,7 +132,9 @@  extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
 	}                                                                                          \
 	static int __##name(arg)
 
-#define HID_BPF_DEVICE_EVENT(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_DEVICE_EVENT, name, arg)
-#define HID_BPF_RDESC_FIXUP(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RDESC_FIXUP, name, arg)
+#define HID_BPF_DEVICE_EVENT(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_DEVICE_EVENT, name, arg, )
+#define HID_BPF_RDESC_FIXUP(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RDESC_FIXUP, name, arg, )
+#define HID_BPF_RAW_REQUEST(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RAW_REQUEST, name, arg, )
+#define HID_BPF_SLEEPABLE_RAW_REQUEST(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RAW_REQUEST, name, arg, sleepable_)
 
 #endif /* __HID_BPF_HELPERS_H */