On Mon, Feb 23, 2026 at 12:32 AM Slava Imameev
<[email protected]> wrote:
>
> Multi-level pointer params and return value test coverage for BPF
> trampolines:
> - fentry/fexit programs covering struct and void double/triple
>   pointer parameters and returned values
> - verifier context tests covering multi-level pointers as parameters
> - verifier context tests covering multi-level pointers as returned
>   values
> - verifier context tests for lsm to check trusted parameters handling
> - verifier context tests covering out-of-bound access after cast
> - verifier BPF helper tests to validate no change in verifier
>   behaviour
>
> Signed-off-by: Slava Imameev <[email protected]>
> ---
>  net/bpf/test_run.c                            | 130 ++++++
>  .../prog_tests/fentry_fexit_multi_level_ptr.c | 206 +++++++++
>  .../selftests/bpf/prog_tests/verifier.c       |   2 +
>  .../progs/fentry_fexit_pptr_nullable_test.c   |  56 +++
>  .../bpf/progs/fentry_fexit_pptr_test.c        |  67 +++
>  .../bpf/progs/fentry_fexit_void_ppptr_test.c  |  38 ++
>  .../bpf/progs/fentry_fexit_void_pptr_test.c   |  71 +++
>  .../bpf/progs/verifier_ctx_multilevel_ptr.c   | 435 ++++++++++++++++++
>  8 files changed, 1005 insertions(+)
>  create mode 100644 
> tools/testing/selftests/bpf/prog_tests/fentry_fexit_multi_level_ptr.c
>  create mode 100644 
> tools/testing/selftests/bpf/progs/fentry_fexit_pptr_nullable_test.c
>  create mode 100644 tools/testing/selftests/bpf/progs/fentry_fexit_pptr_test.c
>  create mode 100644 
> tools/testing/selftests/bpf/progs/fentry_fexit_void_ppptr_test.c
>  create mode 100644 
> tools/testing/selftests/bpf/progs/fentry_fexit_void_pptr_test.c
>  create mode 100644 
> tools/testing/selftests/bpf/progs/verifier_ctx_multilevel_ptr.c
>
> diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
> index 178c4738e63b..9f6ee2eb01cd 100644
> --- a/net/bpf/test_run.c
> +++ b/net/bpf/test_run.c
> @@ -24,6 +24,9 @@
>  #include <net/netdev_rx_queue.h>
>  #include <net/xdp.h>
>  #include <net/netfilter/nf_bpf_link.h>
> +#include <linux/set_memory.h>
> +#include <linux/string.h>
> +#include <asm/tlbflush.h>
>
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/bpf_test_run.h>
> @@ -563,6 +566,42 @@ noinline int bpf_fentry_test10(const void *a)
>         return (long)a;
>  }
>
> +struct bpf_fentry_test_pptr_t {
> +       u32 value1;
> +       u32 value2;
> +};
> +
> +noinline int bpf_fentry_test11_pptr_nullable(struct bpf_fentry_test_pptr_t 
> **pptr__nullable)
> +{
> +       if (!pptr__nullable)
> +               return -1;
> +
> +       return (*pptr__nullable)->value1;
> +}
> +
> +noinline u32 **bpf_fentry_test12_pptr(u32 id, u32 **pptr)
> +{
> +       /* prevent DCE */
> +       asm volatile("" : "+r"(id));
> +       asm volatile("" : "+r"(pptr));
> +       return pptr;
> +}
> +
> +noinline u8 bpf_fentry_test13_pptr(void **pptr)
> +{
> +       void *ptr;
> +
> +       return copy_from_kernel_nofault(&ptr, pptr, sizeof(pptr)) == 0;
> +}
> +
> +/* Test the verifier can handle multi-level pointer types with qualifiers. */
> +noinline void ***bpf_fentry_test14_ppptr(void **volatile *const ppptr)
> +{
> +       /* prevent DCE */
> +       asm volatile("" :: "r"(ppptr) : "memory");
> +       return (void ***)ppptr;
> +}
> +
>  noinline void bpf_fentry_test_sinfo(struct skb_shared_info *sinfo)
>  {
>  }
> @@ -670,20 +709,110 @@ static void *bpf_test_init(const union bpf_attr 
> *kattr, u32 user_size,
>         return data;
>  }
>
> +static void *create_bad_kaddr(void)
> +{
> +       /*
> +        * Try to get an address that passes kernel range checks but causes
> +        * a page fault handler invocation if accessed from a BPF program.
> +        */
> +#if defined(CONFIG_ARCH_HAS_SET_MEMORY) && defined(CONFIG_X86)
> +       void *addr = vmalloc(PAGE_SIZE);
> +
> +       if (!addr)
> +               return NULL;
> +       /* Make it non-present - any access will fault */
> +       if (set_memory_np((unsigned long)addr, 1)) {
> +               vfree(addr);
> +               return NULL;
> +       }
> +       return addr;
> +#elif defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP)
> +       struct page *page = alloc_page(GFP_KERNEL);
> +
> +       if (!page)
> +               return NULL;
> +       /* Remove from direct map - any access will fault */
> +       if (set_direct_map_invalid_noflush(page)) {
> +               __free_page(page);
> +               return NULL;
> +       }
> +       flush_tlb_kernel_range((unsigned long)page_address(page),
> +                              (unsigned long)page_address(page) + PAGE_SIZE);
> +       return page_address(page);
> +#endif

This is serious overkill for a test.
See how bpf_testmod_return_ptr() does it.

pw-bot: cr

Reply via email to