@@ -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,
@@ -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;
+}
@@ -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 */
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(-)