Re: [PATCH bpf-next v4 3/3] selftests/bpf: Add tests for arena fault reporting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 27 Aug 2025 at 21:55, Yonghong Song <yonghong.song@xxxxxxxxx> wrote:
>
>
>
> On 8/27/25 8:37 AM, Puranjay Mohan wrote:
> > Add selftests for testing the reporting of arena page faults through BPF
> > streams. Two new bpf programs are added that read and write to an
> > unmapped arena address and the fault reporting is verified in the
> > userspace through streams.
> >
> > Signed-off-by: Puranjay Mohan <puranjay@xxxxxxxxxx>
> > ---
> >   .../testing/selftests/bpf/prog_tests/stream.c | 33 +++++++++++++++-
> >   tools/testing/selftests/bpf/progs/stream.c    | 39 +++++++++++++++++++
> >   2 files changed, 71 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/testing/selftests/bpf/prog_tests/stream.c b/tools/testing/selftests/bpf/prog_tests/stream.c
> > index 36a1a1ebde692..8fdc83260ea14 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/stream.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/stream.c
> > @@ -41,6 +41,22 @@ struct {
> >               "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> >               "|[ \t]+[^\n]+\n)*",
> >       },
> > +     {
> > +             offsetof(struct stream, progs.stream_arena_read_fault),
> > +             "ERROR: Arena READ access at unmapped address 0x.*\n"
> > +             "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
> > +             "Call trace:\n"
> > +             "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> > +             "|[ \t]+[^\n]+\n)*",
> > +     },
> > +     {
> > +             offsetof(struct stream, progs.stream_arena_write_fault),
> > +             "ERROR: Arena WRITE access at unmapped address 0x.*\n"
> > +             "CPU: [0-9]+ UID: 0 PID: [0-9]+ Comm: .*\n"
> > +             "Call trace:\n"
> > +             "([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
> > +             "|[ \t]+[^\n]+\n)*",
> > +     },
> >   };
> >
> >   static int match_regex(const char *pattern, const char *string)
> > @@ -63,6 +79,7 @@ void test_stream_errors(void)
> >       struct stream *skel;
> >       int ret, prog_fd;
> >       char buf[1024];
> > +     char fault_addr[64] = {0};
>
> You can replace '{0}' to '{}' so the whole array will be initialized.
>
> >
> >       skel = stream__open_and_load();
> >       if (!ASSERT_OK_PTR(skel, "stream__open_and_load"))
> > @@ -85,6 +102,14 @@ void test_stream_errors(void)
> >                       continue;
> >               }
> >   #endif
> > +#if !defined(__x86_64__) && !defined(__aarch64__)
> > +             ASSERT_TRUE(1, "Arena fault reporting unsupported, skip.");
> > +             if (i == 2 || i == 3) {
> > +                     ret = bpf_prog_stream_read(prog_fd, 2, buf, sizeof(buf), &ropts);
> > +                     ASSERT_EQ(ret, 0, "stream read");
> > +                     continue;
> > +             }
> > +#endif
> >
> >               ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, buf, sizeof(buf), &ropts);
> >               ASSERT_GT(ret, 0, "stream read");
> > @@ -92,8 +117,14 @@ void test_stream_errors(void)
> >               buf[ret] = '\0';
> >
> >               ret = match_regex(stream_error_arr[i].errstr, buf);
> > -             if (!ASSERT_TRUE(ret == 1, "regex match"))
> > +             if (ret && (i == 2 || i == 3)) {
> > +                     sprintf(fault_addr, "0x%lx", skel->bss->fault_addr);
> > +                     ret = match_regex(fault_addr, buf);
> > +             }
> > +             if (!ASSERT_TRUE(ret == 1, "regex match")) {
> >                       fprintf(stderr, "Output from stream:\n%s\n", buf);
> > +                     fprintf(stderr, "Fault Addr: 0x%lx\n", skel->bss->fault_addr);
>
> This will fault addr even for i == 0 or i == 1 and those address may be confusing
> for test 0/1.
>
> > +             }
> >       }
> >
> >       stream__destroy(skel);
> > diff --git a/tools/testing/selftests/bpf/progs/stream.c b/tools/testing/selftests/bpf/progs/stream.c
> > index 35790897dc879..9de015ac3ced5 100644
> > --- a/tools/testing/selftests/bpf/progs/stream.c
> > +++ b/tools/testing/selftests/bpf/progs/stream.c
> > @@ -5,6 +5,7 @@
> >   #include <bpf/bpf_helpers.h>
> >   #include "bpf_misc.h"
> >   #include "bpf_experimental.h"
> > +#include "bpf_arena_common.h"
> >
> >   struct arr_elem {
> >       struct bpf_res_spin_lock lock;
> > @@ -17,10 +18,17 @@ struct {
> >       __type(value, struct arr_elem);
> >   } arrmap SEC(".maps");
> >
> > +struct {
> > +     __uint(type, BPF_MAP_TYPE_ARENA);
> > +     __uint(map_flags, BPF_F_MMAPABLE);
> > +     __uint(max_entries, 1); /* number of pages */
> > +} arena SEC(".maps");
> > +
> >   #define ENOSPC 28
> >   #define _STR "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
> >
> >   int size;
> > +u64 fault_addr;
> >
> >   SEC("syscall")
> >   __success __retval(0)
> > @@ -76,4 +84,35 @@ int stream_syscall(void *ctx)
> >       return 0;
> >   }
> >
> > +SEC("syscall")
> > +__success __retval(0)
> > +int stream_arena_write_fault(void *ctx)
> > +{
> > +     struct bpf_arena *ptr = (void *)&arena;
> > +     u64 user_vm_start;
> > +
> > +     barrier_var(ptr);
>
> Do we need this barrier_var()? I tried llvm20 and it works fine without the
> above barrier_var().

Puranjay should add some context in the commit log or comments for
this, but I think the reason was that we found that GCC would diagnose
accesses into ptr assuming it points into the actual typeof(arena)
object defined in the C file (which is the right thing to do from a
language standpoint), but that obviously leads to misdiagnosis once we
access something in struct bpf_arena that goes out of bounds for this
type. So laundering the pointer through barrier_var gets rid of the
provenance information and the warning/error is gone.

But it would be better to add a comment since it's not obvious why.

>
> > +     user_vm_start =  ptr->user_vm_start;
> > +
>
> Remove this line.
>
> > +     fault_addr = user_vm_start + 0xbeef;
> > +     *(u32 __arena *)(user_vm_start + 0xbeef) = 1;
>
> Simplify to *(u32 __arena *)fault = 1;
>
> > +
>
> Remove this line.
>
> > +     return 0;
> > +}
> > +
> > +SEC("syscall")
> > +__success __retval(0)
> > +int stream_arena_read_fault(void *ctx)
> > +{
> > +     struct bpf_arena *ptr = (void *)&arena;
> > +     u64 user_vm_start;
> > +
> > +     barrier_var(ptr);
>
> Is this necessary?
>
> > +     user_vm_start =  ptr->user_vm_start;
> > +
>
> Remove this line.
>
> > +     fault_addr = user_vm_start + 0xbeef;
> > +
>
> Remove this line.
>
> > +     return *(u32 __arena *)(user_vm_start + 0xbeef);
>
> return*(u32 __arena *)fault_addr.
>
> > +}
> > +
> >   char _license[] SEC("license") = "GPL";
>




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux