Commit 4f7153cf authored by Benjamin Tissoires's avatar Benjamin Tissoires Committed by Jiri Kosina
Browse files

selftests/hid: add tests for bpf_hid_hw_request



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: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 91a7f802
Loading
Loading
Loading
Loading
+55 −1
Original line number Diff line number Diff line
@@ -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)
{
+36 −0
Original line number Diff line number Diff line
@@ -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;
}
+7 −0
Original line number Diff line number Diff line
@@ -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 */