~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/hid/progs/hid.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2022 Red hat */
  3 #include "hid_bpf_helpers.h"
  4 
  5 char _license[] SEC("license") = "GPL";
  6 
  7 struct attach_prog_args {
  8         int prog_fd;
  9         unsigned int hid;
 10         int retval;
 11         int insert_head;
 12 };
 13 
 14 __u64 callback_check = 52;
 15 __u64 callback2_check = 52;
 16 
 17 SEC("?struct_ops/hid_device_event")
 18 int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
 19 {
 20         __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
 21 
 22         if (!rw_data)
 23                 return 0; /* EPERM check */
 24 
 25         callback_check = rw_data[1];
 26 
 27         rw_data[2] = rw_data[1] + 5;
 28 
 29         return hid_ctx->size;
 30 }
 31 
 32 SEC(".struct_ops.link")
 33 struct hid_bpf_ops first_event = {
 34         .hid_device_event = (void *)hid_first_event,
 35         .hid_id = 2,
 36 };
 37 
 38 int __hid_subprog_first_event(struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
 39 {
 40         __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
 41 
 42         if (!rw_data)
 43                 return 0; /* EPERM check */
 44 
 45         rw_data[2] = rw_data[1] + 5;
 46 
 47         return hid_ctx->size;
 48 }
 49 
 50 SEC("?struct_ops/hid_device_event")
 51 int BPF_PROG(hid_subprog_first_event, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
 52 {
 53         return __hid_subprog_first_event(hid_ctx, type);
 54 }
 55 
 56 SEC(".struct_ops.link")
 57 struct hid_bpf_ops subprog_first_event = {
 58         .hid_device_event = (void *)hid_subprog_first_event,
 59         .hid_id = 2,
 60 };
 61 
 62 SEC("?struct_ops/hid_device_event")
 63 int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
 64 {
 65         __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
 66 
 67         if (!rw_data)
 68                 return 0; /* EPERM check */
 69 
 70         rw_data[3] = rw_data[2] + 5;
 71 
 72         return hid_ctx->size;
 73 }
 74 
 75 SEC(".struct_ops.link")
 76 struct hid_bpf_ops second_event = {
 77         .hid_device_event = (void *)hid_second_event,
 78 };
 79 
 80 SEC("?struct_ops/hid_device_event")
 81 int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
 82 {
 83         __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
 84 
 85         if (!rw_data)
 86                 return 0; /* EPERM check */
 87 
 88         rw_data[0] = 2;
 89 
 90         return 9;
 91 }
 92 
 93 SEC(".struct_ops.link")
 94 struct hid_bpf_ops change_report_id = {
 95         .hid_device_event = (void *)hid_change_report_id,
 96 };
 97 
 98 struct hid_hw_request_syscall_args {
 99         /* data needs to come at offset 0 so we can use it in calls */
100         __u8 data[10];
101         unsigned int hid;
102         int retval;
103         size_t size;
104         enum hid_report_type type;
105         __u8 request_type;
106 };
107 
108 SEC("syscall")
109 int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
110 {
111         struct hid_bpf_ctx *ctx;
112         const size_t size = args->size;
113         int i, ret = 0;
114 
115         if (size > sizeof(args->data))
116                 return -7; /* -E2BIG */
117 
118         ctx = hid_bpf_allocate_context(args->hid);
119         if (!ctx)
120                 return -1; /* EPERM check */
121 
122         ret = hid_bpf_hw_request(ctx,
123                                  args->data,
124                                  size,
125                                  args->type,
126                                  args->request_type);
127         args->retval = ret;
128 
129         hid_bpf_release_context(ctx);
130 
131         return 0;
132 }
133 
134 SEC("syscall")
135 int hid_user_output_report(struct hid_hw_request_syscall_args *args)
136 {
137         struct hid_bpf_ctx *ctx;
138         const size_t size = args->size;
139         int i, ret = 0;
140 
141         if (size > sizeof(args->data))
142                 return -7; /* -E2BIG */
143 
144         ctx = hid_bpf_allocate_context(args->hid);
145         if (!ctx)
146                 return -1; /* EPERM check */
147 
148         ret = hid_bpf_hw_output_report(ctx,
149                                        args->data,
150                                        size);
151         args->retval = ret;
152 
153         hid_bpf_release_context(ctx);
154 
155         return 0;
156 }
157 
158 SEC("syscall")
159 int hid_user_input_report(struct hid_hw_request_syscall_args *args)
160 {
161         struct hid_bpf_ctx *ctx;
162         const size_t size = args->size;
163         int i, ret = 0;
164 
165         if (size > sizeof(args->data))
166                 return -7; /* -E2BIG */
167 
168         ctx = hid_bpf_allocate_context(args->hid);
169         if (!ctx)
170                 return -1; /* EPERM check */
171 
172         ret = hid_bpf_input_report(ctx, HID_INPUT_REPORT, args->data, size);
173         args->retval = ret;
174 
175         hid_bpf_release_context(ctx);
176 
177         return 0;
178 }
179 
180 static const __u8 rdesc[] = {
181         0x05, 0x01,                             /* USAGE_PAGE (Generic Desktop) */
182         0x09, 0x32,                             /* USAGE (Z) */
183         0x95, 0x01,                             /* REPORT_COUNT (1) */
184         0x81, 0x06,                             /* INPUT (Data,Var,Rel) */
185 
186         0x06, 0x00, 0xff,                       /* Usage Page (Vendor Defined Page 1) */
187         0x19, 0x01,                             /* USAGE_MINIMUM (1) */
188         0x29, 0x03,                             /* USAGE_MAXIMUM (3) */
189         0x15, 0x00,                             /* LOGICAL_MINIMUM (0) */
190         0x25, 0x01,                             /* LOGICAL_MAXIMUM (1) */
191         0x95, 0x03,                             /* REPORT_COUNT (3) */
192         0x75, 0x01,                             /* REPORT_SIZE (1) */
193         0x91, 0x02,                             /* Output (Data,Var,Abs) */
194         0x95, 0x01,                             /* REPORT_COUNT (1) */
195         0x75, 0x05,                             /* REPORT_SIZE (5) */
196         0x91, 0x01,                             /* Output (Cnst,Var,Abs) */
197 
198         0x06, 0x00, 0xff,                       /* Usage Page (Vendor Defined Page 1) */
199         0x19, 0x06,                             /* USAGE_MINIMUM (6) */
200         0x29, 0x08,                             /* USAGE_MAXIMUM (8) */
201         0x15, 0x00,                             /* LOGICAL_MINIMUM (0) */
202         0x25, 0x01,                             /* LOGICAL_MAXIMUM (1) */
203         0x95, 0x03,                             /* REPORT_COUNT (3) */
204         0x75, 0x01,                             /* REPORT_SIZE (1) */
205         0xb1, 0x02,                             /* Feature (Data,Var,Abs) */
206         0x95, 0x01,                             /* REPORT_COUNT (1) */
207         0x75, 0x05,                             /* REPORT_SIZE (5) */
208         0x91, 0x01,                             /* Output (Cnst,Var,Abs) */
209 
210         0xc0,                           /* END_COLLECTION */
211         0xc0,                   /* END_COLLECTION */
212 };
213 
214 /*
215  * the following program is marked as sleepable (struct_ops.s).
216  * This is not strictly mandatory but is a nice test for
217  * sleepable struct_ops
218  */
219 SEC("?struct_ops.s/hid_rdesc_fixup")
220 int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
221 {
222         __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */);
223 
224         if (!data)
225                 return 0; /* EPERM check */
226 
227         callback2_check = data[4];
228 
229         /* insert rdesc at offset 73 */
230         __builtin_memcpy(&data[73], rdesc, sizeof(rdesc));
231 
232         /* Change Usage Vendor globally */
233         data[4] = 0x42;
234 
235         return sizeof(rdesc) + 73;
236 }
237 
238 SEC(".struct_ops.link")
239 struct hid_bpf_ops rdesc_fixup = {
240         .hid_rdesc_fixup = (void *)hid_rdesc_fixup,
241 };
242 
243 SEC("?struct_ops/hid_device_event")
244 int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
245 {
246         __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
247 
248         if (!data)
249                 return 0; /* EPERM check */
250 
251         /* we need to be run first */
252         if (data[2] || data[3])
253                 return -1;
254 
255         data[1] = 1;
256 
257         return 0;
258 }
259 
260 SEC(".struct_ops.link")
261 struct hid_bpf_ops test_insert1 = {
262         .hid_device_event = (void *)hid_test_insert1,
263         .flags = BPF_F_BEFORE,
264 };
265 
266 SEC("?struct_ops/hid_device_event")
267 int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
268 {
269         __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
270 
271         if (!data)
272                 return 0; /* EPERM check */
273 
274         /* after insert0 and before insert2 */
275         if (!data[1] || data[3])
276                 return -1;
277 
278         data[2] = 2;
279 
280         return 0;
281 }
282 
283 SEC(".struct_ops.link")
284 struct hid_bpf_ops test_insert2 = {
285         .hid_device_event = (void *)hid_test_insert2,
286 };
287 
288 SEC("?struct_ops/hid_device_event")
289 int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
290 {
291         __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
292 
293         if (!data)
294                 return 0; /* EPERM check */
295 
296         /* at the end */
297         if (!data[1] || !data[2])
298                 return -1;
299 
300         data[3] = 3;
301 
302         return 0;
303 }
304 
305 SEC(".struct_ops.link")
306 struct hid_bpf_ops test_insert3 = {
307         .hid_device_event = (void *)hid_test_insert3,
308 };
309 
310 SEC("?struct_ops/hid_hw_request")
311 int BPF_PROG(hid_test_filter_raw_request, struct hid_bpf_ctx *hctx, unsigned char reportnum,
312              enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source)
313 {
314         return -20;
315 }
316 
317 SEC(".struct_ops.link")
318 struct hid_bpf_ops test_filter_raw_request = {
319         .hid_hw_request = (void *)hid_test_filter_raw_request,
320 };
321 
322 static struct file *current_file;
323 
324 SEC("fentry/hidraw_open")
325 int BPF_PROG(hidraw_open, struct inode *inode, struct file *file)
326 {
327         current_file = file;
328         return 0;
329 }
330 
331 SEC("?struct_ops.s/hid_hw_request")
332 int BPF_PROG(hid_test_hidraw_raw_request, struct hid_bpf_ctx *hctx, unsigned char reportnum,
333              enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source)
334 {
335         __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */);
336         int ret;
337 
338         if (!data)
339                 return 0; /* EPERM check */
340 
341         /* check if the incoming request comes from our hidraw operation */
342         if (source == (__u64)current_file) {
343                 data[0] = reportnum;
344 
345                 ret = hid_bpf_hw_request(hctx, data, 2, rtype, reqtype);
346                 if (ret != 2)
347                         return -1;
348                 data[0] = reportnum + 1;
349                 data[1] = reportnum + 2;
350                 data[2] = reportnum + 3;
351                 return 3;
352         }
353 
354         return 0;
355 }
356 
357 SEC(".struct_ops.link")
358 struct hid_bpf_ops test_hidraw_raw_request = {
359         .hid_hw_request = (void *)hid_test_hidraw_raw_request,
360 };
361 
362 SEC("?struct_ops.s/hid_hw_request")
363 int BPF_PROG(hid_test_infinite_loop_raw_request, struct hid_bpf_ctx *hctx, unsigned char reportnum,
364              enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source)
365 {
366         __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */);
367         int ret;
368 
369         if (!data)
370                 return 0; /* EPERM check */
371 
372         /* always forward the request as-is to the device, hid-bpf should prevent
373          * infinite loops.
374          */
375         data[0] = reportnum;
376 
377         ret = hid_bpf_hw_request(hctx, data, 2, rtype, reqtype);
378         if (ret == 2)
379                 return 3;
380 
381         return 0;
382 }
383 
384 SEC(".struct_ops.link")
385 struct hid_bpf_ops test_infinite_loop_raw_request = {
386         .hid_hw_request = (void *)hid_test_infinite_loop_raw_request,
387 };
388 
389 SEC("?struct_ops/hid_hw_output_report")
390 int BPF_PROG(hid_test_filter_output_report, struct hid_bpf_ctx *hctx, unsigned char reportnum,
391              enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source)
392 {
393         return -25;
394 }
395 
396 SEC(".struct_ops.link")
397 struct hid_bpf_ops test_filter_output_report = {
398         .hid_hw_output_report = (void *)hid_test_filter_output_report,
399 };
400 
401 SEC("?struct_ops.s/hid_hw_output_report")
402 int BPF_PROG(hid_test_hidraw_output_report, struct hid_bpf_ctx *hctx, __u64 source)
403 {
404         __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */);
405         int ret;
406 
407         if (!data)
408                 return 0; /* EPERM check */
409 
410         /* check if the incoming request comes from our hidraw operation */
411         if (source == (__u64)current_file)
412                 return hid_bpf_hw_output_report(hctx, data, 2);
413 
414         return 0;
415 }
416 
417 SEC(".struct_ops.link")
418 struct hid_bpf_ops test_hidraw_output_report = {
419         .hid_hw_output_report = (void *)hid_test_hidraw_output_report,
420 };
421 
422 SEC("?struct_ops.s/hid_hw_output_report")
423 int BPF_PROG(hid_test_infinite_loop_output_report, struct hid_bpf_ctx *hctx, __u64 source)
424 {
425         __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */);
426         int ret;
427 
428         if (!data)
429                 return 0; /* EPERM check */
430 
431         /* always forward the request as-is to the device, hid-bpf should prevent
432          * infinite loops.
433          */
434 
435         ret = hid_bpf_hw_output_report(hctx, data, 2);
436         if (ret == 2)
437                 return 2;
438 
439         return 0;
440 }
441 
442 SEC(".struct_ops.link")
443 struct hid_bpf_ops test_infinite_loop_output_report = {
444         .hid_hw_output_report = (void *)hid_test_infinite_loop_output_report,
445 };
446 
447 struct elem {
448         struct bpf_wq work;
449 };
450 
451 struct {
452         __uint(type, BPF_MAP_TYPE_HASH);
453         __uint(max_entries, 1);
454         __type(key, int);
455         __type(value, struct elem);
456 } hmap SEC(".maps");
457 
458 static int wq_cb_sleepable(void *map, int *key, void *work)
459 {
460         __u8 buf[9] = {2, 3, 4, 5, 6, 7, 8, 9, 10};
461         struct hid_bpf_ctx *hid_ctx;
462 
463         hid_ctx = hid_bpf_allocate_context(*key);
464         if (!hid_ctx)
465                 return 0; /* EPERM check */
466 
467         hid_bpf_input_report(hid_ctx, HID_INPUT_REPORT, buf, sizeof(buf));
468 
469         hid_bpf_release_context(hid_ctx);
470 
471         return 0;
472 }
473 
474 static int test_inject_input_report_callback(int *key)
475 {
476         struct elem init = {}, *val;
477         struct bpf_wq *wq;
478 
479         if (bpf_map_update_elem(&hmap, key, &init, 0))
480                 return -1;
481 
482         val = bpf_map_lookup_elem(&hmap, key);
483         if (!val)
484                 return -2;
485 
486         wq = &val->work;
487         if (bpf_wq_init(wq, &hmap, 0) != 0)
488                 return -3;
489 
490         if (bpf_wq_set_callback(wq, wq_cb_sleepable, 0))
491                 return -4;
492 
493         if (bpf_wq_start(wq, 0))
494                 return -5;
495 
496         return 0;
497 }
498 
499 SEC("?struct_ops/hid_device_event")
500 int BPF_PROG(hid_test_multiply_events_wq, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
501 {
502         __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 9 /* size */);
503         int hid = hid_ctx->hid->id;
504         int ret;
505 
506         if (!data)
507                 return 0; /* EPERM check */
508 
509         if (data[0] != 1)
510                 return 0;
511 
512         ret = test_inject_input_report_callback(&hid);
513         if (ret)
514                 return ret;
515 
516         data[1] += 5;
517 
518         return 0;
519 }
520 
521 SEC(".struct_ops.link")
522 struct hid_bpf_ops test_multiply_events_wq = {
523         .hid_device_event = (void *)hid_test_multiply_events_wq,
524 };
525 
526 SEC("?struct_ops/hid_device_event")
527 int BPF_PROG(hid_test_multiply_events, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
528 {
529         __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 9 /* size */);
530         __u8 buf[9];
531         int ret;
532 
533         if (!data)
534                 return 0; /* EPERM check */
535 
536         if (data[0] != 1)
537                 return 0;
538 
539         /*
540          * we have to use an intermediate buffer as hid_bpf_input_report
541          * will memset data to \0
542          */
543         __builtin_memcpy(buf, data, sizeof(buf));
544 
545         buf[0] = 2;
546         buf[1] += 5;
547         ret = hid_bpf_try_input_report(hid_ctx, HID_INPUT_REPORT, buf, sizeof(buf));
548         if (ret < 0)
549                 return ret;
550 
551         /*
552          * In real world we should reset the original buffer as data might be garbage now,
553          * but it actually now has the content of 'buf'
554          */
555         data[1] += 5;
556 
557         return 9;
558 }
559 
560 SEC(".struct_ops.link")
561 struct hid_bpf_ops test_multiply_events = {
562         .hid_device_event = (void *)hid_test_multiply_events,
563 };
564 
565 SEC("?struct_ops/hid_device_event")
566 int BPF_PROG(hid_test_infinite_loop_input_report, struct hid_bpf_ctx *hctx,
567              enum hid_report_type report_type, __u64 source)
568 {
569         __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 6 /* size */);
570         __u8 buf[6];
571 
572         if (!data)
573                 return 0; /* EPERM check */
574 
575         /*
576          * we have to use an intermediate buffer as hid_bpf_input_report
577          * will memset data to \0
578          */
579         __builtin_memcpy(buf, data, sizeof(buf));
580 
581         /* always forward the request as-is to the device, hid-bpf should prevent
582          * infinite loops.
583          * the return value is ignored so the event is passing to userspace.
584          */
585 
586         hid_bpf_try_input_report(hctx, report_type, buf, sizeof(buf));
587 
588         /* each time we process the event, we increment by one data[1]:
589          * after each successful call to hid_bpf_try_input_report, buf
590          * has been memcopied into data by the kernel.
591          */
592         data[1] += 1;
593 
594         return 0;
595 }
596 
597 SEC(".struct_ops.link")
598 struct hid_bpf_ops test_infinite_loop_input_report = {
599         .hid_device_event = (void *)hid_test_infinite_loop_input_report,
600 };
601 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php