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