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