Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp126499imm; Mon, 14 May 2018 22:24:16 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrGIM2w/+REjF4mbs4ASCXvWn+6geDSzgv2KJ7IzAMlZfZwckge/9UxsKzE03btQhZZW3Go X-Received: by 2002:a63:3fc9:: with SMTP id m192-v6mr11099430pga.340.1526361856335; Mon, 14 May 2018 22:24:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526361856; cv=none; d=google.com; s=arc-20160816; b=NNXe7B6YI3YLrXfVj/x/phuY/qW9GpV4sJdXods9+lvxWXa/JXQtyiz4T7L0JGskJC hQdPcGSmy4gb7MpY1fJ5nbkl0zYtU0Gdm+LgLC90y7v+blzvtDmGCiI0/vY1iOvXc5GO 6euXcpksbHlJHM0K4jUEoiYpo22GsQauFTXrwswu/SBZFUR7FnYjxnymDQdhhaAPQOjN 1+GabDmW45Yr2Kmxq+hnBgq2482ZSkeI/jYZJPebhyIppZMtD5eg+xHVy+CjaCK3NwTu 7YU+ZjkPX8lfyUjFjFIE1XtplKHoxD0O+0kxqpZJ+D4c3ZPYD+Y+Jtrdc1ZxNoKFzIwJ KNZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=ddgrjzRXsnEfLJeP/30+VpOrCjCWrb/b0OR0ua+fLeI=; b=bhpacT0bXtF8UPmVeVhBr2cq2D1Q4eyfH+rADqw80eafQQPlE1QhOaetH7o+bDHhrk fgQwnnS8LWFvCBI/q303WeY69mzE9Now6FFh8GRd1aFP8e8+Egd3YtGRjA+EP2Lr6lZj 6j2/Ver5czxAQFg6bIBw5H2BHxzFMlXjftt+Wd0KJzqIN6LZAKP33L7icd40VfbYVkNz r10H8QFB9EwTyEW6CVUyu+LKClsxx2e3Xb+0pkH9FJGDLmph3t3j4rUcDcJ7nmTnLTC1 oFxp8EBx0YN8sbWuzXvktFCDbm/U+WpMpKS2hfEcodmg+pSUNLIAbyvgr55KbhyRi6fo 0fVw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=dy8kulao; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b2-v6si9109240pgn.276.2018.05.14.22.24.02; Mon, 14 May 2018 22:24:16 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=dy8kulao; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752168AbeEOFXl (ORCPT + 99 others); Tue, 15 May 2018 01:23:41 -0400 Received: from mail-ua0-f195.google.com ([209.85.217.195]:46035 "EHLO mail-ua0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750886AbeEOFXi (ORCPT ); Tue, 15 May 2018 01:23:38 -0400 Received: by mail-ua0-f195.google.com with SMTP id j5-v6so9959845uak.12; Mon, 14 May 2018 22:23:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=ddgrjzRXsnEfLJeP/30+VpOrCjCWrb/b0OR0ua+fLeI=; b=dy8kulaoqzBp0haVwAEn2E1IJNnc5kNqwm65yYrx+JS3oPvBYbgndBCMJBCgs5Trto WXHHEnId8+5ebA/82QUC7wvn6rmHtqMsCiLcLHbDbo5RLf3AfGbxUurdwd18zoF2LE0q MrlBeQucSSPCyfcdPvXj9MglwcLCZkDZxTKIM3MGmo3MKRn+Ka0X/ZQJuHwaplRuIgIG EnqeOBLBQgqai1hgWtquJjynaNs4lBkbqjk0o6g/xE5SHL2g5StJjC14NwpdrBJQbGMk bKa9BPGazR55TI8/eyc8t3orHpK6ikcECNFHODnowhIrJ4poIT7yL+uiHmEhp2GNY5+f Pwmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=ddgrjzRXsnEfLJeP/30+VpOrCjCWrb/b0OR0ua+fLeI=; b=NakYw3dkMkvPLxHjJNs9WWuIvY37GpYYrPNPrG1qQQDGb9pZlyAnC3wgoKxdkk/5DZ vq3biWLCmNx1j5VaSgxIJ/lo5UvggguIbVSG+Z+XCaf5GZKusmQaLMZlfuh5UGqpoZw9 xiZaRxgqXznK3Nhg3d4wO+pS/pXAfXedjZ96iBsTG3w+E4T9QWsjna1O5Auu/sLm588B vgdZPrm4LhJ0dRzXeOagDiGz0F9slQdpMeVes5wqepoMIxwBi6niT5B/t08cMJHIJPSn Qnfc6sHiUF9BZPbr2bNf9muzJ/3vzsBHxWjnwx49RSkMODRSgBXAa2mgMDJkUjsGXpw2 xsQQ== X-Gm-Message-State: ALKqPwdJsR5MNbohmXU6h1c9YtC+lmNI7LNIIeIeOkAyQPGRt0Z4zPdm OZkEgx8brtgVpmy+CqXgydDqXbXObCNQUN/lAnY= X-Received: by 2002:a9f:3e4e:: with SMTP id c14-v6mr14692439uaj.100.1526361817526; Mon, 14 May 2018 22:23:37 -0700 (PDT) MIME-Version: 1.0 Received: by 10.103.64.90 with HTTP; Mon, 14 May 2018 22:22:57 -0700 (PDT) In-Reply-To: References: From: Y Song Date: Mon, 14 May 2018 22:22:57 -0700 Message-ID: Subject: Re: [PATCH v1 2/4] media: bpf: allow raw IR decoder bpf programs to be used To: Sean Young Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, Alexei Starovoitov , Mauro Carvalho Chehab , Daniel Borkmann , netdev , Matthias Reichl , Devin Heitmueller Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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(&rcdev->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, &new_array); > + if (ret < 0) > + goto out; > + > + rcu_assign_pointer(raw->progs, new_array); > + bpf_prog_array_free(old_array); > +out: > + mutex_unlock(&rcdev->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(&rcdev->lock); > + if (ret) > + return ret; > + > + raw = rcdev->raw; > + > + old_array = raw->progs; > + ret = bpf_prog_array_copy(old_array, prog, NULL, &new_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(&rcdev->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, &raw->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(&rcdev->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(&rcdev->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 = rc_dev_get_from_fd(attr->query.target_fd); > + if (IS_ERR(rcdev)) > + return PTR_ERR(rcdev); > + > + if (rcdev->driver_type != RC_DRIVER_IR_RAW) { > + ret = -EINVAL; > + goto out; > + } > + > + ret = mutex_lock_interruptible(&rcdev->lock); > + if (ret) > + goto out; > + > + progs = rcdev->raw->progs; > + cnt = progs ? bpf_prog_array_length(progs) : 0; > + > + if (copy_to_user(&uattr->query.prog_cnt, &cnt, sizeof(cnt))) { > + ret = -EFAULT; > + goto out; > + } > + if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags))) { > + ret = -EFAULT; > + goto out; > + } > + > + if (attr->query.prog_cnt != 0 && prog_ids && cnt) > + ret = bpf_prog_array_copy_to_user(progs, prog_ids, cnt); > + > +out: > + mutex_unlock(&rcdev->lock); > + put_device(&rcdev->dev); > + > + return ret; > +} > diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c > index 24e9fbb80e81..65319f2ccc13 100644 > --- a/drivers/media/rc/lirc_dev.c > +++ b/drivers/media/rc/lirc_dev.c > @@ -20,6 +20,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -28,6 +29,8 @@ > #include "rc-core-priv.h" > #include > > +#include > + > #define LIRCBUF_SIZE 256 > > static dev_t lirc_base_dev; > @@ -816,4 +819,31 @@ void __exit lirc_dev_exit(void) > unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); > } > > +struct rc_dev *rc_dev_get_from_fd(int fd) > +{ > + struct rc_dev *dev; > + struct file *f; > + > + f = fget_raw(fd); > + if (!f) > + return ERR_PTR(-EBADF); > + > + if (!S_ISCHR(f->f_inode->i_mode) || > + imajor(f->f_inode) != MAJOR(lirc_base_dev)) { > + fput(f); > + return ERR_PTR(-EBADF); > + } > + > + dev = container_of(f->f_inode->i_cdev, struct rc_dev, lirc_cdev); > + if (!dev->registered) { > + fput(f); > + return ERR_PTR(-ENODEV); > + } > + > + get_device(&dev->dev); > + fput(f); > + > + return dev; > +} > + > MODULE_ALIAS("lirc_dev"); > diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h > index e0e6a17460f6..b6f24f369657 100644 > --- a/drivers/media/rc/rc-core-priv.h > +++ b/drivers/media/rc/rc-core-priv.h > @@ -57,6 +57,9 @@ struct ir_raw_event_ctrl { > /* raw decoder state follows */ > struct ir_raw_event prev_ev; > struct ir_raw_event this_ev; > +#ifdef CONFIG_IR_BPF_DECODER > + struct bpf_prog_array *progs; > +#endif > struct nec_dec { > int state; > unsigned count; > @@ -288,6 +291,7 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev); > void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc); > int ir_lirc_register(struct rc_dev *dev); > void ir_lirc_unregister(struct rc_dev *dev); > +struct rc_dev *rc_dev_get_from_fd(int fd); > #else > static inline int lirc_dev_init(void) { return 0; } > static inline void lirc_dev_exit(void) {} > @@ -299,4 +303,15 @@ static inline int ir_lirc_register(struct rc_dev *dev) { return 0; } > static inline void ir_lirc_unregister(struct rc_dev *dev) { } > #endif > > +/* > + * bpf interface > + */ > +#ifdef CONFIG_IR_BPF_DECODER > +void rc_dev_bpf_put(struct rc_dev *dev); > +void rc_dev_bpf_run(struct rc_dev *dev); > +#else > +void rc_dev_bpf_put(struct rc_dev *dev) {} > +void rc_dev_bpf_run(struct rc_dev *dev) {} > +#endif > + > #endif /* _RC_CORE_PRIV */ > diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c > index 374f83105a23..efddd9c44466 100644 > --- a/drivers/media/rc/rc-ir-raw.c > +++ b/drivers/media/rc/rc-ir-raw.c > @@ -8,6 +8,8 @@ > #include > #include > #include > +#include > +#include > #include "rc-core-priv.h" > > /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ > @@ -33,6 +35,7 @@ static int ir_raw_event_thread(void *data) > handler->decode(raw->dev, ev); > ir_lirc_raw_event(raw->dev, ev); > raw->prev_ev = ev; > + rc_dev_bpf_run(raw->dev); > } > mutex_unlock(&ir_raw_handler_lock); > > @@ -623,6 +626,8 @@ void ir_raw_event_unregister(struct rc_dev *dev) > handler->raw_unregister(dev); > mutex_unlock(&ir_raw_handler_lock); > > + rc_dev_bpf_put(dev); > + > ir_raw_event_free(dev); > } > > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index 6ad053e831c0..d9740599adf6 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -155,6 +155,7 @@ enum bpf_attach_type { > BPF_CGROUP_INET6_CONNECT, > BPF_CGROUP_INET4_POST_BIND, > BPF_CGROUP_INET6_POST_BIND, > + BPF_RAWIR_DECODER, > __MAX_BPF_ATTACH_TYPE > }; > > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c > index 016ef9025827..63ecc1f2e1e3 100644 > --- a/kernel/bpf/syscall.c > +++ b/kernel/bpf/syscall.c > @@ -27,6 +27,7 @@ > #include > #include > #include > +#include > > #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ > (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ > @@ -1556,6 +1557,8 @@ static int bpf_prog_attach(const union bpf_attr *attr) > case BPF_SK_SKB_STREAM_PARSER: > case BPF_SK_SKB_STREAM_VERDICT: > return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, true); > + case BPF_RAWIR_DECODER: > + return rc_dev_prog_attach(attr); > default: > return -EINVAL; > } > @@ -1626,6 +1629,8 @@ static int bpf_prog_detach(const union bpf_attr *attr) > case BPF_SK_SKB_STREAM_PARSER: > case BPF_SK_SKB_STREAM_VERDICT: > return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, false); > + case BPF_RAWIR_DECODER: > + return rc_dev_prog_detach(attr); > default: > return -EINVAL; > } > @@ -1673,6 +1678,8 @@ static int bpf_prog_query(const union bpf_attr *attr, > case BPF_CGROUP_SOCK_OPS: > case BPF_CGROUP_DEVICE: > break; > + case BPF_RAWIR_DECODER: > + return rc_dev_prog_query(attr, uattr); > default: > return -EINVAL; > } > -- > 2.17.0 >