Re: [PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used

2018-05-14 Thread Y Song
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)
> +   

Re: [PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used

2018-05-14 Thread Y Song
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

2018-05-14 Thread kbuild test robot
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

2018-05-14 Thread kbuild test robot
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

2018-05-14 Thread Sean Young
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

2018-05-14 Thread Sean Young
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