1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Red hat */
3 #include "vmlinux.h"
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_tracing.h>
6 #include "hid_bpf_helpers.h"
7 
8 char _license[] SEC("license") = "GPL";
9 
10 struct attach_prog_args {
11 	int prog_fd;
12 	unsigned int hid;
13 	int retval;
14 };
15 
16 __u64 callback_check = 52;
17 __u64 callback2_check = 52;
18 
19 SEC("?fmod_ret/hid_bpf_device_event")
20 int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx)
21 {
22 	__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
23 
24 	if (!rw_data)
25 		return 0; /* EPERM check */
26 
27 	callback_check = rw_data[1];
28 
29 	rw_data[2] = rw_data[1] + 5;
30 
31 	return hid_ctx->size;
32 }
33 
34 SEC("?fmod_ret/hid_bpf_device_event")
35 int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx)
36 {
37 	__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
38 
39 	if (!rw_data)
40 		return 0; /* EPERM check */
41 
42 	rw_data[0] = 2;
43 
44 	return 9;
45 }
46 
47 SEC("syscall")
48 int attach_prog(struct attach_prog_args *ctx)
49 {
50 	ctx->retval = hid_bpf_attach_prog(ctx->hid,
51 					  ctx->prog_fd,
52 					  0);
53 	return 0;
54 }
55 
56 struct hid_hw_request_syscall_args {
57 	/* data needs to come at offset 0 so we can use it in calls */
58 	__u8 data[10];
59 	unsigned int hid;
60 	int retval;
61 	size_t size;
62 	enum hid_report_type type;
63 	__u8 request_type;
64 };
65 
66 SEC("syscall")
67 int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
68 {
69 	struct hid_bpf_ctx *ctx;
70 	const size_t size = args->size;
71 	int i, ret = 0;
72 
73 	if (size > sizeof(args->data))
74 		return -7; /* -E2BIG */
75 
76 	ctx = hid_bpf_allocate_context(args->hid);
77 	if (!ctx)
78 		return -1; /* EPERM check */
79 
80 	ret = hid_bpf_hw_request(ctx,
81 				 args->data,
82 				 size,
83 				 args->type,
84 				 args->request_type);
85 	args->retval = ret;
86 
87 	hid_bpf_release_context(ctx);
88 
89 	return 0;
90 }
91 
92 static const __u8 rdesc[] = {
93 	0x05, 0x01,				/* USAGE_PAGE (Generic Desktop) */
94 	0x09, 0x32,				/* USAGE (Z) */
95 	0x95, 0x01,				/* REPORT_COUNT (1) */
96 	0x81, 0x06,				/* INPUT (Data,Var,Rel) */
97 
98 	0x06, 0x00, 0xff,			/* Usage Page (Vendor Defined Page 1) */
99 	0x19, 0x01,				/* USAGE_MINIMUM (1) */
100 	0x29, 0x03,				/* USAGE_MAXIMUM (3) */
101 	0x15, 0x00,				/* LOGICAL_MINIMUM (0) */
102 	0x25, 0x01,				/* LOGICAL_MAXIMUM (1) */
103 	0x95, 0x03,				/* REPORT_COUNT (3) */
104 	0x75, 0x01,				/* REPORT_SIZE (1) */
105 	0x91, 0x02,				/* Output (Data,Var,Abs) */
106 	0x95, 0x01,				/* REPORT_COUNT (1) */
107 	0x75, 0x05,				/* REPORT_SIZE (5) */
108 	0x91, 0x01,				/* Output (Cnst,Var,Abs) */
109 
110 	0x06, 0x00, 0xff,			/* Usage Page (Vendor Defined Page 1) */
111 	0x19, 0x06,				/* USAGE_MINIMUM (6) */
112 	0x29, 0x08,				/* USAGE_MAXIMUM (8) */
113 	0x15, 0x00,				/* LOGICAL_MINIMUM (0) */
114 	0x25, 0x01,				/* LOGICAL_MAXIMUM (1) */
115 	0x95, 0x03,				/* REPORT_COUNT (3) */
116 	0x75, 0x01,				/* REPORT_SIZE (1) */
117 	0xb1, 0x02,				/* Feature (Data,Var,Abs) */
118 	0x95, 0x01,				/* REPORT_COUNT (1) */
119 	0x75, 0x05,				/* REPORT_SIZE (5) */
120 	0x91, 0x01,				/* Output (Cnst,Var,Abs) */
121 
122 	0xc0,				/* END_COLLECTION */
123 	0xc0,			/* END_COLLECTION */
124 };
125 
126 SEC("?fmod_ret/hid_bpf_rdesc_fixup")
127 int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
128 {
129 	__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */);
130 
131 	if (!data)
132 		return 0; /* EPERM check */
133 
134 	callback2_check = data[4];
135 
136 	/* insert rdesc at offset 73 */
137 	__builtin_memcpy(&data[73], rdesc, sizeof(rdesc));
138 
139 	/* Change Usage Vendor globally */
140 	data[4] = 0x42;
141 
142 	return sizeof(rdesc) + 73;
143 }
144