linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Song Liu <song@kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>,
	Jiri Kosina <jikos@kernel.org>,
	Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Martin KaFai Lau <kafai@fb.com>, Song Liu <songliubraving@fb.com>,
	Yonghong Song <yhs@fb.com>,
	John Fastabend <john.fastabend@gmail.com>,
	KP Singh <kpsingh@kernel.org>, Shuah Khan <shuah@kernel.org>,
	Dave Marchevsky <davemarchevsky@fb.com>,
	Joe Stringer <joe@cilium.io>, Jonathan Corbet <corbet@lwn.net>,
	Tero Kristo <tero.kristo@linux.intel.com>,
	open list <linux-kernel@vger.kernel.org>,
	"open list:HID CORE LAYER" <linux-input@vger.kernel.org>,
	Networking <netdev@vger.kernel.org>, bpf <bpf@vger.kernel.org>,
	linux-kselftest@vger.kernel.org,
	Linux Doc Mailing List <linux-doc@vger.kernel.org>
Subject: Re: [PATCH bpf-next v3 02/17] bpf: introduce hid program type
Date: Mon, 21 Mar 2022 17:07:21 +0100	[thread overview]
Message-ID: <CAO-hwJ+WSi645HhNV_BYACoJe2UTc4KZzqH0oHocfnBR8xUYEQ@mail.gmail.com> (raw)
In-Reply-To: <CAPhsuW5qseqVs4=hz3VvSJ2ObqB2kTbKXoaOCh=5vjoU_AXnKQ@mail.gmail.com>

Hi Song,

many thanks for the quick response.

On Fri, Mar 18, 2022 at 9:48 PM Song Liu <song@kernel.org> wrote:
>
> On Fri, Mar 18, 2022 at 9:16 AM Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
> >
> [...]
> >
> > diff --git a/include/linux/bpf-hid.h b/include/linux/bpf-hid.h
> > new file mode 100644
> > index 000000000000..9c8dbd389995
> > --- /dev/null
> > +++ b/include/linux/bpf-hid.h
> >
> [...]
> > +
> > +struct hid_bpf_ctx_kern {
> > +       enum hid_bpf_event type;        /* read-only */
> > +       struct hid_device *hdev;        /* read-only */
> > +
> > +       u16 size;                       /* used size in data (RW) */
> > +       u8 *data;                       /* data buffer (RW) */
> > +       u32 allocated_size;             /* allocated size of data (RO) */
>
> Why u16 size vs. u32 allocated_size?

Probably an oversight because I wrote u32 in the public uapi. Will
change this into u16 too.

> Also, maybe shuffle the members
> to remove some holes?

Ack will do in the next version.

>
> > +
> > +       s32 retval;                     /* in use when BPF_HID_ATTACH_USER_EVENT (RW) */
> > +};
> > +
> [...]
>
> > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>
> We need to mirror these changes to tools/include/uapi/linux/bpf.h.

OK. I did that in patch 4/17 but I can bring in the changes there too.

>
> > index 99fab54ae9c0..0e8438e93768 100644
> > --- a/include/uapi/linux/bpf.h
> > +++ b/include/uapi/linux/bpf.h
> > @@ -952,6 +952,7 @@ enum bpf_prog_type {
> >         BPF_PROG_TYPE_LSM,
> >         BPF_PROG_TYPE_SK_LOOKUP,
> >         BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
> > +       BPF_PROG_TYPE_HID,
> >  };
> [...]
> > +
> >  /* When BPF ldimm64's insn[0].src_reg != 0 then this can have
> >   * the following extensions:
> >   *
> > @@ -5129,6 +5145,16 @@ union bpf_attr {
> >   *             The **hash_algo** is returned on success,
> >   *             **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if
> >   *             invalid arguments are passed.
> > + *
> > + * void *bpf_hid_get_data(void *ctx, u64 offset, u64 size)
> > + *     Description
> > + *             Returns a pointer to the data associated with context at the given
> > + *             offset and size (in bytes).
> > + *
> > + *             Note: the returned pointer is refcounted and must be dereferenced
> > + *             by a call to bpf_hid_discard;
> > + *     Return
> > + *             The pointer to the data. On error, a null value is returned.
>
> Please use annotations like *size*, **NULL**.

Ack

>
> >   */
> >  #define __BPF_FUNC_MAPPER(FN)          \
> >         FN(unspec),                     \
> > @@ -5325,6 +5351,7 @@ union bpf_attr {
> >         FN(copy_from_user_task),        \
> >         FN(skb_set_tstamp),             \
> >         FN(ima_file_hash),              \
> > +       FN(hid_get_data),               \
> >         /* */
> >
> >  /* integer value in 'imm' field of BPF_CALL instruction selects which helper
> > @@ -5925,6 +5952,10 @@ struct bpf_link_info {
> >                 struct {
> >                         __u32 ifindex;
> >                 } xdp;
> > +               struct  {
> > +                       __s32 hidraw_number;
> > +                       __u32 attach_type;
> > +               } hid;
> >         };
> >  } __attribute__((aligned(8)));
> >
> > diff --git a/include/uapi/linux/bpf_hid.h b/include/uapi/linux/bpf_hid.h
> > new file mode 100644
> > index 000000000000..64a8b9dd8809
> > --- /dev/null
> > +++ b/include/uapi/linux/bpf_hid.h
> > @@ -0,0 +1,31 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
> > +
> > +/*
> > + *  HID BPF public headers
> > + *
> > + *  Copyright (c) 2022 Benjamin Tissoires
> > + */
> > +
> > +#ifndef _UAPI__LINUX_BPF_HID_H__
> > +#define _UAPI__LINUX_BPF_HID_H__
> > +
> > +#include <linux/types.h>
> > +
> > +enum hid_bpf_event {
> > +       HID_BPF_UNDEF = 0,
> > +       HID_BPF_DEVICE_EVENT,           /* when attach type is BPF_HID_DEVICE_EVENT */
> > +       HID_BPF_RDESC_FIXUP,            /* ................... BPF_HID_RDESC_FIXUP */
> > +       HID_BPF_USER_EVENT,             /* ................... BPF_HID_USER_EVENT */
>
> Why don't we have a DRIVER_EVENT type here?

For driver event, I want to have a little bit more of information
which tells which event we have:
- HID_BPF_DRIVER_PROBE
- HID_BPF_DRIVER_SUSPEND
- HID_BPF_DRIVER_RAW_REQUEST
- HID_BPF_DRIVER_RAW_REQUEST_ANSWER
- etc...

However, I am not entirely sure on the implementation of all of those,
so I left them aside for now.

I'll work on that for v4.

>
> >
> [...]
> > +
> > +BPF_CALL_3(bpf_hid_get_data, struct hid_bpf_ctx_kern*, ctx, u64, offset, u64, size)
> > +{
> > +       if (!size)
> > +               return 0UL;
> > +
> > +       if (offset + size > ctx->allocated_size)
> > +               return 0UL;
> > +
> > +       return (unsigned long)(ctx->data + offset);
> > +}
> > +
> > +static const struct bpf_func_proto bpf_hid_get_data_proto = {
> > +       .func      = bpf_hid_get_data,
> > +       .gpl_only  = true,
> > +       .ret_type  = RET_PTR_TO_ALLOC_MEM_OR_NULL,
> > +       .arg1_type = ARG_PTR_TO_CTX,
> > +       .arg2_type = ARG_ANYTHING,
> > +       .arg3_type = ARG_CONST_ALLOC_SIZE_OR_ZERO,
>
> I think we should use ARG_CONST_SIZE or ARG_CONST_SIZE_OR_ZERO?

I initially tried this with ARG_CONST_SIZE_OR_ZERO but it doesn't work
for 2 reasons:
- we need to pair the argument ARG_CONST_SIZE_* with a pointer to a
memory just before, which doesn't really make sense here
- ARG_CONST_SIZE_* isn't handled in the same way
ARG_CONST_ALLOC_SIZE_OR_ZERO is. The latter tells the verifier that
the given size is the available size of the returned
PTR_TO_ALLOC_MEM_OR_NULL, which is exactly what we want.

>
> > +};
> > +
> > +static const struct bpf_func_proto *
> > +hid_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
> > +{
> > +       switch (func_id) {
> > +       case BPF_FUNC_hid_get_data:
> > +               return &bpf_hid_get_data_proto;
> > +       default:
> > +               return bpf_base_func_proto(func_id);
> > +       }
> > +}
> [...]
> > +
> > +static int hid_bpf_prog_test_run(struct bpf_prog *prog,
> > +                                const union bpf_attr *attr,
> > +                                union bpf_attr __user *uattr)
> > +{
> > +       struct hid_device *hdev = NULL;
> > +       struct bpf_prog_array *progs;
> > +       bool valid_prog = false;
> > +       int i;
> > +       int target_fd, ret;
> > +       void __user *data_out = u64_to_user_ptr(attr->test.data_out);
> > +       void __user *data_in = u64_to_user_ptr(attr->test.data_in);
> > +       u32 user_size_in = attr->test.data_size_in;
> > +       u32 user_size_out = attr->test.data_size_out;
> > +       u32 allocated_size = max(user_size_in, user_size_out);
> > +       struct hid_bpf_ctx_kern ctx = {
> > +               .type = HID_BPF_USER_EVENT,
> > +               .allocated_size = allocated_size,
> > +       };
> > +
> > +       if (!hid_hooks.hdev_from_fd)
> > +               return -EOPNOTSUPP;
> > +
> > +       if (attr->test.ctx_size_in != sizeof(int))
> > +               return -EINVAL;
>
> ctx_size_in is always 4 bytes?

Yes. Basically what I had in mind is that the "ctx" for
user_prog_test_run is the file descriptor to the sysfs that represent
the HID device.
This seemed to me to be the easiest to handle for users.

I'm open to suggestions though.

>
> > +
> > +       if (allocated_size > HID_MAX_BUFFER_SIZE)
> > +               return -E2BIG;
> > +
> > +       if (copy_from_user(&target_fd, (void *)attr->test.ctx_in, attr->test.ctx_size_in))
> > +               return -EFAULT;
> > +
> > +       hdev = hid_hooks.hdev_from_fd(target_fd);
> > +       if (IS_ERR(hdev))
> > +               return PTR_ERR(hdev);
> > +
> > +       if (allocated_size) {
> > +               ctx.data = kzalloc(allocated_size, GFP_KERNEL);
> > +               if (!ctx.data)
> > +                       return -ENOMEM;
> > +
> > +               ctx.allocated_size = allocated_size;
> > +       }
> > +       ctx.hdev = hdev;
> > +
> > +       ret = mutex_lock_interruptible(&bpf_hid_mutex);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /* check if the given program is of correct type and registered */
> > +       progs = rcu_dereference_protected(hdev->bpf.run_array[BPF_HID_ATTACH_USER_EVENT],
> > +                                         lockdep_is_held(&bpf_hid_mutex));
> > +       if (!progs) {
> > +               ret = -EFAULT;
> > +               goto unlock;
> > +       }
> > +
> > +       for (i = 0; i < bpf_prog_array_length(progs); i++) {
> > +               if (progs->items[i].prog == prog) {
> > +                       valid_prog = true;
> > +                       break;
> > +               }
> > +       }
> > +
> > +       if (!valid_prog) {
> > +               ret = -EINVAL;
> > +               goto unlock;
> > +       }
> > +
> > +       /* copy data_in from userspace */
> > +       if (user_size_in) {
> > +               if (copy_from_user(ctx.data, data_in, user_size_in)) {
> > +                       ret = -EFAULT;
> > +                       goto unlock;
> > +               }
> > +
> > +               ctx.size = user_size_in;
> > +       }
> > +
> > +       migrate_disable();
> > +
> > +       ret = bpf_prog_run(prog, &ctx);
> > +
> > +       migrate_enable();
> > +
> > +       if (user_size_out && data_out) {
> > +               user_size_out = min3(user_size_out, (u32)ctx.size, allocated_size);
> > +
> > +               if (copy_to_user(data_out, ctx.data, user_size_out)) {
> > +                       ret = -EFAULT;
> > +                       goto unlock;
> > +               }
> > +
> > +               if (copy_to_user(&uattr->test.data_size_out,
> > +                                &user_size_out,
> > +                                sizeof(user_size_out))) {
> > +                       ret = -EFAULT;
> > +                       goto unlock;
> > +               }
> > +       }
> > +
> > +       if (copy_to_user(&uattr->test.retval, &ctx.retval, sizeof(ctx.retval)))
> > +               ret = -EFAULT;
> > +
> > +unlock:
> > +       kfree(ctx.data);
> > +
> > +       mutex_unlock(&bpf_hid_mutex);
> > +       return ret;
> > +}
> > +
> > +const struct bpf_prog_ops hid_prog_ops = {
> > +       .test_run = hid_bpf_prog_test_run,
> > +};
> > +
> > +int bpf_hid_init(struct hid_device *hdev)
> > +{
> > +       int type;
> > +
> > +       for (type = 0; type < MAX_BPF_HID_ATTACH_TYPE; type++)
> > +               INIT_LIST_HEAD(&hdev->bpf.links[type]);
> > +
> > +       return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(bpf_hid_init);
> > +
> > +void bpf_hid_exit(struct hid_device *hdev)
> > +{
> > +       enum bpf_hid_attach_type type;
> > +       struct bpf_hid_link *hid_link;
> > +
> > +       mutex_lock(&bpf_hid_mutex);
> > +       for (type = 0; type < MAX_BPF_HID_ATTACH_TYPE; type++) {
> > +               bpf_hid_run_array_detach(hdev, type);
> > +               list_for_each_entry(hid_link, &hdev->bpf.links[type], node) {
> > +                       hid_link->hdev = NULL; /* auto-detach link */
> > +               }
> > +       }
> > +       mutex_unlock(&bpf_hid_mutex);
> > +}
> > +EXPORT_SYMBOL_GPL(bpf_hid_exit);
> > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> > index b88688264ad0..d1c05011e5ab 100644
> > --- a/kernel/bpf/syscall.c
> > +++ b/kernel/bpf/syscall.c
> > @@ -3,6 +3,7 @@
> >   */
> >  #include <linux/bpf.h>
> >  #include <linux/bpf-cgroup.h>
> > +#include <linux/bpf-hid.h>
> >  #include <linux/bpf_trace.h>
> >  #include <linux/bpf_lirc.h>
> >  #include <linux/bpf_verifier.h>
> > @@ -2205,6 +2206,7 @@ static bool is_sys_admin_prog_type(enum bpf_prog_type prog_type)
> >  {
> >         switch (prog_type) {
> >         case BPF_PROG_TYPE_LIRC_MODE2:
> > +       case BPF_PROG_TYPE_HID:
> >                 return true;
> >         default:
> >                 return false;
> > @@ -3199,6 +3201,11 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
> >                 return BPF_PROG_TYPE_SK_LOOKUP;
> >         case BPF_XDP:
> >                 return BPF_PROG_TYPE_XDP;
> > +       case BPF_HID_DEVICE_EVENT:
> > +       case BPF_HID_RDESC_FIXUP:
> > +       case BPF_HID_USER_EVENT:
> > +       case BPF_HID_DRIVER_EVENT:
> > +               return BPF_PROG_TYPE_HID;
> >         default:
> >                 return BPF_PROG_TYPE_UNSPEC;
> >         }
> > @@ -3342,6 +3349,11 @@ static int bpf_prog_query(const union bpf_attr *attr,
> >         case BPF_SK_MSG_VERDICT:
> >         case BPF_SK_SKB_VERDICT:
> >                 return sock_map_bpf_prog_query(attr, uattr);
> > +       case BPF_HID_DEVICE_EVENT:
> > +       case BPF_HID_RDESC_FIXUP:
> > +       case BPF_HID_USER_EVENT:
> > +       case BPF_HID_DRIVER_EVENT:
> > +               return bpf_hid_prog_query(attr, uattr);
> >         default:
> >                 return -EINVAL;
> >         }
> > @@ -4336,6 +4348,8 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr)
> >                 ret = bpf_perf_link_attach(attr, prog);
> >                 break;
> >  #endif
> > +       case BPF_PROG_TYPE_HID:
> > +               return bpf_hid_link_create(attr, prog);
> >         default:
> >                 ret = -EINVAL;
> >         }
> > --
> > 2.35.1
> >
>

Cheers,
Benjamin


  reply	other threads:[~2022-03-21 16:07 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-18 16:15 [PATCH bpf-next v3 00/17] Introduce eBPF support for HID devices Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 01/17] bpf: add new is_sys_admin_prog_type() helper Benjamin Tissoires
2022-03-18 18:07   ` Song Liu
2022-03-18 16:15 ` [PATCH bpf-next v3 02/17] bpf: introduce hid program type Benjamin Tissoires
2022-03-18 20:48   ` Song Liu
2022-03-21 16:07     ` Benjamin Tissoires [this message]
2022-03-21 21:51       ` Song Liu
2022-03-22 11:06         ` Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 03/17] bpf/verifier: prevent non GPL programs to be loaded against HID Benjamin Tissoires
2022-03-18 20:51   ` Song Liu
2022-03-18 16:15 ` [PATCH bpf-next v3 04/17] libbpf: add HID program type and API Benjamin Tissoires
2022-03-18 20:53   ` Song Liu
2022-03-18 16:15 ` [PATCH bpf-next v3 05/17] HID: hook up with bpf Benjamin Tissoires
2022-03-18 21:02   ` Song Liu
2022-03-18 21:04     ` Song Liu
2022-03-18 16:15 ` [PATCH bpf-next v3 06/17] HID: allow to change the report descriptor from an eBPF program Benjamin Tissoires
2022-03-18 21:10   ` Song Liu
2022-03-21 16:20     ` Benjamin Tissoires
2022-03-21 22:03       ` Song Liu
2022-03-22 22:51   ` Alexei Starovoitov
2022-03-23 16:08     ` Benjamin Tissoires
2022-03-25 17:00       ` Andrii Nakryiko
2022-03-28  6:56         ` Benjamin Tissoires
2022-03-28 21:35           ` Andrii Nakryiko
2022-03-29 13:53             ` Benjamin Tissoires
2022-04-01 13:21               ` Benjamin Tissoires
2022-03-30 21:27       ` Alexei Starovoitov
2022-03-18 16:15 ` [PATCH bpf-next v3 07/17] selftests/bpf: add tests for the HID-bpf initial implementation Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 08/17] selftests/bpf: add report descriptor fixup tests Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 09/17] selftests/bpf: Add a test for BPF_F_INSERT_HEAD Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 10/17] selftests/bpf: add test for user call of HID bpf programs Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 11/17] samples/bpf: add new hid_mouse example Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 12/17] bpf/hid: add more HID helpers Benjamin Tissoires
2022-03-18 21:19   ` Song Liu
2022-03-21 16:24     ` Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 13/17] HID: bpf: implement hid_bpf_get|set_bits Benjamin Tissoires
2022-03-18 21:20   ` Song Liu
2022-03-18 16:15 ` [PATCH bpf-next v3 14/17] HID: add implementation of bpf_hid_raw_request Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 15/17] selftests/bpf: add tests for hid_{get|set}_bits helpers Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 16/17] selftests/bpf: add tests for bpf_hid_hw_request Benjamin Tissoires
2022-03-18 16:15 ` [PATCH bpf-next v3 17/17] Documentation: add HID-BPF docs Benjamin Tissoires
2022-03-18 18:05   ` Song Liu
2022-03-29 13:04 ` [PATCH bpf-next v3 00/17] Introduce eBPF support for HID devices Tero Kristo
2022-04-01  9:37   ` Benjamin Tissoires

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAO-hwJ+WSi645HhNV_BYACoJe2UTc4KZzqH0oHocfnBR8xUYEQ@mail.gmail.com \
    --to=benjamin.tissoires@redhat.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=corbet@lwn.net \
    --cc=daniel@iogearbox.net \
    --cc=davemarchevsky@fb.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jikos@kernel.org \
    --cc=joe@cilium.io \
    --cc=john.fastabend@gmail.com \
    --cc=kafai@fb.com \
    --cc=kpsingh@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=shuah@kernel.org \
    --cc=song@kernel.org \
    --cc=songliubraving@fb.com \
    --cc=tero.kristo@linux.intel.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).