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