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