Signed-off-by: Benjamin Tissoires <bentiss@xxxxxxxxxx> --- 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 --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 */ -- 2.44.0