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