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("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_first_event,struct hid_bpf_ctx * hid_ctx)18 int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx)
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("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_second_event,struct hid_bpf_ctx * hid_ctx)33 int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx)
34 {
35 __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
36
37 if (!rw_data)
38 return 0; /* EPERM check */
39
40 rw_data[3] = rw_data[2] + 5;
41
42 return hid_ctx->size;
43 }
44
45 SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_change_report_id,struct hid_bpf_ctx * hid_ctx)46 int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx)
47 {
48 __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
49
50 if (!rw_data)
51 return 0; /* EPERM check */
52
53 rw_data[0] = 2;
54
55 return 9;
56 }
57
58 SEC("syscall")
attach_prog(struct attach_prog_args * ctx)59 int attach_prog(struct attach_prog_args *ctx)
60 {
61 ctx->retval = hid_bpf_attach_prog(ctx->hid,
62 ctx->prog_fd,
63 ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD :
64 HID_BPF_FLAG_NONE);
65 return 0;
66 }
67
68 struct hid_hw_request_syscall_args {
69 /* data needs to come at offset 0 so we can use it in calls */
70 __u8 data[10];
71 unsigned int hid;
72 int retval;
73 size_t size;
74 enum hid_report_type type;
75 __u8 request_type;
76 };
77
78 SEC("syscall")
hid_user_raw_request(struct hid_hw_request_syscall_args * args)79 int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
80 {
81 struct hid_bpf_ctx *ctx;
82 const size_t size = args->size;
83 int i, ret = 0;
84
85 if (size > sizeof(args->data))
86 return -7; /* -E2BIG */
87
88 ctx = hid_bpf_allocate_context(args->hid);
89 if (!ctx)
90 return -1; /* EPERM check */
91
92 ret = hid_bpf_hw_request(ctx,
93 args->data,
94 size,
95 args->type,
96 args->request_type);
97 args->retval = ret;
98
99 hid_bpf_release_context(ctx);
100
101 return 0;
102 }
103
104 static const __u8 rdesc[] = {
105 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
106 0x09, 0x32, /* USAGE (Z) */
107 0x95, 0x01, /* REPORT_COUNT (1) */
108 0x81, 0x06, /* INPUT (Data,Var,Rel) */
109
110 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
111 0x19, 0x01, /* USAGE_MINIMUM (1) */
112 0x29, 0x03, /* USAGE_MAXIMUM (3) */
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 0x91, 0x02, /* Output (Data,Var,Abs) */
118 0x95, 0x01, /* REPORT_COUNT (1) */
119 0x75, 0x05, /* REPORT_SIZE (5) */
120 0x91, 0x01, /* Output (Cnst,Var,Abs) */
121
122 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
123 0x19, 0x06, /* USAGE_MINIMUM (6) */
124 0x29, 0x08, /* USAGE_MAXIMUM (8) */
125 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
126 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
127 0x95, 0x03, /* REPORT_COUNT (3) */
128 0x75, 0x01, /* REPORT_SIZE (1) */
129 0xb1, 0x02, /* Feature (Data,Var,Abs) */
130 0x95, 0x01, /* REPORT_COUNT (1) */
131 0x75, 0x05, /* REPORT_SIZE (5) */
132 0x91, 0x01, /* Output (Cnst,Var,Abs) */
133
134 0xc0, /* END_COLLECTION */
135 0xc0, /* END_COLLECTION */
136 };
137
138 SEC("?fmod_ret/hid_bpf_rdesc_fixup")
BPF_PROG(hid_rdesc_fixup,struct hid_bpf_ctx * hid_ctx)139 int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
140 {
141 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */);
142
143 if (!data)
144 return 0; /* EPERM check */
145
146 callback2_check = data[4];
147
148 /* insert rdesc at offset 73 */
149 __builtin_memcpy(&data[73], rdesc, sizeof(rdesc));
150
151 /* Change Usage Vendor globally */
152 data[4] = 0x42;
153
154 return sizeof(rdesc) + 73;
155 }
156
157 SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_test_insert1,struct hid_bpf_ctx * hid_ctx)158 int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx)
159 {
160 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
161
162 if (!data)
163 return 0; /* EPERM check */
164
165 /* we need to be run first */
166 if (data[2] || data[3])
167 return -1;
168
169 data[1] = 1;
170
171 return 0;
172 }
173
174 SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_test_insert2,struct hid_bpf_ctx * hid_ctx)175 int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx)
176 {
177 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
178
179 if (!data)
180 return 0; /* EPERM check */
181
182 /* after insert0 and before insert2 */
183 if (!data[1] || data[3])
184 return -1;
185
186 data[2] = 2;
187
188 return 0;
189 }
190
191 SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_test_insert3,struct hid_bpf_ctx * hid_ctx)192 int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
193 {
194 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
195
196 if (!data)
197 return 0; /* EPERM check */
198
199 /* at the end */
200 if (!data[1] || !data[2])
201 return -1;
202
203 data[3] = 3;
204
205 return 0;
206 }
207