Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : // bpf-lirc.c - handles bpf
3 : : //
4 : : // Copyright (C) 2018 Sean Young <sean@mess.org>
5 : :
6 : : #include <linux/bpf.h>
7 : : #include <linux/filter.h>
8 : : #include <linux/bpf_lirc.h>
9 : : #include "rc-core-priv.h"
10 : :
11 : : #define lirc_rcu_dereference(p) \
12 : : rcu_dereference_protected(p, lockdep_is_held(&ir_raw_handler_lock))
13 : :
14 : : /*
15 : : * BPF interface for raw IR
16 : : */
17 : : const struct bpf_prog_ops lirc_mode2_prog_ops = {
18 : : };
19 : :
20 : 0 : BPF_CALL_1(bpf_rc_repeat, u32*, sample)
21 : : {
22 : : struct ir_raw_event_ctrl *ctrl;
23 : :
24 : : ctrl = container_of(sample, struct ir_raw_event_ctrl, bpf_sample);
25 : :
26 : 0 : rc_repeat(ctrl->dev);
27 : :
28 : : return 0;
29 : : }
30 : :
31 : : static const struct bpf_func_proto rc_repeat_proto = {
32 : : .func = bpf_rc_repeat,
33 : : .gpl_only = true, /* rc_repeat is EXPORT_SYMBOL_GPL */
34 : : .ret_type = RET_INTEGER,
35 : : .arg1_type = ARG_PTR_TO_CTX,
36 : : };
37 : :
38 : : /*
39 : : * Currently rc-core does not support 64-bit scancodes, but there are many
40 : : * known protocols with more than 32 bits. So, define the interface as u64
41 : : * as a future-proof.
42 : : */
43 : 0 : BPF_CALL_4(bpf_rc_keydown, u32*, sample, u32, protocol, u64, scancode,
44 : : u32, toggle)
45 : : {
46 : : struct ir_raw_event_ctrl *ctrl;
47 : :
48 : : ctrl = container_of(sample, struct ir_raw_event_ctrl, bpf_sample);
49 : :
50 : 0 : rc_keydown(ctrl->dev, protocol, scancode, toggle != 0);
51 : :
52 : : return 0;
53 : : }
54 : :
55 : : static const struct bpf_func_proto rc_keydown_proto = {
56 : : .func = bpf_rc_keydown,
57 : : .gpl_only = true, /* rc_keydown is EXPORT_SYMBOL_GPL */
58 : : .ret_type = RET_INTEGER,
59 : : .arg1_type = ARG_PTR_TO_CTX,
60 : : .arg2_type = ARG_ANYTHING,
61 : : .arg3_type = ARG_ANYTHING,
62 : : .arg4_type = ARG_ANYTHING,
63 : : };
64 : :
65 : 0 : BPF_CALL_3(bpf_rc_pointer_rel, u32*, sample, s32, rel_x, s32, rel_y)
66 : : {
67 : : struct ir_raw_event_ctrl *ctrl;
68 : :
69 : : ctrl = container_of(sample, struct ir_raw_event_ctrl, bpf_sample);
70 : :
71 : 0 : input_report_rel(ctrl->dev->input_dev, REL_X, rel_x);
72 : 0 : input_report_rel(ctrl->dev->input_dev, REL_Y, rel_y);
73 : 0 : input_sync(ctrl->dev->input_dev);
74 : :
75 : : return 0;
76 : : }
77 : :
78 : : static const struct bpf_func_proto rc_pointer_rel_proto = {
79 : : .func = bpf_rc_pointer_rel,
80 : : .gpl_only = true,
81 : : .ret_type = RET_INTEGER,
82 : : .arg1_type = ARG_PTR_TO_CTX,
83 : : .arg2_type = ARG_ANYTHING,
84 : : .arg3_type = ARG_ANYTHING,
85 : : };
86 : :
87 : : static const struct bpf_func_proto *
88 : 0 : lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
89 : : {
90 [ # # # # : 0 : switch (func_id) {
# # # # #
# # # #
# ]
91 : : case BPF_FUNC_rc_repeat:
92 : : return &rc_repeat_proto;
93 : : case BPF_FUNC_rc_keydown:
94 : 0 : return &rc_keydown_proto;
95 : : case BPF_FUNC_rc_pointer_rel:
96 : 0 : return &rc_pointer_rel_proto;
97 : : case BPF_FUNC_map_lookup_elem:
98 : 0 : return &bpf_map_lookup_elem_proto;
99 : : case BPF_FUNC_map_update_elem:
100 : 0 : return &bpf_map_update_elem_proto;
101 : : case BPF_FUNC_map_delete_elem:
102 : 0 : return &bpf_map_delete_elem_proto;
103 : : case BPF_FUNC_map_push_elem:
104 : 0 : return &bpf_map_push_elem_proto;
105 : : case BPF_FUNC_map_pop_elem:
106 : 0 : return &bpf_map_pop_elem_proto;
107 : : case BPF_FUNC_map_peek_elem:
108 : 0 : return &bpf_map_peek_elem_proto;
109 : : case BPF_FUNC_ktime_get_ns:
110 : 0 : return &bpf_ktime_get_ns_proto;
111 : : case BPF_FUNC_tail_call:
112 : 0 : return &bpf_tail_call_proto;
113 : : case BPF_FUNC_get_prandom_u32:
114 : 0 : return &bpf_get_prandom_u32_proto;
115 : : case BPF_FUNC_trace_printk:
116 [ # # ]: 0 : if (capable(CAP_SYS_ADMIN))
117 : 0 : return bpf_get_trace_printk_proto();
118 : : /* fall through */
119 : : default:
120 : : return NULL;
121 : : }
122 : : }
123 : :
124 : 0 : static bool lirc_mode2_is_valid_access(int off, int size,
125 : : enum bpf_access_type type,
126 : : const struct bpf_prog *prog,
127 : : struct bpf_insn_access_aux *info)
128 : : {
129 : : /* We have one field of u32 */
130 [ # # # # ]: 0 : return type == BPF_READ && off == 0 && size == sizeof(u32);
131 : : }
132 : :
133 : : const struct bpf_verifier_ops lirc_mode2_verifier_ops = {
134 : : .get_func_proto = lirc_mode2_func_proto,
135 : : .is_valid_access = lirc_mode2_is_valid_access
136 : : };
137 : :
138 : : #define BPF_MAX_PROGS 64
139 : :
140 : 0 : static int lirc_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog)
141 : : {
142 : : struct bpf_prog_array *old_array;
143 : : struct bpf_prog_array *new_array;
144 : : struct ir_raw_event_ctrl *raw;
145 : : int ret;
146 : :
147 [ # # ]: 0 : if (rcdev->driver_type != RC_DRIVER_IR_RAW)
148 : : return -EINVAL;
149 : :
150 : 0 : ret = mutex_lock_interruptible(&ir_raw_handler_lock);
151 [ # # ]: 0 : if (ret)
152 : : return ret;
153 : :
154 : 0 : raw = rcdev->raw;
155 [ # # ]: 0 : if (!raw) {
156 : : ret = -ENODEV;
157 : : goto unlock;
158 : : }
159 : :
160 : 0 : old_array = lirc_rcu_dereference(raw->progs);
161 [ # # # # ]: 0 : if (old_array && bpf_prog_array_length(old_array) >= BPF_MAX_PROGS) {
162 : : ret = -E2BIG;
163 : : goto unlock;
164 : : }
165 : :
166 : 0 : ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array);
167 [ # # ]: 0 : if (ret < 0)
168 : : goto unlock;
169 : :
170 : 0 : rcu_assign_pointer(raw->progs, new_array);
171 : 0 : bpf_prog_array_free(old_array);
172 : :
173 : : unlock:
174 : 0 : mutex_unlock(&ir_raw_handler_lock);
175 : 0 : return ret;
176 : : }
177 : :
178 : 0 : static int lirc_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog)
179 : : {
180 : : struct bpf_prog_array *old_array;
181 : : struct bpf_prog_array *new_array;
182 : : struct ir_raw_event_ctrl *raw;
183 : : int ret;
184 : :
185 [ # # ]: 0 : if (rcdev->driver_type != RC_DRIVER_IR_RAW)
186 : : return -EINVAL;
187 : :
188 : 0 : ret = mutex_lock_interruptible(&ir_raw_handler_lock);
189 [ # # ]: 0 : if (ret)
190 : : return ret;
191 : :
192 : 0 : raw = rcdev->raw;
193 [ # # ]: 0 : if (!raw) {
194 : : ret = -ENODEV;
195 : : goto unlock;
196 : : }
197 : :
198 : 0 : old_array = lirc_rcu_dereference(raw->progs);
199 : 0 : ret = bpf_prog_array_copy(old_array, prog, NULL, &new_array);
200 : : /*
201 : : * Do not use bpf_prog_array_delete_safe() as we would end up
202 : : * with a dummy entry in the array, and the we would free the
203 : : * dummy in lirc_bpf_free()
204 : : */
205 [ # # ]: 0 : if (ret)
206 : : goto unlock;
207 : :
208 : 0 : rcu_assign_pointer(raw->progs, new_array);
209 : 0 : bpf_prog_array_free(old_array);
210 : 0 : bpf_prog_put(prog);
211 : : unlock:
212 : 0 : mutex_unlock(&ir_raw_handler_lock);
213 : 0 : return ret;
214 : : }
215 : :
216 : 0 : void lirc_bpf_run(struct rc_dev *rcdev, u32 sample)
217 : : {
218 : 0 : struct ir_raw_event_ctrl *raw = rcdev->raw;
219 : :
220 : 0 : raw->bpf_sample = sample;
221 : :
222 [ # # ]: 0 : if (raw->progs)
223 [ # # # # ]: 0 : BPF_PROG_RUN_ARRAY(raw->progs, &raw->bpf_sample, BPF_PROG_RUN);
224 : 0 : }
225 : :
226 : : /*
227 : : * This should be called once the rc thread has been stopped, so there can be
228 : : * no concurrent bpf execution.
229 : : *
230 : : * Should be called with the ir_raw_handler_lock held.
231 : : */
232 : 0 : void lirc_bpf_free(struct rc_dev *rcdev)
233 : : {
234 : : struct bpf_prog_array_item *item;
235 : : struct bpf_prog_array *array;
236 : :
237 : 0 : array = lirc_rcu_dereference(rcdev->raw->progs);
238 [ # # ]: 0 : if (!array)
239 : 0 : return;
240 : :
241 [ # # ]: 0 : for (item = array->items; item->prog; item++)
242 : 0 : bpf_prog_put(item->prog);
243 : :
244 : 0 : bpf_prog_array_free(array);
245 : : }
246 : :
247 : 0 : int lirc_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
248 : : {
249 : : struct rc_dev *rcdev;
250 : : int ret;
251 : :
252 [ # # ]: 0 : if (attr->attach_flags)
253 : : return -EINVAL;
254 : :
255 : 0 : rcdev = rc_dev_get_from_fd(attr->target_fd);
256 [ # # ]: 0 : if (IS_ERR(rcdev))
257 : 0 : return PTR_ERR(rcdev);
258 : :
259 : 0 : ret = lirc_bpf_attach(rcdev, prog);
260 : :
261 : 0 : put_device(&rcdev->dev);
262 : :
263 : 0 : return ret;
264 : : }
265 : :
266 : 0 : int lirc_prog_detach(const union bpf_attr *attr)
267 : : {
268 : : struct bpf_prog *prog;
269 : : struct rc_dev *rcdev;
270 : : int ret;
271 : :
272 [ # # ]: 0 : if (attr->attach_flags)
273 : : return -EINVAL;
274 : :
275 : 0 : prog = bpf_prog_get_type(attr->attach_bpf_fd,
276 : : BPF_PROG_TYPE_LIRC_MODE2);
277 [ # # ]: 0 : if (IS_ERR(prog))
278 : 0 : return PTR_ERR(prog);
279 : :
280 : 0 : rcdev = rc_dev_get_from_fd(attr->target_fd);
281 [ # # ]: 0 : if (IS_ERR(rcdev)) {
282 : 0 : bpf_prog_put(prog);
283 : 0 : return PTR_ERR(rcdev);
284 : : }
285 : :
286 : 0 : ret = lirc_bpf_detach(rcdev, prog);
287 : :
288 : 0 : bpf_prog_put(prog);
289 : 0 : put_device(&rcdev->dev);
290 : :
291 : 0 : return ret;
292 : : }
293 : :
294 : 0 : int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
295 : : {
296 : 0 : __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
297 : : struct bpf_prog_array *progs;
298 : : struct rc_dev *rcdev;
299 : 0 : u32 cnt, flags = 0;
300 : : int ret;
301 : :
302 [ # # ]: 0 : if (attr->query.query_flags)
303 : : return -EINVAL;
304 : :
305 : 0 : rcdev = rc_dev_get_from_fd(attr->query.target_fd);
306 [ # # ]: 0 : if (IS_ERR(rcdev))
307 : 0 : return PTR_ERR(rcdev);
308 : :
309 [ # # ]: 0 : if (rcdev->driver_type != RC_DRIVER_IR_RAW) {
310 : : ret = -EINVAL;
311 : : goto put;
312 : : }
313 : :
314 : 0 : ret = mutex_lock_interruptible(&ir_raw_handler_lock);
315 [ # # ]: 0 : if (ret)
316 : : goto put;
317 : :
318 : 0 : progs = lirc_rcu_dereference(rcdev->raw->progs);
319 [ # # ]: 0 : cnt = progs ? bpf_prog_array_length(progs) : 0;
320 : :
321 [ # # ]: 0 : if (copy_to_user(&uattr->query.prog_cnt, &cnt, sizeof(cnt))) {
322 : : ret = -EFAULT;
323 : : goto unlock;
324 : : }
325 : :
326 [ # # ]: 0 : if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags))) {
327 : : ret = -EFAULT;
328 : : goto unlock;
329 : : }
330 : :
331 [ # # # # : 0 : if (attr->query.prog_cnt != 0 && prog_ids && cnt)
# # ]
332 : 0 : ret = bpf_prog_array_copy_to_user(progs, prog_ids, cnt);
333 : :
334 : : unlock:
335 : 0 : mutex_unlock(&ir_raw_handler_lock);
336 : : put:
337 : 0 : put_device(&rcdev->dev);
338 : :
339 : 0 : return ret;
340 : : }
|