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