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