selftests/hid: add tests for bpf_hid_hw_request
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>
Thu, 3 Nov 2022 15:57:50 +0000 (16:57 +0100)
committerJiri Kosina <jkosina@suse.cz>
Tue, 15 Nov 2022 15:28:31 +0000 (16:28 +0100)
Add tests for the newly implemented function.
We test here only the GET_REPORT part because the other calls are pure
HID protocol and won't infer the result of the test of the bpf hook.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
tools/testing/selftests/hid/hid_bpf.c
tools/testing/selftests/hid/progs/hid.c
tools/testing/selftests/hid/progs/hid_bpf_helpers.h

index 6c1f43e..f77ee7f 100644 (file)
@@ -82,12 +82,23 @@ static unsigned char rdesc[] = {
        0xc0,                   /* END_COLLECTION */
 };
 
+static __u8 feature_data[] = { 1, 2 };
+
 struct attach_prog_args {
        int prog_fd;
        unsigned int hid;
        int retval;
 };
 
+struct hid_hw_request_syscall_args {
+       __u8 data[10];
+       unsigned int hid;
+       int retval;
+       size_t size;
+       enum hid_report_type type;
+       __u8 request_type;
+};
+
 #define ASSERT_OK(data) ASSERT_FALSE(data)
 #define ASSERT_OK_PTR(ptr) ASSERT_NE(NULL, ptr)
 
@@ -155,7 +166,7 @@ static void uhid_destroy(struct __test_metadata *_metadata, int fd)
 
 static int uhid_event(struct __test_metadata *_metadata, int fd)
 {
-       struct uhid_event ev;
+       struct uhid_event ev, answer;
        ssize_t ret;
 
        memset(&ev, 0, sizeof(ev));
@@ -196,6 +207,15 @@ static int uhid_event(struct __test_metadata *_metadata, int fd)
                break;
        case UHID_GET_REPORT:
                UHID_LOG("UHID_GET_REPORT from uhid-dev");
+
+               answer.type = UHID_GET_REPORT_REPLY;
+               answer.u.get_report_reply.id = ev.u.get_report.id;
+               answer.u.get_report_reply.err = ev.u.get_report.rnum == 1 ? 0 : -EIO;
+               answer.u.get_report_reply.size = sizeof(feature_data);
+               memcpy(answer.u.get_report_reply.data, feature_data, sizeof(feature_data));
+
+               uhid_write(_metadata, fd, &answer);
+
                break;
        case UHID_SET_REPORT:
                UHID_LOG("UHID_SET_REPORT from uhid-dev");
@@ -686,6 +706,40 @@ TEST_F(hid_bpf, test_hid_change_report)
        ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");
 }
 
+/*
+ * Attach hid_user_raw_request to the given uhid device,
+ * call the bpf program from userspace
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_user_raw_request_call)
+{
+       struct hid_hw_request_syscall_args args = {
+               .retval = -1,
+               .type = HID_FEATURE_REPORT,
+               .request_type = HID_REQ_GET_REPORT,
+               .size = 10,
+       };
+       DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
+                           .ctx_in = &args,
+                           .ctx_size_in = sizeof(args),
+       );
+       int err, prog_fd;
+
+       LOAD_BPF;
+
+       args.hid = self->hid_id;
+       args.data[0] = 1; /* report ID */
+
+       prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request);
+
+       err = bpf_prog_test_run_opts(prog_fd, &tattrs);
+       ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");
+
+       ASSERT_EQ(args.retval, 2);
+
+       ASSERT_EQ(args.data[1], 2);
+}
+
 static int libbpf_print_fn(enum libbpf_print_level level,
                           const char *format, va_list args)
 {
index b69c3f8..7e35bb8 100644 (file)
@@ -52,3 +52,39 @@ int attach_prog(struct attach_prog_args *ctx)
                                          0);
        return 0;
 }
+
+struct hid_hw_request_syscall_args {
+       /* data needs to come at offset 0 so we can use it in calls */
+       __u8 data[10];
+       unsigned int hid;
+       int retval;
+       size_t size;
+       enum hid_report_type type;
+       __u8 request_type;
+};
+
+SEC("syscall")
+int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
+{
+       struct hid_bpf_ctx *ctx;
+       const size_t size = args->size;
+       int i, ret = 0;
+
+       if (size > sizeof(args->data))
+               return -7; /* -E2BIG */
+
+       ctx = hid_bpf_allocate_context(args->hid);
+       if (!ctx)
+               return -1; /* EPERM check */
+
+       ret = hid_bpf_hw_request(ctx,
+                                args->data,
+                                size,
+                                args->type,
+                                args->request_type);
+       args->retval = ret;
+
+       hid_bpf_release_context(ctx);
+
+       return 0;
+}
index b9fa33f..4fff31d 100644 (file)
@@ -10,5 +10,12 @@ extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
                              unsigned int offset,
                              const size_t __sz) __ksym;
 extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __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,
+                             __u8 *data,
+                             size_t buf__sz,
+                             enum hid_report_type type,
+                             enum hid_class_request reqtype) __ksym;
 
 #endif /* __HID_BPF_HELPERS_H */