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