mbox series

[bpf-next,v1,0/7] Dynamic pointers

Message ID 20220402015826.3941317-1-joannekoong@fb.com (mailing list archive)
Headers show
Series Dynamic pointers | expand

Message

Joanne Koong April 2, 2022, 1:58 a.m. UTC
From: Joanne Koong <joannelkoong@gmail.com>

This patchset implements the basics of dynamic pointers in bpf.

A dynamic pointer (struct bpf_dynptr) is a pointer that stores extra metadata
alongside the address it points to. This abstraction is useful in bpf, given
that every memory access in a bpf program must be safe. The verifier and bpf
helper functions can use the metadata to enforce safety guarantees for things 
such as dynamically sized strings and kernel heap allocations.

From the program side, the bpf_dynptr is an opaque struct and the verifier
will enforce that its contents are never written to by the program.
It can only be written to through specific bpf helper functions.

There are several uses cases for dynamic pointers in bpf programs. A list of
some are: dynamically sized ringbuf reservations without any extra memcpys,
dynamic string parsing and memory comparisons, dynamic memory allocations that
can be persisted in a map, and dynamic parsing of sk_buff and xdp_md packet
data.

At a high-level, the patches are as follows:
1/7 - Adds MEM_UNINIT as a bpf_type_flag
2/7 - Adds MEM_RELEASE as a bpf_type_flag
3/7 - Adds bpf_dynptr_from_mem, bpf_malloc, and bpf_free
4/7 - Adds bpf_dynptr_read and bpf_dynptr_write
5/7 - Adds dynptr data slices (ptr to underlying dynptr memory)
6/7 - Adds dynptr support for ring buffers
7/7 - Tests to check that verifier rejects certain fail cases and passes
certain success cases

This is the first dynptr patchset in a larger series. The next series of
patches will add persisting dynamic memory allocations in maps, parsing packet
data through dynptrs, dynptrs to referenced objects, convenience helpers for
using dynptrs as iterators, and more helper functions for interacting with
strings and memory dynamically.

Joanne Koong (7):
  bpf: Add MEM_UNINIT as a bpf_type_flag
  bpf: Add MEM_RELEASE as a bpf_type_flag
  bpf: Add bpf_dynptr_from_mem, bpf_malloc, bpf_free
  bpf: Add bpf_dynptr_read and bpf_dynptr_write
  bpf: Add dynptr data slices
  bpf: Dynptr support for ring buffers
  bpf: Dynptr tests

 include/linux/bpf.h                           | 107 +++-
 include/linux/bpf_verifier.h                  |  23 +-
 include/uapi/linux/bpf.h                      | 100 ++++
 kernel/bpf/bpf_lsm.c                          |   4 +-
 kernel/bpf/btf.c                              |   3 +-
 kernel/bpf/cgroup.c                           |   4 +-
 kernel/bpf/helpers.c                          | 190 ++++++-
 kernel/bpf/ringbuf.c                          |  75 ++-
 kernel/bpf/stackmap.c                         |   6 +-
 kernel/bpf/verifier.c                         | 406 ++++++++++++--
 kernel/trace/bpf_trace.c                      |  20 +-
 net/core/filter.c                             |  28 +-
 scripts/bpf_doc.py                            |   2 +
 tools/include/uapi/linux/bpf.h                | 100 ++++
 .../testing/selftests/bpf/prog_tests/dynptr.c | 303 ++++++++++
 .../testing/selftests/bpf/progs/dynptr_fail.c | 527 ++++++++++++++++++
 .../selftests/bpf/progs/dynptr_success.c      | 147 +++++
 17 files changed, 1955 insertions(+), 90 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/dynptr.c
 create mode 100644 tools/testing/selftests/bpf/progs/dynptr_fail.c
 create mode 100644 tools/testing/selftests/bpf/progs/dynptr_success.c

Comments

Andrii Nakryiko April 6, 2022, 11:13 p.m. UTC | #1
On Fri, Apr 1, 2022 at 6:59 PM Joanne Koong <joannekoong@fb.com> wrote:
>
> From: Joanne Koong <joannelkoong@gmail.com>
>
> This patchset implements the basics of dynamic pointers in bpf.
>
> A dynamic pointer (struct bpf_dynptr) is a pointer that stores extra metadata
> alongside the address it points to. This abstraction is useful in bpf, given
> that every memory access in a bpf program must be safe. The verifier and bpf
> helper functions can use the metadata to enforce safety guarantees for things
> such as dynamically sized strings and kernel heap allocations.
>
> From the program side, the bpf_dynptr is an opaque struct and the verifier
> will enforce that its contents are never written to by the program.
> It can only be written to through specific bpf helper functions.
>
> There are several uses cases for dynamic pointers in bpf programs. A list of
> some are: dynamically sized ringbuf reservations without any extra memcpys,
> dynamic string parsing and memory comparisons, dynamic memory allocations that
> can be persisted in a map, and dynamic parsing of sk_buff and xdp_md packet
> data.
>
> At a high-level, the patches are as follows:
> 1/7 - Adds MEM_UNINIT as a bpf_type_flag
> 2/7 - Adds MEM_RELEASE as a bpf_type_flag
> 3/7 - Adds bpf_dynptr_from_mem, bpf_malloc, and bpf_free
> 4/7 - Adds bpf_dynptr_read and bpf_dynptr_write
> 5/7 - Adds dynptr data slices (ptr to underlying dynptr memory)
> 6/7 - Adds dynptr support for ring buffers
> 7/7 - Tests to check that verifier rejects certain fail cases and passes
> certain success cases
>
> This is the first dynptr patchset in a larger series. The next series of
> patches will add persisting dynamic memory allocations in maps, parsing packet
> data through dynptrs, dynptrs to referenced objects, convenience helpers for
> using dynptrs as iterators, and more helper functions for interacting with
> strings and memory dynamically.
>
> Joanne Koong (7):
>   bpf: Add MEM_UNINIT as a bpf_type_flag
>   bpf: Add MEM_RELEASE as a bpf_type_flag
>   bpf: Add bpf_dynptr_from_mem, bpf_malloc, bpf_free
>   bpf: Add bpf_dynptr_read and bpf_dynptr_write
>   bpf: Add dynptr data slices
>   bpf: Dynptr support for ring buffers
>   bpf: Dynptr tests
>
>  include/linux/bpf.h                           | 107 +++-
>  include/linux/bpf_verifier.h                  |  23 +-
>  include/uapi/linux/bpf.h                      | 100 ++++
>  kernel/bpf/bpf_lsm.c                          |   4 +-
>  kernel/bpf/btf.c                              |   3 +-
>  kernel/bpf/cgroup.c                           |   4 +-
>  kernel/bpf/helpers.c                          | 190 ++++++-
>  kernel/bpf/ringbuf.c                          |  75 ++-
>  kernel/bpf/stackmap.c                         |   6 +-
>  kernel/bpf/verifier.c                         | 406 ++++++++++++--
>  kernel/trace/bpf_trace.c                      |  20 +-
>  net/core/filter.c                             |  28 +-
>  scripts/bpf_doc.py                            |   2 +
>  tools/include/uapi/linux/bpf.h                | 100 ++++
>  .../testing/selftests/bpf/prog_tests/dynptr.c | 303 ++++++++++
>  .../testing/selftests/bpf/progs/dynptr_fail.c | 527 ++++++++++++++++++
>  .../selftests/bpf/progs/dynptr_success.c      | 147 +++++
>  17 files changed, 1955 insertions(+), 90 deletions(-)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/dynptr.c
>  create mode 100644 tools/testing/selftests/bpf/progs/dynptr_fail.c
>  create mode 100644 tools/testing/selftests/bpf/progs/dynptr_success.c
>

KP, Florent, Brendan,

You always wanted a way to work with runtime-sized BPF ringbuf samples
without extra copies. This is the way we can finally do this with good
usability and simplicity. Please take a look and provide feedback.
Thanks!

> --
> 2.30.2
>
Brendan Jackman April 7, 2022, 12:44 p.m. UTC | #2
On Thu, 7 Apr 2022 at 01:13, Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
>
> On Fri, Apr 1, 2022 at 6:59 PM Joanne Koong <joannekoong@fb.com> wrote:
> >
> > From: Joanne Koong <joannelkoong@gmail.com>
> KP, Florent, Brendan,
>
> You always wanted a way to work with runtime-sized BPF ringbuf samples
> without extra copies. This is the way we can finally do this with good
> usability and simplicity. Please take a look and provide feedback.
> Thanks!

Thanks folks, this looks very cool. Please excuse my ignorance, one
thing that isn't clear to me is does this work for user memory? Or
would we need bpf_copy_from_user_dynptr to avoid an extra copy?
Joanne Koong April 7, 2022, 8:40 p.m. UTC | #3
On Thu, Apr 7, 2022 at 5:44 AM Brendan Jackman <jackmanb@google.com> wrote:
>
> On Thu, 7 Apr 2022 at 01:13, Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
> >
> > On Fri, Apr 1, 2022 at 6:59 PM Joanne Koong <joannekoong@fb.com> wrote:
> > >
> > > From: Joanne Koong <joannelkoong@gmail.com>
> > KP, Florent, Brendan,
> >
> > You always wanted a way to work with runtime-sized BPF ringbuf samples
> > without extra copies. This is the way we can finally do this with good
> > usability and simplicity. Please take a look and provide feedback.
> > Thanks!
>
> Thanks folks, this looks very cool. Please excuse my ignorance, one
> thing that isn't clear to me is does this work for user memory? Or
> would we need bpf_copy_from_user_dynptr to avoid an extra copy?

Userspace programs will not be able to use or interact with dynptrs
directly. If there is data at a user-space address that needs to be
copied into the ringbuffer, the address can be passed to the bpf
program and then the bpf program can use a helper like
bpf_probe_read_user_dynptr (not added in this patchset but will be
part of a following one), which will read the contents at that user
address into the ringbuf dynptr.
Brendan Jackman April 8, 2022, 10:21 a.m. UTC | #4
On Thu, 7 Apr 2022 at 22:40, Joanne Koong <joannelkoong@gmail.com> wrote:
>
> On Thu, Apr 7, 2022 at 5:44 AM Brendan Jackman <jackmanb@google.com> wrote:
> >
> > On Thu, 7 Apr 2022 at 01:13, Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
> > >
> > > On Fri, Apr 1, 2022 at 6:59 PM Joanne Koong <joannekoong@fb.com> wrote:
> > > >
> > > > From: Joanne Koong <joannelkoong@gmail.com>
> > > KP, Florent, Brendan,
> > >
> > > You always wanted a way to work with runtime-sized BPF ringbuf samples
> > > without extra copies. This is the way we can finally do this with good
> > > usability and simplicity. Please take a look and provide feedback.
> > > Thanks!
> >
> > Thanks folks, this looks very cool. Please excuse my ignorance, one
> > thing that isn't clear to me is does this work for user memory? Or
> > would we need bpf_copy_from_user_dynptr to avoid an extra copy?
>
> Userspace programs will not be able to use or interact with dynptrs
> directly. If there is data at a user-space address that needs to be
> copied into the ringbuffer, the address can be passed to the bpf
> program and then the bpf program can use a helper like
> bpf_probe_read_user_dynptr (not added in this patchset but will be
> part of a following one), which will read the contents at that user
> address into the ringbuf dynptr.

Ah yeah right, this is not for userspace programs just programs in the
kernel that need to read user memory; the specific case I'm thinking
of is reading the argv/env from the exec path.
bpf_probe_read_user_dynptr sounds for sure like it would solve that
case.