brintos

brintos / linux-shallow public Read only

0
0
Text · 23.5 KiB · 86f4d66 Raw
935 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2022-2024 Red Hat */3#include "hid.skel.h"4#include "hid_common.h"5#include <bpf/bpf.h>6 7struct attach_prog_args {8	int prog_fd;9	unsigned int hid;10	int retval;11	int insert_head;12};13 14struct hid_hw_request_syscall_args {15	__u8 data[10];16	unsigned int hid;17	int retval;18	size_t size;19	enum hid_report_type type;20	__u8 request_type;21};22 23FIXTURE(hid_bpf) {24	int dev_id;25	int uhid_fd;26	int hidraw_fd;27	int hid_id;28	pthread_t tid;29	struct hid *skel;30	struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */31};32static void detach_bpf(FIXTURE_DATA(hid_bpf) * self)33{34	int i;35 36	if (self->hidraw_fd)37		close(self->hidraw_fd);38	self->hidraw_fd = 0;39 40	if (!self->skel)41		return;42 43	hid__detach(self->skel);44 45	for (i = 0; i < ARRAY_SIZE(self->hid_links); i++) {46		if (self->hid_links[i])47			bpf_link__destroy(self->hid_links[i]);48	}49 50	hid__destroy(self->skel);51	self->skel = NULL;52}53 54FIXTURE_TEARDOWN(hid_bpf) {55	void *uhid_err;56 57	uhid_destroy(_metadata, self->uhid_fd);58 59	detach_bpf(self);60	pthread_join(self->tid, &uhid_err);61}62#define TEARDOWN_LOG(fmt, ...) do { \63	TH_LOG(fmt, ##__VA_ARGS__); \64	hid_bpf_teardown(_metadata, self, variant); \65} while (0)66 67FIXTURE_SETUP(hid_bpf)68{69	time_t t;70	int err;71 72	/* initialize random number generator */73	srand((unsigned int)time(&t));74 75	self->dev_id = rand() % 1024;76 77	self->uhid_fd = setup_uhid(_metadata, self->dev_id);78 79	/* locate the uev, self, variant);ent file of the created device */80	self->hid_id = get_hid_id(self->dev_id);81	ASSERT_GT(self->hid_id, 0)82		TEARDOWN_LOG("Could not locate uhid device id: %d", self->hid_id);83 84	err = uhid_start_listener(_metadata, &self->tid, self->uhid_fd);85	ASSERT_EQ(0, err) TEARDOWN_LOG("could not start udev listener: %d", err);86}87 88struct test_program {89	const char *name;90	int insert_head;91};92#define LOAD_PROGRAMS(progs) \93	load_programs(progs, ARRAY_SIZE(progs), _metadata, self, variant)94#define LOAD_BPF \95	load_programs(NULL, 0, _metadata, self, variant)96static void load_programs(const struct test_program programs[],97			  const size_t progs_count,98			  struct __test_metadata *_metadata,99			  FIXTURE_DATA(hid_bpf) * self,100			  const FIXTURE_VARIANT(hid_bpf) * variant)101{102	struct bpf_map *iter_map;103	int err = -EINVAL;104 105	ASSERT_LE(progs_count, ARRAY_SIZE(self->hid_links))106		TH_LOG("too many programs are to be loaded");107 108	/* open the bpf file */109	self->skel = hid__open();110	ASSERT_OK_PTR(self->skel) TEARDOWN_LOG("Error while calling hid__open");111 112	for (int i = 0; i < progs_count; i++) {113		struct bpf_program *prog;114		struct bpf_map *map;115		int *ops_hid_id;116 117		prog = bpf_object__find_program_by_name(*self->skel->skeleton->obj,118							programs[i].name);119		ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name);120 121		bpf_program__set_autoload(prog, true);122 123		map = bpf_object__find_map_by_name(*self->skel->skeleton->obj,124							  programs[i].name + 4);125		ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'",126					  programs[i].name + 4);127 128		/* hid_id is the first field of struct hid_bpf_ops */129		ops_hid_id = bpf_map__initial_value(map, NULL);130		ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data");131 132		*ops_hid_id = self->hid_id;133	}134 135	/* we disable the auto-attach feature of all maps because we136	 * only want the tested one to be manually attached in the next137	 * call to bpf_map__attach_struct_ops()138	 */139	bpf_object__for_each_map(iter_map, *self->skel->skeleton->obj)140		bpf_map__set_autoattach(iter_map, false);141 142	err = hid__load(self->skel);143	ASSERT_OK(err) TH_LOG("hid_skel_load failed: %d", err);144 145	for (int i = 0; i < progs_count; i++) {146		struct bpf_map *map;147 148		map = bpf_object__find_map_by_name(*self->skel->skeleton->obj,149							  programs[i].name + 4);150		ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'",151					  programs[i].name + 4);152 153		self->hid_links[i] = bpf_map__attach_struct_ops(map);154		ASSERT_OK_PTR(self->hid_links[i]) TH_LOG("failed to attach struct ops '%s'",155							 programs[i].name + 4);156	}157 158	hid__attach(self->skel);159 160	self->hidraw_fd = open_hidraw(self->dev_id);161	ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");162}163 164/*165 * A simple test to see if the fixture is working fine.166 * If this fails, none of the other tests will pass.167 */168TEST_F(hid_bpf, test_create_uhid)169{170}171 172/*173 * Attach hid_first_event to the given uhid device,174 * retrieve and open the matching hidraw node,175 * inject one event in the uhid device,176 * check that the program sees it and can change the data177 */178TEST_F(hid_bpf, raw_event)179{180	const struct test_program progs[] = {181		{ .name = "hid_first_event" },182	};183	__u8 buf[10] = {0};184	int err;185 186	LOAD_PROGRAMS(progs);187 188	/* check that the program is correctly loaded */189	ASSERT_EQ(self->skel->data->callback_check, 52) TH_LOG("callback_check1");190	ASSERT_EQ(self->skel->data->callback2_check, 52) TH_LOG("callback2_check1");191 192	/* inject one event */193	buf[0] = 1;194	buf[1] = 42;195	uhid_send_event(_metadata, self->uhid_fd, buf, 6);196 197	/* check that hid_first_event() was executed */198	ASSERT_EQ(self->skel->data->callback_check, 42) TH_LOG("callback_check1");199 200	/* read the data from hidraw */201	memset(buf, 0, sizeof(buf));202	err = read(self->hidraw_fd, buf, sizeof(buf));203	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");204	ASSERT_EQ(buf[0], 1);205	ASSERT_EQ(buf[2], 47);206 207	/* inject another event */208	memset(buf, 0, sizeof(buf));209	buf[0] = 1;210	buf[1] = 47;211	uhid_send_event(_metadata, self->uhid_fd, buf, 6);212 213	/* check that hid_first_event() was executed */214	ASSERT_EQ(self->skel->data->callback_check, 47) TH_LOG("callback_check1");215 216	/* read the data from hidraw */217	memset(buf, 0, sizeof(buf));218	err = read(self->hidraw_fd, buf, sizeof(buf));219	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");220	ASSERT_EQ(buf[2], 52);221}222 223/*224 * Attach hid_first_event to the given uhid device,225 * retrieve and open the matching hidraw node,226 * inject one event in the uhid device,227 * check that the program sees it and can change the data228 */229TEST_F(hid_bpf, subprog_raw_event)230{231	const struct test_program progs[] = {232		{ .name = "hid_subprog_first_event" },233	};234	__u8 buf[10] = {0};235	int err;236 237	LOAD_PROGRAMS(progs);238 239	/* inject one event */240	buf[0] = 1;241	buf[1] = 42;242	uhid_send_event(_metadata, self->uhid_fd, buf, 6);243 244	/* read the data from hidraw */245	memset(buf, 0, sizeof(buf));246	err = read(self->hidraw_fd, buf, sizeof(buf));247	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");248	ASSERT_EQ(buf[0], 1);249	ASSERT_EQ(buf[2], 47);250 251	/* inject another event */252	memset(buf, 0, sizeof(buf));253	buf[0] = 1;254	buf[1] = 47;255	uhid_send_event(_metadata, self->uhid_fd, buf, 6);256 257	/* read the data from hidraw */258	memset(buf, 0, sizeof(buf));259	err = read(self->hidraw_fd, buf, sizeof(buf));260	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");261	ASSERT_EQ(buf[2], 52);262}263 264/*265 * Attach hid_first_event to the given uhid device,266 * attempt at re-attaching it, we should not lock and267 * return an invalid struct bpf_link268 */269TEST_F(hid_bpf, multiple_attach)270{271	const struct test_program progs[] = {272		{ .name = "hid_first_event" },273	};274	struct bpf_link *link;275 276	LOAD_PROGRAMS(progs);277 278	link = bpf_map__attach_struct_ops(self->skel->maps.first_event);279	ASSERT_NULL(link) TH_LOG("unexpected return value when re-attaching the struct_ops");280}281 282/*283 * Ensures that we can attach/detach programs284 */285TEST_F(hid_bpf, test_attach_detach)286{287	const struct test_program progs[] = {288		{ .name = "hid_first_event" },289		{ .name = "hid_second_event" },290	};291	struct bpf_link *link;292	__u8 buf[10] = {0};293	int err, link_fd;294 295	LOAD_PROGRAMS(progs);296 297	link = self->hid_links[0];298	ASSERT_OK_PTR(link) TH_LOG("HID-BPF link not created");299 300	link_fd = bpf_link__fd(link);301	ASSERT_GE(link_fd, 0) TH_LOG("HID-BPF link FD not valid");302 303	/* inject one event */304	buf[0] = 1;305	buf[1] = 42;306	uhid_send_event(_metadata, self->uhid_fd, buf, 6);307 308	/* read the data from hidraw */309	memset(buf, 0, sizeof(buf));310	err = read(self->hidraw_fd, buf, sizeof(buf));311	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");312	ASSERT_EQ(buf[0], 1);313	ASSERT_EQ(buf[2], 47);314 315	/* make sure both programs are run */316	ASSERT_EQ(buf[3], 52);317 318	/* pin the first program and immediately unpin it */319#define PIN_PATH "/sys/fs/bpf/hid_first_event"320	err = bpf_obj_pin(link_fd, PIN_PATH);321	ASSERT_OK(err) TH_LOG("error while calling bpf_obj_pin");322	remove(PIN_PATH);323#undef PIN_PATH324	usleep(100000);325 326	/* detach the program */327	detach_bpf(self);328 329	self->hidraw_fd = open_hidraw(self->dev_id);330	ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");331 332	/* inject another event */333	memset(buf, 0, sizeof(buf));334	buf[0] = 1;335	buf[1] = 47;336	uhid_send_event(_metadata, self->uhid_fd, buf, 6);337 338	/* read the data from hidraw */339	memset(buf, 0, sizeof(buf));340	err = read(self->hidraw_fd, buf, sizeof(buf));341	ASSERT_EQ(err, 6) TH_LOG("read_hidraw_no_bpf");342	ASSERT_EQ(buf[0], 1);343	ASSERT_EQ(buf[1], 47);344	ASSERT_EQ(buf[2], 0);345	ASSERT_EQ(buf[3], 0);346 347	/* re-attach our program */348 349	LOAD_PROGRAMS(progs);350 351	/* inject one event */352	memset(buf, 0, sizeof(buf));353	buf[0] = 1;354	buf[1] = 42;355	uhid_send_event(_metadata, self->uhid_fd, buf, 6);356 357	/* read the data from hidraw */358	memset(buf, 0, sizeof(buf));359	err = read(self->hidraw_fd, buf, sizeof(buf));360	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");361	ASSERT_EQ(buf[0], 1);362	ASSERT_EQ(buf[2], 47);363	ASSERT_EQ(buf[3], 52);364}365 366/*367 * Attach hid_change_report_id to the given uhid device,368 * retrieve and open the matching hidraw node,369 * inject one event in the uhid device,370 * check that the program sees it and can change the data371 */372TEST_F(hid_bpf, test_hid_change_report)373{374	const struct test_program progs[] = {375		{ .name = "hid_change_report_id" },376	};377	__u8 buf[10] = {0};378	int err;379 380	LOAD_PROGRAMS(progs);381 382	/* inject one event */383	buf[0] = 1;384	buf[1] = 42;385	uhid_send_event(_metadata, self->uhid_fd, buf, 6);386 387	/* read the data from hidraw */388	memset(buf, 0, sizeof(buf));389	err = read(self->hidraw_fd, buf, sizeof(buf));390	ASSERT_EQ(err, 9) TH_LOG("read_hidraw");391	ASSERT_EQ(buf[0], 2);392	ASSERT_EQ(buf[1], 42);393	ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");394}395 396/*397 * Call hid_bpf_input_report against the given uhid device,398 * check that the program is called and does the expected.399 */400TEST_F(hid_bpf, test_hid_user_input_report_call)401{402	struct hid_hw_request_syscall_args args = {403		.retval = -1,404		.size = 10,405	};406	DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,407			    .ctx_in = &args,408			    .ctx_size_in = sizeof(args),409	);410	__u8 buf[10] = {0};411	int err, prog_fd;412 413	LOAD_BPF;414 415	args.hid = self->hid_id;416	args.data[0] = 1; /* report ID */417	args.data[1] = 2; /* report ID */418	args.data[2] = 42; /* report ID */419 420	prog_fd = bpf_program__fd(self->skel->progs.hid_user_input_report);421 422	/* check that there is no data to read from hidraw */423	memset(buf, 0, sizeof(buf));424	err = read(self->hidraw_fd, buf, sizeof(buf));425	ASSERT_EQ(err, -1) TH_LOG("read_hidraw");426 427	err = bpf_prog_test_run_opts(prog_fd, &tattrs);428 429	ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");430 431	ASSERT_EQ(args.retval, 0);432 433	/* read the data from hidraw */434	memset(buf, 0, sizeof(buf));435	err = read(self->hidraw_fd, buf, sizeof(buf));436	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");437	ASSERT_EQ(buf[0], 1);438	ASSERT_EQ(buf[1], 2);439	ASSERT_EQ(buf[2], 42);440}441 442/*443 * Call hid_bpf_hw_output_report against the given uhid device,444 * check that the program is called and does the expected.445 */446TEST_F(hid_bpf, test_hid_user_output_report_call)447{448	struct hid_hw_request_syscall_args args = {449		.retval = -1,450		.size = 10,451	};452	DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,453			    .ctx_in = &args,454			    .ctx_size_in = sizeof(args),455	);456	int err, cond_err, prog_fd;457	struct timespec time_to_wait;458 459	LOAD_BPF;460 461	args.hid = self->hid_id;462	args.data[0] = 1; /* report ID */463	args.data[1] = 2; /* report ID */464	args.data[2] = 42; /* report ID */465 466	prog_fd = bpf_program__fd(self->skel->progs.hid_user_output_report);467 468	pthread_mutex_lock(&uhid_output_mtx);469 470	memset(output_report, 0, sizeof(output_report));471	clock_gettime(CLOCK_REALTIME, &time_to_wait);472	time_to_wait.tv_sec += 2;473 474	err = bpf_prog_test_run_opts(prog_fd, &tattrs);475	cond_err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);476 477	ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");478	ASSERT_OK(cond_err) TH_LOG("error while calling waiting for the condition");479 480	ASSERT_EQ(args.retval, 3);481 482	ASSERT_EQ(output_report[0], 1);483	ASSERT_EQ(output_report[1], 2);484	ASSERT_EQ(output_report[2], 42);485 486	pthread_mutex_unlock(&uhid_output_mtx);487}488 489/*490 * Call hid_hw_raw_request against the given uhid device,491 * check that the program is called and does the expected.492 */493TEST_F(hid_bpf, test_hid_user_raw_request_call)494{495	struct hid_hw_request_syscall_args args = {496		.retval = -1,497		.type = HID_FEATURE_REPORT,498		.request_type = HID_REQ_GET_REPORT,499		.size = 10,500	};501	DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,502			    .ctx_in = &args,503			    .ctx_size_in = sizeof(args),504	);505	int err, prog_fd;506 507	LOAD_BPF;508 509	args.hid = self->hid_id;510	args.data[0] = 1; /* report ID */511 512	prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request);513 514	err = bpf_prog_test_run_opts(prog_fd, &tattrs);515	ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");516 517	ASSERT_EQ(args.retval, 2);518 519	ASSERT_EQ(args.data[1], 2);520}521 522/*523 * Call hid_hw_raw_request against the given uhid device,524 * check that the program is called and prevents the525 * call to uhid.526 */527TEST_F(hid_bpf, test_hid_filter_raw_request_call)528{529	const struct test_program progs[] = {530		{ .name = "hid_test_filter_raw_request" },531	};532	__u8 buf[10] = {0};533	int err;534 535	LOAD_PROGRAMS(progs);536 537	/* first check that we did not attach to device_event */538 539	/* inject one event */540	buf[0] = 1;541	buf[1] = 42;542	uhid_send_event(_metadata, self->uhid_fd, buf, 6);543 544	/* read the data from hidraw */545	memset(buf, 0, sizeof(buf));546	err = read(self->hidraw_fd, buf, sizeof(buf));547	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");548	ASSERT_EQ(buf[0], 1);549	ASSERT_EQ(buf[1], 42);550	ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");551 552	/* now check that our program is preventing hid_hw_raw_request() */553 554	/* emit hid_hw_raw_request from hidraw */555	/* Get Feature */556	memset(buf, 0, sizeof(buf));557	buf[0] = 0x1; /* Report Number */558	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);559	ASSERT_LT(err, 0) TH_LOG("unexpected success while reading HIDIOCGFEATURE: %d", err);560	ASSERT_EQ(errno, 20) TH_LOG("unexpected error code while reading HIDIOCGFEATURE: %d",561				    errno);562 563	/* remove our bpf program and check that we can now emit commands */564 565	/* detach the program */566	detach_bpf(self);567 568	self->hidraw_fd = open_hidraw(self->dev_id);569	ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");570 571	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);572	ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGFEATURE: %d", err);573}574 575/*576 * Call hid_hw_raw_request against the given uhid device,577 * check that the program is called and can issue the call578 * to uhid and transform the answer.579 */580TEST_F(hid_bpf, test_hid_change_raw_request_call)581{582	const struct test_program progs[] = {583		{ .name = "hid_test_hidraw_raw_request" },584	};585	__u8 buf[10] = {0};586	int err;587 588	LOAD_PROGRAMS(progs);589 590	/* emit hid_hw_raw_request from hidraw */591	/* Get Feature */592	memset(buf, 0, sizeof(buf));593	buf[0] = 0x1; /* Report Number */594	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);595	ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err);596 597	ASSERT_EQ(buf[0], 2);598	ASSERT_EQ(buf[1], 3);599	ASSERT_EQ(buf[2], 4);600}601 602/*603 * Call hid_hw_raw_request against the given uhid device,604 * check that the program is not making infinite loops.605 */606TEST_F(hid_bpf, test_hid_infinite_loop_raw_request_call)607{608	const struct test_program progs[] = {609		{ .name = "hid_test_infinite_loop_raw_request" },610	};611	__u8 buf[10] = {0};612	int err;613 614	LOAD_PROGRAMS(progs);615 616	/* emit hid_hw_raw_request from hidraw */617	/* Get Feature */618	memset(buf, 0, sizeof(buf));619	buf[0] = 0x1; /* Report Number */620	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);621	ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err);622}623 624/*625 * Call hid_hw_output_report against the given uhid device,626 * check that the program is called and prevents the627 * call to uhid.628 */629TEST_F(hid_bpf, test_hid_filter_output_report_call)630{631	const struct test_program progs[] = {632		{ .name = "hid_test_filter_output_report" },633	};634	__u8 buf[10] = {0};635	int err;636 637	LOAD_PROGRAMS(progs);638 639	/* first check that we did not attach to device_event */640 641	/* inject one event */642	buf[0] = 1;643	buf[1] = 42;644	uhid_send_event(_metadata, self->uhid_fd, buf, 6);645 646	/* read the data from hidraw */647	memset(buf, 0, sizeof(buf));648	err = read(self->hidraw_fd, buf, sizeof(buf));649	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");650	ASSERT_EQ(buf[0], 1);651	ASSERT_EQ(buf[1], 42);652	ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");653 654	/* now check that our program is preventing hid_hw_output_report() */655 656	buf[0] = 1; /* report ID */657	buf[1] = 2;658	buf[2] = 42;659 660	err = write(self->hidraw_fd, buf, 3);661	ASSERT_LT(err, 0) TH_LOG("unexpected success while sending hid_hw_output_report: %d", err);662	ASSERT_EQ(errno, 25) TH_LOG("unexpected error code while sending hid_hw_output_report: %d",663				    errno);664 665	/* remove our bpf program and check that we can now emit commands */666 667	/* detach the program */668	detach_bpf(self);669 670	self->hidraw_fd = open_hidraw(self->dev_id);671	ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");672 673	err = write(self->hidraw_fd, buf, 3);674	ASSERT_GE(err, 0) TH_LOG("error while sending hid_hw_output_report: %d", err);675}676 677/*678 * Call hid_hw_output_report against the given uhid device,679 * check that the program is called and can issue the call680 * to uhid and transform the answer.681 */682TEST_F(hid_bpf, test_hid_change_output_report_call)683{684	const struct test_program progs[] = {685		{ .name = "hid_test_hidraw_output_report" },686	};687	__u8 buf[10] = {0};688	int err;689 690	LOAD_PROGRAMS(progs);691 692	/* emit hid_hw_output_report from hidraw */693	buf[0] = 1; /* report ID */694	buf[1] = 2;695	buf[2] = 42;696 697	err = write(self->hidraw_fd, buf, 10);698	ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d",699				 err);700}701 702/*703 * Call hid_hw_output_report against the given uhid device,704 * check that the program is not making infinite loops.705 */706TEST_F(hid_bpf, test_hid_infinite_loop_output_report_call)707{708	const struct test_program progs[] = {709		{ .name = "hid_test_infinite_loop_output_report" },710	};711	__u8 buf[10] = {0};712	int err;713 714	LOAD_PROGRAMS(progs);715 716	/* emit hid_hw_output_report from hidraw */717	buf[0] = 1; /* report ID */718	buf[1] = 2;719	buf[2] = 42;720 721	err = write(self->hidraw_fd, buf, 8);722	ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d",723				 err);724}725 726/*727 * Attach hid_multiply_event_wq to the given uhid device,728 * retrieve and open the matching hidraw node,729 * inject one event in the uhid device,730 * check that the program sees it and can add extra data731 */732TEST_F(hid_bpf, test_multiply_events_wq)733{734	const struct test_program progs[] = {735		{ .name = "hid_test_multiply_events_wq" },736	};737	__u8 buf[10] = {0};738	int err;739 740	LOAD_PROGRAMS(progs);741 742	/* inject one event */743	buf[0] = 1;744	buf[1] = 42;745	uhid_send_event(_metadata, self->uhid_fd, buf, 6);746 747	/* read the data from hidraw */748	memset(buf, 0, sizeof(buf));749	err = read(self->hidraw_fd, buf, sizeof(buf));750	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");751	ASSERT_EQ(buf[0], 1);752	ASSERT_EQ(buf[1], 47);753 754	usleep(100000);755 756	/* read the data from hidraw */757	memset(buf, 0, sizeof(buf));758	err = read(self->hidraw_fd, buf, sizeof(buf));759	ASSERT_EQ(err, 9) TH_LOG("read_hidraw");760	ASSERT_EQ(buf[0], 2);761	ASSERT_EQ(buf[1], 3);762}763 764/*765 * Attach hid_multiply_event to the given uhid device,766 * retrieve and open the matching hidraw node,767 * inject one event in the uhid device,768 * check that the program sees it and can add extra data769 */770TEST_F(hid_bpf, test_multiply_events)771{772	const struct test_program progs[] = {773		{ .name = "hid_test_multiply_events" },774	};775	__u8 buf[10] = {0};776	int err;777 778	LOAD_PROGRAMS(progs);779 780	/* inject one event */781	buf[0] = 1;782	buf[1] = 42;783	uhid_send_event(_metadata, self->uhid_fd, buf, 6);784 785	/* read the data from hidraw */786	memset(buf, 0, sizeof(buf));787	err = read(self->hidraw_fd, buf, sizeof(buf));788	ASSERT_EQ(err, 9) TH_LOG("read_hidraw");789	ASSERT_EQ(buf[0], 2);790	ASSERT_EQ(buf[1], 47);791 792	/* read the data from hidraw */793	memset(buf, 0, sizeof(buf));794	err = read(self->hidraw_fd, buf, sizeof(buf));795	ASSERT_EQ(err, 9) TH_LOG("read_hidraw");796	ASSERT_EQ(buf[0], 2);797	ASSERT_EQ(buf[1], 52);798}799 800/*801 * Call hid_bpf_input_report against the given uhid device,802 * check that the program is not making infinite loops.803 */804TEST_F(hid_bpf, test_hid_infinite_loop_input_report_call)805{806	const struct test_program progs[] = {807		{ .name = "hid_test_infinite_loop_input_report" },808	};809	__u8 buf[10] = {0};810	int err;811 812	LOAD_PROGRAMS(progs);813 814	/* emit hid_hw_output_report from hidraw */815	buf[0] = 1; /* report ID */816	buf[1] = 2;817	buf[2] = 42;818 819	uhid_send_event(_metadata, self->uhid_fd, buf, 6);820 821	/* read the data from hidraw */822	memset(buf, 0, sizeof(buf));823	err = read(self->hidraw_fd, buf, sizeof(buf));824	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");825	ASSERT_EQ(buf[0], 1);826	ASSERT_EQ(buf[1], 3);827 828	/* read the data from hidraw: hid_bpf_try_input_report should work exactly one time */829	memset(buf, 0, sizeof(buf));830	err = read(self->hidraw_fd, buf, sizeof(buf));831	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");832	ASSERT_EQ(buf[0], 1);833	ASSERT_EQ(buf[1], 4);834 835	/* read the data from hidraw: there should be none */836	memset(buf, 0, sizeof(buf));837	err = read(self->hidraw_fd, buf, sizeof(buf));838	ASSERT_EQ(err, -1) TH_LOG("read_hidraw");839}840 841/*842 * Attach hid_insert{0,1,2} to the given uhid device,843 * retrieve and open the matching hidraw node,844 * inject one event in the uhid device,845 * check that the programs have been inserted in the correct order.846 */847TEST_F(hid_bpf, test_hid_attach_flags)848{849	const struct test_program progs[] = {850		{851			.name = "hid_test_insert2",852			.insert_head = 0,853		},854		{855			.name = "hid_test_insert1",856			.insert_head = 1,857		},858		{859			.name = "hid_test_insert3",860			.insert_head = 0,861		},862	};863	__u8 buf[10] = {0};864	int err;865 866	LOAD_PROGRAMS(progs);867 868	/* inject one event */869	buf[0] = 1;870	uhid_send_event(_metadata, self->uhid_fd, buf, 6);871 872	/* read the data from hidraw */873	memset(buf, 0, sizeof(buf));874	err = read(self->hidraw_fd, buf, sizeof(buf));875	ASSERT_EQ(err, 6) TH_LOG("read_hidraw");876	ASSERT_EQ(buf[1], 1);877	ASSERT_EQ(buf[2], 2);878	ASSERT_EQ(buf[3], 3);879}880 881/*882 * Attach hid_rdesc_fixup to the given uhid device,883 * retrieve and open the matching hidraw node,884 * check that the hidraw report descriptor has been updated.885 */886TEST_F(hid_bpf, test_rdesc_fixup)887{888	struct hidraw_report_descriptor rpt_desc = {0};889	const struct test_program progs[] = {890		{ .name = "hid_rdesc_fixup" },891	};892	int err, desc_size;893 894	LOAD_PROGRAMS(progs);895 896	/* check that hid_rdesc_fixup() was executed */897	ASSERT_EQ(self->skel->data->callback2_check, 0x21);898 899	/* read the exposed report descriptor from hidraw */900	err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);901	ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESCSIZE: %d", err);902 903	/* ensure the new size of the rdesc is bigger than the old one */904	ASSERT_GT(desc_size, sizeof(rdesc));905 906	rpt_desc.size = desc_size;907	err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &rpt_desc);908	ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESC: %d", err);909 910	ASSERT_EQ(rpt_desc.value[4], 0x42);911}912 913static int libbpf_print_fn(enum libbpf_print_level level,914			   const char *format, va_list args)915{916	char buf[1024];917 918	if (level == LIBBPF_DEBUG)919		return 0;920 921	snprintf(buf, sizeof(buf), "# %s", format);922 923	vfprintf(stdout, buf, args);924	return 0;925}926 927int main(int argc, char **argv)928{929	/* Use libbpf 1.0 API mode */930	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);931	libbpf_set_print(libbpf_print_fn);932 933	return test_harness_run(argc, argv);934}935