Re: [PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used
On Mon, May 14, 2018 at 2:10 PM, Sean Youngwrote: > This implements attaching, detaching, querying and execution. The target > fd has to be the /dev/lircN device. > > Signed-off-by: Sean Young > --- > drivers/media/rc/ir-bpf-decoder.c | 191 ++ > drivers/media/rc/lirc_dev.c | 30 + > drivers/media/rc/rc-core-priv.h | 15 +++ > drivers/media/rc/rc-ir-raw.c | 5 + > include/uapi/linux/bpf.h | 1 + > kernel/bpf/syscall.c | 7 ++ > 6 files changed, 249 insertions(+) > > diff --git a/drivers/media/rc/ir-bpf-decoder.c > b/drivers/media/rc/ir-bpf-decoder.c > index aaa5e208b1a5..651590a14772 100644 > --- a/drivers/media/rc/ir-bpf-decoder.c > +++ b/drivers/media/rc/ir-bpf-decoder.c > @@ -91,3 +91,194 @@ const struct bpf_verifier_ops ir_decoder_verifier_ops = { > .get_func_proto = ir_decoder_func_proto, > .is_valid_access = ir_decoder_is_valid_access > }; > + > +#define BPF_MAX_PROGS 64 > + > +int rc_dev_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) flags is not used in this function. > +{ > + struct ir_raw_event_ctrl *raw; > + struct bpf_prog_array __rcu *old_array; > + struct bpf_prog_array *new_array; > + int ret; > + > + if (rcdev->driver_type != RC_DRIVER_IR_RAW) > + return -EINVAL; > + > + ret = mutex_lock_interruptible(>lock); > + if (ret) > + return ret; > + > + raw = rcdev->raw; > + > + if (raw->progs && bpf_prog_array_length(raw->progs) >= BPF_MAX_PROGS) > { > + ret = -E2BIG; > + goto out; > + } > + > + old_array = raw->progs; > + ret = bpf_prog_array_copy(old_array, NULL, prog, _array); > + if (ret < 0) > + goto out; > + > + rcu_assign_pointer(raw->progs, new_array); > + bpf_prog_array_free(old_array); > +out: > + mutex_unlock(>lock); > + return ret; > +} > + > +int rc_dev_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) flags is not used in this function. > +{ > + struct ir_raw_event_ctrl *raw; > + struct bpf_prog_array __rcu *old_array; > + struct bpf_prog_array *new_array; > + int ret; > + > + if (rcdev->driver_type != RC_DRIVER_IR_RAW) > + return -EINVAL; > + > + ret = mutex_lock_interruptible(>lock); > + if (ret) > + return ret; > + > + raw = rcdev->raw; > + > + old_array = raw->progs; > + ret = bpf_prog_array_copy(old_array, prog, NULL, _array); > + if (ret < 0) { > + bpf_prog_array_delete_safe(old_array, prog); > + } else { > + rcu_assign_pointer(raw->progs, new_array); > + bpf_prog_array_free(old_array); > + } > + > + bpf_prog_put(prog); > + mutex_unlock(>lock); > + return 0; > +} > + > +void rc_dev_bpf_run(struct rc_dev *rcdev) > +{ > + struct ir_raw_event_ctrl *raw = rcdev->raw; > + > + if (raw->progs) > + BPF_PROG_RUN_ARRAY(raw->progs, >prev_ev, BPF_PROG_RUN); > +} > + > +void rc_dev_bpf_put(struct rc_dev *rcdev) > +{ > + struct bpf_prog_array *progs = rcdev->raw->progs; > + int i, size; > + > + if (!progs) > + return; > + > + size = bpf_prog_array_length(progs); > + for (i = 0; i < size; i++) > + bpf_prog_put(progs->progs[i]); > + > + bpf_prog_array_free(rcdev->raw->progs); > +} > + > +int rc_dev_prog_attach(const union bpf_attr *attr) > +{ > + struct bpf_prog *prog; > + struct rc_dev *rcdev; > + int ret; > + > + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) > + return -EINVAL; Looks like you really did not use flags except here. BPF_F_ALLOW_OVERRIDE is originally used for cgroup type of attachment and the comment explicits saying so. In the query below, the flags value "0" is copied to userspace. In your case, I think you can just disallow any value, i.g., attr->attach_flags must be 0, and then you further down check that if the prog is already in the array, you just return an error. > + > + prog = bpf_prog_get_type(attr->attach_bpf_fd, > +BPF_PROG_TYPE_RAWIR_DECODER); > + if (IS_ERR(prog)) > + return PTR_ERR(prog); > + > + rcdev = rc_dev_get_from_fd(attr->target_fd); > + if (IS_ERR(rcdev)) { > + bpf_prog_put(prog); > + return PTR_ERR(rcdev); > + } > + > + ret = rc_dev_bpf_attach(rcdev, prog, attr->attach_flags); > + if (ret) > + bpf_prog_put(prog); > + > + put_device(>dev); > + > + return ret; > +} > + > +int rc_dev_prog_detach(const union bpf_attr *attr) > +{ > + struct bpf_prog *prog; > + struct rc_dev *rcdev; > + int ret; > + > + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) > +
Re: [PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used
On Mon, May 14, 2018 at 2:10 PM, Sean Young wrote: > This implements attaching, detaching, querying and execution. The target > fd has to be the /dev/lircN device. > > Signed-off-by: Sean Young > --- > drivers/media/rc/ir-bpf-decoder.c | 191 ++ > drivers/media/rc/lirc_dev.c | 30 + > drivers/media/rc/rc-core-priv.h | 15 +++ > drivers/media/rc/rc-ir-raw.c | 5 + > include/uapi/linux/bpf.h | 1 + > kernel/bpf/syscall.c | 7 ++ > 6 files changed, 249 insertions(+) > > diff --git a/drivers/media/rc/ir-bpf-decoder.c > b/drivers/media/rc/ir-bpf-decoder.c > index aaa5e208b1a5..651590a14772 100644 > --- a/drivers/media/rc/ir-bpf-decoder.c > +++ b/drivers/media/rc/ir-bpf-decoder.c > @@ -91,3 +91,194 @@ const struct bpf_verifier_ops ir_decoder_verifier_ops = { > .get_func_proto = ir_decoder_func_proto, > .is_valid_access = ir_decoder_is_valid_access > }; > + > +#define BPF_MAX_PROGS 64 > + > +int rc_dev_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) flags is not used in this function. > +{ > + struct ir_raw_event_ctrl *raw; > + struct bpf_prog_array __rcu *old_array; > + struct bpf_prog_array *new_array; > + int ret; > + > + if (rcdev->driver_type != RC_DRIVER_IR_RAW) > + return -EINVAL; > + > + ret = mutex_lock_interruptible(>lock); > + if (ret) > + return ret; > + > + raw = rcdev->raw; > + > + if (raw->progs && bpf_prog_array_length(raw->progs) >= BPF_MAX_PROGS) > { > + ret = -E2BIG; > + goto out; > + } > + > + old_array = raw->progs; > + ret = bpf_prog_array_copy(old_array, NULL, prog, _array); > + if (ret < 0) > + goto out; > + > + rcu_assign_pointer(raw->progs, new_array); > + bpf_prog_array_free(old_array); > +out: > + mutex_unlock(>lock); > + return ret; > +} > + > +int rc_dev_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) flags is not used in this function. > +{ > + struct ir_raw_event_ctrl *raw; > + struct bpf_prog_array __rcu *old_array; > + struct bpf_prog_array *new_array; > + int ret; > + > + if (rcdev->driver_type != RC_DRIVER_IR_RAW) > + return -EINVAL; > + > + ret = mutex_lock_interruptible(>lock); > + if (ret) > + return ret; > + > + raw = rcdev->raw; > + > + old_array = raw->progs; > + ret = bpf_prog_array_copy(old_array, prog, NULL, _array); > + if (ret < 0) { > + bpf_prog_array_delete_safe(old_array, prog); > + } else { > + rcu_assign_pointer(raw->progs, new_array); > + bpf_prog_array_free(old_array); > + } > + > + bpf_prog_put(prog); > + mutex_unlock(>lock); > + return 0; > +} > + > +void rc_dev_bpf_run(struct rc_dev *rcdev) > +{ > + struct ir_raw_event_ctrl *raw = rcdev->raw; > + > + if (raw->progs) > + BPF_PROG_RUN_ARRAY(raw->progs, >prev_ev, BPF_PROG_RUN); > +} > + > +void rc_dev_bpf_put(struct rc_dev *rcdev) > +{ > + struct bpf_prog_array *progs = rcdev->raw->progs; > + int i, size; > + > + if (!progs) > + return; > + > + size = bpf_prog_array_length(progs); > + for (i = 0; i < size; i++) > + bpf_prog_put(progs->progs[i]); > + > + bpf_prog_array_free(rcdev->raw->progs); > +} > + > +int rc_dev_prog_attach(const union bpf_attr *attr) > +{ > + struct bpf_prog *prog; > + struct rc_dev *rcdev; > + int ret; > + > + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) > + return -EINVAL; Looks like you really did not use flags except here. BPF_F_ALLOW_OVERRIDE is originally used for cgroup type of attachment and the comment explicits saying so. In the query below, the flags value "0" is copied to userspace. In your case, I think you can just disallow any value, i.g., attr->attach_flags must be 0, and then you further down check that if the prog is already in the array, you just return an error. > + > + prog = bpf_prog_get_type(attr->attach_bpf_fd, > +BPF_PROG_TYPE_RAWIR_DECODER); > + if (IS_ERR(prog)) > + return PTR_ERR(prog); > + > + rcdev = rc_dev_get_from_fd(attr->target_fd); > + if (IS_ERR(rcdev)) { > + bpf_prog_put(prog); > + return PTR_ERR(rcdev); > + } > + > + ret = rc_dev_bpf_attach(rcdev, prog, attr->attach_flags); > + if (ret) > + bpf_prog_put(prog); > + > + put_device(>dev); > + > + return ret; > +} > + > +int rc_dev_prog_detach(const union bpf_attr *attr) > +{ > + struct bpf_prog *prog; > + struct rc_dev *rcdev; > + int ret; > + > + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) > + return -EINVAL; > + > +
Re: [PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used
Hi Sean, I love your patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on v4.17-rc5] [cannot apply to next-20180514] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Sean-Young/media-rc-introduce-BPF_PROG_IR_DECODER/20180515-093234 config: i386-allmodconfig (attached as .config) compiler: gcc-7 (Debian 7.3.0-16) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=i386 All errors (new ones prefixed by >>): >> drivers/media/rc/lirc_dev.c:32:10: fatal error: linux/bpf-rcdev.h: No such >> file or directory #include ^~~ compilation terminated. -- >> kernel/bpf/syscall.c:30:10: fatal error: linux/bpf-rcdev.h: No such file or >> directory #include ^~~ compilation terminated. vim +32 drivers/media/rc/lirc_dev.c 31 > 32 #include 33 --- 0-DAY kernel test infrastructureOpen Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation .config.gz Description: application/gzip
Re: [PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used
Hi Sean, I love your patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on v4.17-rc5] [cannot apply to next-20180514] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Sean-Young/media-rc-introduce-BPF_PROG_IR_DECODER/20180515-093234 config: i386-allmodconfig (attached as .config) compiler: gcc-7 (Debian 7.3.0-16) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=i386 All errors (new ones prefixed by >>): >> drivers/media/rc/lirc_dev.c:32:10: fatal error: linux/bpf-rcdev.h: No such >> file or directory #include ^~~ compilation terminated. -- >> kernel/bpf/syscall.c:30:10: fatal error: linux/bpf-rcdev.h: No such file or >> directory #include ^~~ compilation terminated. vim +32 drivers/media/rc/lirc_dev.c 31 > 32 #include 33 --- 0-DAY kernel test infrastructureOpen Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation .config.gz Description: application/gzip
[PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used
This implements attaching, detaching, querying and execution. The target fd has to be the /dev/lircN device. Signed-off-by: Sean Young--- drivers/media/rc/ir-bpf-decoder.c | 191 ++ drivers/media/rc/lirc_dev.c | 30 + drivers/media/rc/rc-core-priv.h | 15 +++ drivers/media/rc/rc-ir-raw.c | 5 + include/uapi/linux/bpf.h | 1 + kernel/bpf/syscall.c | 7 ++ 6 files changed, 249 insertions(+) diff --git a/drivers/media/rc/ir-bpf-decoder.c b/drivers/media/rc/ir-bpf-decoder.c index aaa5e208b1a5..651590a14772 100644 --- a/drivers/media/rc/ir-bpf-decoder.c +++ b/drivers/media/rc/ir-bpf-decoder.c @@ -91,3 +91,194 @@ const struct bpf_verifier_ops ir_decoder_verifier_ops = { .get_func_proto = ir_decoder_func_proto, .is_valid_access = ir_decoder_is_valid_access }; + +#define BPF_MAX_PROGS 64 + +int rc_dev_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) +{ + struct ir_raw_event_ctrl *raw; + struct bpf_prog_array __rcu *old_array; + struct bpf_prog_array *new_array; + int ret; + + if (rcdev->driver_type != RC_DRIVER_IR_RAW) + return -EINVAL; + + ret = mutex_lock_interruptible(>lock); + if (ret) + return ret; + + raw = rcdev->raw; + + if (raw->progs && bpf_prog_array_length(raw->progs) >= BPF_MAX_PROGS) { + ret = -E2BIG; + goto out; + } + + old_array = raw->progs; + ret = bpf_prog_array_copy(old_array, NULL, prog, _array); + if (ret < 0) + goto out; + + rcu_assign_pointer(raw->progs, new_array); + bpf_prog_array_free(old_array); +out: + mutex_unlock(>lock); + return ret; +} + +int rc_dev_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) +{ + struct ir_raw_event_ctrl *raw; + struct bpf_prog_array __rcu *old_array; + struct bpf_prog_array *new_array; + int ret; + + if (rcdev->driver_type != RC_DRIVER_IR_RAW) + return -EINVAL; + + ret = mutex_lock_interruptible(>lock); + if (ret) + return ret; + + raw = rcdev->raw; + + old_array = raw->progs; + ret = bpf_prog_array_copy(old_array, prog, NULL, _array); + if (ret < 0) { + bpf_prog_array_delete_safe(old_array, prog); + } else { + rcu_assign_pointer(raw->progs, new_array); + bpf_prog_array_free(old_array); + } + + bpf_prog_put(prog); + mutex_unlock(>lock); + return 0; +} + +void rc_dev_bpf_run(struct rc_dev *rcdev) +{ + struct ir_raw_event_ctrl *raw = rcdev->raw; + + if (raw->progs) + BPF_PROG_RUN_ARRAY(raw->progs, >prev_ev, BPF_PROG_RUN); +} + +void rc_dev_bpf_put(struct rc_dev *rcdev) +{ + struct bpf_prog_array *progs = rcdev->raw->progs; + int i, size; + + if (!progs) + return; + + size = bpf_prog_array_length(progs); + for (i = 0; i < size; i++) + bpf_prog_put(progs->progs[i]); + + bpf_prog_array_free(rcdev->raw->progs); +} + +int rc_dev_prog_attach(const union bpf_attr *attr) +{ + struct bpf_prog *prog; + struct rc_dev *rcdev; + int ret; + + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) + return -EINVAL; + + prog = bpf_prog_get_type(attr->attach_bpf_fd, +BPF_PROG_TYPE_RAWIR_DECODER); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + rcdev = rc_dev_get_from_fd(attr->target_fd); + if (IS_ERR(rcdev)) { + bpf_prog_put(prog); + return PTR_ERR(rcdev); + } + + ret = rc_dev_bpf_attach(rcdev, prog, attr->attach_flags); + if (ret) + bpf_prog_put(prog); + + put_device(>dev); + + return ret; +} + +int rc_dev_prog_detach(const union bpf_attr *attr) +{ + struct bpf_prog *prog; + struct rc_dev *rcdev; + int ret; + + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) + return -EINVAL; + + prog = bpf_prog_get_type(attr->attach_bpf_fd, +BPF_PROG_TYPE_RAWIR_DECODER); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + rcdev = rc_dev_get_from_fd(attr->target_fd); + if (IS_ERR(rcdev)) { + bpf_prog_put(prog); + return PTR_ERR(rcdev); + } + + ret = rc_dev_bpf_detach(rcdev, prog, attr->attach_flags); + + bpf_prog_put(prog); + put_device(>dev); + + return ret; +} + +int rc_dev_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) +{ + __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids); + struct bpf_prog_array *progs; + struct rc_dev *rcdev; + u32 cnt, flags = 0; + int ret; + + if (attr->query.query_flags) + return -EINVAL;
[PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used
This implements attaching, detaching, querying and execution. The target fd has to be the /dev/lircN device. Signed-off-by: Sean Young --- drivers/media/rc/ir-bpf-decoder.c | 191 ++ drivers/media/rc/lirc_dev.c | 30 + drivers/media/rc/rc-core-priv.h | 15 +++ drivers/media/rc/rc-ir-raw.c | 5 + include/uapi/linux/bpf.h | 1 + kernel/bpf/syscall.c | 7 ++ 6 files changed, 249 insertions(+) diff --git a/drivers/media/rc/ir-bpf-decoder.c b/drivers/media/rc/ir-bpf-decoder.c index aaa5e208b1a5..651590a14772 100644 --- a/drivers/media/rc/ir-bpf-decoder.c +++ b/drivers/media/rc/ir-bpf-decoder.c @@ -91,3 +91,194 @@ const struct bpf_verifier_ops ir_decoder_verifier_ops = { .get_func_proto = ir_decoder_func_proto, .is_valid_access = ir_decoder_is_valid_access }; + +#define BPF_MAX_PROGS 64 + +int rc_dev_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) +{ + struct ir_raw_event_ctrl *raw; + struct bpf_prog_array __rcu *old_array; + struct bpf_prog_array *new_array; + int ret; + + if (rcdev->driver_type != RC_DRIVER_IR_RAW) + return -EINVAL; + + ret = mutex_lock_interruptible(>lock); + if (ret) + return ret; + + raw = rcdev->raw; + + if (raw->progs && bpf_prog_array_length(raw->progs) >= BPF_MAX_PROGS) { + ret = -E2BIG; + goto out; + } + + old_array = raw->progs; + ret = bpf_prog_array_copy(old_array, NULL, prog, _array); + if (ret < 0) + goto out; + + rcu_assign_pointer(raw->progs, new_array); + bpf_prog_array_free(old_array); +out: + mutex_unlock(>lock); + return ret; +} + +int rc_dev_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog, u32 flags) +{ + struct ir_raw_event_ctrl *raw; + struct bpf_prog_array __rcu *old_array; + struct bpf_prog_array *new_array; + int ret; + + if (rcdev->driver_type != RC_DRIVER_IR_RAW) + return -EINVAL; + + ret = mutex_lock_interruptible(>lock); + if (ret) + return ret; + + raw = rcdev->raw; + + old_array = raw->progs; + ret = bpf_prog_array_copy(old_array, prog, NULL, _array); + if (ret < 0) { + bpf_prog_array_delete_safe(old_array, prog); + } else { + rcu_assign_pointer(raw->progs, new_array); + bpf_prog_array_free(old_array); + } + + bpf_prog_put(prog); + mutex_unlock(>lock); + return 0; +} + +void rc_dev_bpf_run(struct rc_dev *rcdev) +{ + struct ir_raw_event_ctrl *raw = rcdev->raw; + + if (raw->progs) + BPF_PROG_RUN_ARRAY(raw->progs, >prev_ev, BPF_PROG_RUN); +} + +void rc_dev_bpf_put(struct rc_dev *rcdev) +{ + struct bpf_prog_array *progs = rcdev->raw->progs; + int i, size; + + if (!progs) + return; + + size = bpf_prog_array_length(progs); + for (i = 0; i < size; i++) + bpf_prog_put(progs->progs[i]); + + bpf_prog_array_free(rcdev->raw->progs); +} + +int rc_dev_prog_attach(const union bpf_attr *attr) +{ + struct bpf_prog *prog; + struct rc_dev *rcdev; + int ret; + + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) + return -EINVAL; + + prog = bpf_prog_get_type(attr->attach_bpf_fd, +BPF_PROG_TYPE_RAWIR_DECODER); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + rcdev = rc_dev_get_from_fd(attr->target_fd); + if (IS_ERR(rcdev)) { + bpf_prog_put(prog); + return PTR_ERR(rcdev); + } + + ret = rc_dev_bpf_attach(rcdev, prog, attr->attach_flags); + if (ret) + bpf_prog_put(prog); + + put_device(>dev); + + return ret; +} + +int rc_dev_prog_detach(const union bpf_attr *attr) +{ + struct bpf_prog *prog; + struct rc_dev *rcdev; + int ret; + + if (attr->attach_flags & BPF_F_ALLOW_OVERRIDE) + return -EINVAL; + + prog = bpf_prog_get_type(attr->attach_bpf_fd, +BPF_PROG_TYPE_RAWIR_DECODER); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + rcdev = rc_dev_get_from_fd(attr->target_fd); + if (IS_ERR(rcdev)) { + bpf_prog_put(prog); + return PTR_ERR(rcdev); + } + + ret = rc_dev_bpf_detach(rcdev, prog, attr->attach_flags); + + bpf_prog_put(prog); + put_device(>dev); + + return ret; +} + +int rc_dev_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) +{ + __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids); + struct bpf_prog_array *progs; + struct rc_dev *rcdev; + u32 cnt, flags = 0; + int ret; + + if (attr->query.query_flags) + return -EINVAL; + + rcdev