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 62f4364dcfSSean Young static const struct bpf_func_proto * 63f4364dcfSSean Young lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 64f4364dcfSSean Young { 65f4364dcfSSean Young switch (func_id) { 66f4364dcfSSean Young case BPF_FUNC_rc_repeat: 67f4364dcfSSean Young return &rc_repeat_proto; 68f4364dcfSSean Young case BPF_FUNC_rc_keydown: 69f4364dcfSSean Young return &rc_keydown_proto; 70f4364dcfSSean Young case BPF_FUNC_map_lookup_elem: 71f4364dcfSSean Young return &bpf_map_lookup_elem_proto; 72f4364dcfSSean Young case BPF_FUNC_map_update_elem: 73f4364dcfSSean Young return &bpf_map_update_elem_proto; 74f4364dcfSSean Young case BPF_FUNC_map_delete_elem: 75f4364dcfSSean Young return &bpf_map_delete_elem_proto; 76f4364dcfSSean Young case BPF_FUNC_ktime_get_ns: 77f4364dcfSSean Young return &bpf_ktime_get_ns_proto; 78f4364dcfSSean Young case BPF_FUNC_tail_call: 79f4364dcfSSean Young return &bpf_tail_call_proto; 80f4364dcfSSean Young case BPF_FUNC_get_prandom_u32: 81f4364dcfSSean Young return &bpf_get_prandom_u32_proto; 82f4364dcfSSean Young case BPF_FUNC_trace_printk: 83f4364dcfSSean Young if (capable(CAP_SYS_ADMIN)) 84f4364dcfSSean Young return bpf_get_trace_printk_proto(); 85f4364dcfSSean Young /* fall through */ 86f4364dcfSSean Young default: 87f4364dcfSSean Young return NULL; 88f4364dcfSSean Young } 89f4364dcfSSean Young } 90f4364dcfSSean Young 91f4364dcfSSean Young static bool lirc_mode2_is_valid_access(int off, int size, 92f4364dcfSSean Young enum bpf_access_type type, 93f4364dcfSSean Young const struct bpf_prog *prog, 94f4364dcfSSean Young struct bpf_insn_access_aux *info) 95f4364dcfSSean Young { 96f4364dcfSSean Young /* We have one field of u32 */ 97f4364dcfSSean Young return type == BPF_READ && off == 0 && size == sizeof(u32); 98f4364dcfSSean Young } 99f4364dcfSSean Young 100f4364dcfSSean Young const struct bpf_verifier_ops lirc_mode2_verifier_ops = { 101f4364dcfSSean Young .get_func_proto = lirc_mode2_func_proto, 102f4364dcfSSean Young .is_valid_access = lirc_mode2_is_valid_access 103f4364dcfSSean Young }; 104f4364dcfSSean Young 105f4364dcfSSean Young #define BPF_MAX_PROGS 64 106f4364dcfSSean Young 107f4364dcfSSean Young static int lirc_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog) 108f4364dcfSSean Young { 109f4364dcfSSean Young struct bpf_prog_array __rcu *old_array; 110f4364dcfSSean Young struct bpf_prog_array *new_array; 111f4364dcfSSean Young struct ir_raw_event_ctrl *raw; 112f4364dcfSSean Young int ret; 113f4364dcfSSean Young 114f4364dcfSSean Young if (rcdev->driver_type != RC_DRIVER_IR_RAW) 115f4364dcfSSean Young return -EINVAL; 116f4364dcfSSean Young 117f4364dcfSSean Young ret = mutex_lock_interruptible(&ir_raw_handler_lock); 118f4364dcfSSean Young if (ret) 119f4364dcfSSean Young return ret; 120f4364dcfSSean Young 121f4364dcfSSean Young raw = rcdev->raw; 122f4364dcfSSean Young if (!raw) { 123f4364dcfSSean Young ret = -ENODEV; 124f4364dcfSSean Young goto unlock; 125f4364dcfSSean Young } 126f4364dcfSSean Young 127f4364dcfSSean Young if (raw->progs && bpf_prog_array_length(raw->progs) >= BPF_MAX_PROGS) { 128f4364dcfSSean Young ret = -E2BIG; 129f4364dcfSSean Young goto unlock; 130f4364dcfSSean Young } 131f4364dcfSSean Young 132f4364dcfSSean Young old_array = raw->progs; 133f4364dcfSSean Young ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array); 134f4364dcfSSean Young if (ret < 0) 135f4364dcfSSean Young goto unlock; 136f4364dcfSSean Young 137f4364dcfSSean Young rcu_assign_pointer(raw->progs, new_array); 138f4364dcfSSean Young bpf_prog_array_free(old_array); 139f4364dcfSSean Young 140f4364dcfSSean Young unlock: 141f4364dcfSSean Young mutex_unlock(&ir_raw_handler_lock); 142f4364dcfSSean Young return ret; 143f4364dcfSSean Young } 144f4364dcfSSean Young 145f4364dcfSSean Young static int lirc_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog) 146f4364dcfSSean Young { 147f4364dcfSSean Young struct bpf_prog_array __rcu *old_array; 148f4364dcfSSean Young struct bpf_prog_array *new_array; 149f4364dcfSSean Young struct ir_raw_event_ctrl *raw; 150f4364dcfSSean Young int ret; 151f4364dcfSSean Young 152f4364dcfSSean Young if (rcdev->driver_type != RC_DRIVER_IR_RAW) 153f4364dcfSSean Young return -EINVAL; 154f4364dcfSSean Young 155f4364dcfSSean Young ret = mutex_lock_interruptible(&ir_raw_handler_lock); 156f4364dcfSSean Young if (ret) 157f4364dcfSSean Young return ret; 158f4364dcfSSean Young 159f4364dcfSSean Young raw = rcdev->raw; 160f4364dcfSSean Young if (!raw) { 161f4364dcfSSean Young ret = -ENODEV; 162f4364dcfSSean Young goto unlock; 163f4364dcfSSean Young } 164f4364dcfSSean Young 165f4364dcfSSean Young old_array = raw->progs; 166f4364dcfSSean Young ret = bpf_prog_array_copy(old_array, prog, NULL, &new_array); 167f4364dcfSSean Young /* 168f4364dcfSSean Young * Do not use bpf_prog_array_delete_safe() as we would end up 169f4364dcfSSean Young * with a dummy entry in the array, and the we would free the 170f4364dcfSSean Young * dummy in lirc_bpf_free() 171f4364dcfSSean Young */ 172f4364dcfSSean Young if (ret) 173f4364dcfSSean Young goto unlock; 174f4364dcfSSean Young 175f4364dcfSSean Young rcu_assign_pointer(raw->progs, new_array); 176f4364dcfSSean Young bpf_prog_array_free(old_array); 17792cab799SSean Young bpf_prog_put(prog); 178f4364dcfSSean Young unlock: 179f4364dcfSSean Young mutex_unlock(&ir_raw_handler_lock); 180f4364dcfSSean Young return ret; 181f4364dcfSSean Young } 182f4364dcfSSean Young 183f4364dcfSSean Young void lirc_bpf_run(struct rc_dev *rcdev, u32 sample) 184f4364dcfSSean Young { 185f4364dcfSSean Young struct ir_raw_event_ctrl *raw = rcdev->raw; 186f4364dcfSSean Young 187f4364dcfSSean Young raw->bpf_sample = sample; 188f4364dcfSSean Young 189f4364dcfSSean Young if (raw->progs) 190f4364dcfSSean Young BPF_PROG_RUN_ARRAY(raw->progs, &raw->bpf_sample, BPF_PROG_RUN); 191f4364dcfSSean Young } 192f4364dcfSSean Young 193f4364dcfSSean Young /* 194f4364dcfSSean Young * This should be called once the rc thread has been stopped, so there can be 195f4364dcfSSean Young * no concurrent bpf execution. 196f4364dcfSSean Young */ 197f4364dcfSSean Young void lirc_bpf_free(struct rc_dev *rcdev) 198f4364dcfSSean Young { 199f4364dcfSSean Young struct bpf_prog **progs; 200f4364dcfSSean Young 201f4364dcfSSean Young if (!rcdev->raw->progs) 202f4364dcfSSean Young return; 203f4364dcfSSean Young 204f4364dcfSSean Young progs = rcu_dereference(rcdev->raw->progs)->progs; 205f4364dcfSSean Young while (*progs) 206f4364dcfSSean Young bpf_prog_put(*progs++); 207f4364dcfSSean Young 208f4364dcfSSean Young bpf_prog_array_free(rcdev->raw->progs); 209f4364dcfSSean Young } 210f4364dcfSSean Young 211f4364dcfSSean Young int lirc_prog_attach(const union bpf_attr *attr) 212f4364dcfSSean Young { 213f4364dcfSSean Young struct bpf_prog *prog; 214f4364dcfSSean Young struct rc_dev *rcdev; 215f4364dcfSSean Young int ret; 216f4364dcfSSean Young 217f4364dcfSSean Young if (attr->attach_flags) 218f4364dcfSSean Young return -EINVAL; 219f4364dcfSSean Young 220f4364dcfSSean Young prog = bpf_prog_get_type(attr->attach_bpf_fd, 221f4364dcfSSean Young BPF_PROG_TYPE_LIRC_MODE2); 222f4364dcfSSean Young if (IS_ERR(prog)) 223f4364dcfSSean Young return PTR_ERR(prog); 224f4364dcfSSean Young 225f4364dcfSSean Young rcdev = rc_dev_get_from_fd(attr->target_fd); 226f4364dcfSSean Young if (IS_ERR(rcdev)) { 227f4364dcfSSean Young bpf_prog_put(prog); 228f4364dcfSSean Young return PTR_ERR(rcdev); 229f4364dcfSSean Young } 230f4364dcfSSean Young 231f4364dcfSSean Young ret = lirc_bpf_attach(rcdev, prog); 232f4364dcfSSean Young if (ret) 233f4364dcfSSean Young bpf_prog_put(prog); 234f4364dcfSSean Young 235f4364dcfSSean Young put_device(&rcdev->dev); 236f4364dcfSSean Young 237f4364dcfSSean Young return ret; 238f4364dcfSSean Young } 239f4364dcfSSean Young 240f4364dcfSSean Young int lirc_prog_detach(const union bpf_attr *attr) 241f4364dcfSSean Young { 242f4364dcfSSean Young struct bpf_prog *prog; 243f4364dcfSSean Young struct rc_dev *rcdev; 244f4364dcfSSean Young int ret; 245f4364dcfSSean Young 246f4364dcfSSean Young if (attr->attach_flags) 247f4364dcfSSean Young return -EINVAL; 248f4364dcfSSean Young 249f4364dcfSSean Young prog = bpf_prog_get_type(attr->attach_bpf_fd, 250f4364dcfSSean Young BPF_PROG_TYPE_LIRC_MODE2); 251f4364dcfSSean Young if (IS_ERR(prog)) 252f4364dcfSSean Young return PTR_ERR(prog); 253f4364dcfSSean Young 254f4364dcfSSean Young rcdev = rc_dev_get_from_fd(attr->target_fd); 255f4364dcfSSean Young if (IS_ERR(rcdev)) { 256f4364dcfSSean Young bpf_prog_put(prog); 257f4364dcfSSean Young return PTR_ERR(rcdev); 258f4364dcfSSean Young } 259f4364dcfSSean Young 260f4364dcfSSean Young ret = lirc_bpf_detach(rcdev, prog); 261f4364dcfSSean Young 262f4364dcfSSean Young bpf_prog_put(prog); 263f4364dcfSSean Young put_device(&rcdev->dev); 264f4364dcfSSean Young 265f4364dcfSSean Young return ret; 266f4364dcfSSean Young } 267f4364dcfSSean Young 268f4364dcfSSean Young int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) 269f4364dcfSSean Young { 270f4364dcfSSean Young __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids); 271f4364dcfSSean Young struct bpf_prog_array __rcu *progs; 272f4364dcfSSean Young struct rc_dev *rcdev; 273f4364dcfSSean Young u32 cnt, flags = 0; 274f4364dcfSSean Young int ret; 275f4364dcfSSean Young 276f4364dcfSSean Young if (attr->query.query_flags) 277f4364dcfSSean Young return -EINVAL; 278f4364dcfSSean Young 279f4364dcfSSean Young rcdev = rc_dev_get_from_fd(attr->query.target_fd); 280f4364dcfSSean Young if (IS_ERR(rcdev)) 281f4364dcfSSean Young return PTR_ERR(rcdev); 282f4364dcfSSean Young 283f4364dcfSSean Young if (rcdev->driver_type != RC_DRIVER_IR_RAW) { 284f4364dcfSSean Young ret = -EINVAL; 285f4364dcfSSean Young goto put; 286f4364dcfSSean Young } 287f4364dcfSSean Young 288f4364dcfSSean Young ret = mutex_lock_interruptible(&ir_raw_handler_lock); 289f4364dcfSSean Young if (ret) 290f4364dcfSSean Young goto put; 291f4364dcfSSean Young 292f4364dcfSSean Young progs = rcdev->raw->progs; 293f4364dcfSSean Young cnt = progs ? bpf_prog_array_length(progs) : 0; 294f4364dcfSSean Young 295f4364dcfSSean Young if (copy_to_user(&uattr->query.prog_cnt, &cnt, sizeof(cnt))) { 296f4364dcfSSean Young ret = -EFAULT; 297f4364dcfSSean Young goto unlock; 298f4364dcfSSean Young } 299f4364dcfSSean Young 300f4364dcfSSean Young if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags))) { 301f4364dcfSSean Young ret = -EFAULT; 302f4364dcfSSean Young goto unlock; 303f4364dcfSSean Young } 304f4364dcfSSean Young 305f4364dcfSSean Young if (attr->query.prog_cnt != 0 && prog_ids && cnt) 306f4364dcfSSean Young ret = bpf_prog_array_copy_to_user(progs, prog_ids, cnt); 307f4364dcfSSean Young 308f4364dcfSSean Young unlock: 309f4364dcfSSean Young mutex_unlock(&ir_raw_handler_lock); 310f4364dcfSSean Young put: 311f4364dcfSSean Young put_device(&rcdev->dev); 312f4364dcfSSean Young 313f4364dcfSSean Young return ret; 314f4364dcfSSean Young } 315