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