2424#include <net/netdev_rx_queue.h>
2525#include <net/xdp.h>
2626#include <net/netfilter/nf_bpf_link.h>
27+ #include <linux/set_memory.h>
2728
2829#define CREATE_TRACE_POINTS
2930#include <trace/events/bpf_test_run.h>
@@ -563,6 +564,41 @@ noinline int bpf_fentry_test10(const void *a)
563564 return (long )a ;
564565}
565566
567+ struct bpf_fentry_test_dptr_t {
568+ int value ;
569+ };
570+
571+ /* Test fentry/fexit with nullable double pointer parameter */
572+ noinline int bpf_fentry_test11_double_ptr_nullable (struct bpf_fentry_test_dptr_t * * dptr__nullable )
573+ {
574+ if (!dptr__nullable ) {
575+ return -1 ;
576+ }
577+
578+ return (* dptr__nullable )-> value ;
579+ }
580+
581+ /* Test fentry/fexit with non-nullable double pointer parameter */
582+ noinline int bpf_fentry_test12_double_ptr (struct bpf_fentry_test_dptr_t * * dptr )
583+ {
584+ return (long )dptr ;
585+ }
586+
587+ /* Test fentry/fexit with void double pointer parameter and address validation */
588+ noinline int bpf_fentry_test13_void_double_ptr (void * * dptr )
589+ {
590+ return virt_addr_valid (dptr );
591+ }
592+
593+ /* Test fentry/fexit with void triple pointer parameter. The volatile specifier
594+ * doesn't affect function parameter behavior, but it is retained in the BTF type
595+ * descriptor, forcing the verifier to walk through the type modifier chain.
596+ */
597+ noinline int bpf_fentry_test14_void_triple_ptr (void * * const * volatile dptr )
598+ {
599+ return (long )dptr ;
600+ }
601+
566602noinline void bpf_fentry_test_sinfo (struct skb_shared_info * sinfo )
567603{
568604}
@@ -670,18 +706,103 @@ static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,
670706 return data ;
671707}
672708
709+ /* Create a guaranteed-invalid address for testing copy_from_kernel_nofault.
710+ * Returns a valid pointer to memory that has been made non-present,
711+ * so any access will fault. Must be freed with free_invalid_test_address().
712+ */
713+ static void * create_invalid_test_address (void )
714+ {
715+ #if defined(CONFIG_ARCH_HAS_SET_MEMORY ) && \
716+ (defined(CONFIG_X86 ) || defined(CONFIG_PPC ))
717+ void * addr ;
718+
719+ addr = vmalloc (PAGE_SIZE );
720+ if (!addr )
721+ return NULL ;
722+
723+ /* Make it non-present - any access will fault */
724+ if (set_memory_np ((unsigned long )addr , 1 )) {
725+ vfree (addr );
726+ return NULL ;
727+ }
728+
729+ return addr ;
730+ #elif defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP )
731+ struct page * page ;
732+
733+ page = alloc_page (GFP_KERNEL );
734+ if (!page )
735+ return NULL ;
736+
737+ /* Remove from direct map - any access will fault */
738+ if (set_direct_map_invalid_noflush (page )) {
739+ __free_page (page );
740+ return NULL ;
741+ }
742+ flush_tlb_kernel_range ((unsigned long )page_address (page ),
743+ (unsigned long )page_address (page ) + PAGE_SIZE );
744+
745+ return page_address (page );
746+ #else
747+ /* Fallback: return a canonical invalid address.
748+ * On 64-bit: middle of address space (non-canonical hole on x86-64).
749+ * On 32-bit: high user address unlikely to be mapped.
750+ * This is just a number, not allocated memory.
751+ */
752+ if (!virt_addr_valid (VMALLOC_END + 0x1000 ))
753+ return VMALLOC_END + 0x1000 ;
754+ else
755+ #ifdef CONFIG_64BIT
756+ return (void * )0x0010000000000000UL ;
757+ #else
758+ return (void * )0xA0000000UL ;
759+ #endif
760+ #endif
761+ }
762+
763+ /* Free an invalid test address created by create_invalid_test_address().
764+ * Restores the page to present state before freeing.
765+ */
766+ static void free_invalid_test_address (void * addr )
767+ {
768+ if (!addr )
769+ return ;
770+
771+ #if defined(CONFIG_ARCH_HAS_SET_MEMORY ) && \
772+ (defined(CONFIG_X86 ) || defined(CONFIG_PPC ))
773+ set_memory_p ((unsigned long )addr , 1 );
774+ vfree (addr );
775+ #elif defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP )
776+ struct page * page = virt_to_page (addr );
777+
778+ set_direct_map_default_noflush (page );
779+ flush_tlb_kernel_range ((unsigned long )addr ,
780+ (unsigned long )addr + PAGE_SIZE );
781+ __free_page (page );
782+ #else
783+ /* Fallback case: addr is just a constant, nothing to free */
784+ #endif
785+ }
786+
673787int bpf_prog_test_run_tracing (struct bpf_prog * prog ,
674788 const union bpf_attr * kattr ,
675789 union bpf_attr __user * uattr )
676790{
677791 struct bpf_fentry_test_t arg = {};
792+ struct bpf_fentry_test_dptr_t dptr_struct = { .value = 1979 };
793+ struct bpf_fentry_test_dptr_t * dptr_ptr = & dptr_struct ;
794+ void * invalid_addr ;
678795 u16 side_effect = 0 , ret = 0 ;
679796 int b = 2 , err = - EFAULT ;
680797 u32 retval = 0 ;
681798
682799 if (kattr -> test .flags || kattr -> test .cpu || kattr -> test .batch_size )
683800 return - EINVAL ;
684801
802+ invalid_addr = create_invalid_test_address ();
803+ if (!invalid_addr )
804+ return - ENOMEM ;
805+
685806 switch (prog -> expected_attach_type ) {
686807 case BPF_TRACE_FENTRY :
687808 case BPF_TRACE_FEXIT :
@@ -695,7 +816,13 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
695816 bpf_fentry_test7 ((struct bpf_fentry_test_t * )0 ) != 0 ||
696817 bpf_fentry_test8 (& arg ) != 0 ||
697818 bpf_fentry_test9 (& retval ) != 0 ||
698- bpf_fentry_test10 ((void * )0 ) != 0 )
819+ bpf_fentry_test10 ((void * )0 ) != 0 ||
820+ bpf_fentry_test11_double_ptr_nullable (& dptr_ptr ) != 1979 ||
821+ bpf_fentry_test12_double_ptr ((struct bpf_fentry_test_dptr_t * * )17 ) != 17 ||
822+ bpf_fentry_test13_void_double_ptr ((void * * )19 ) != virt_addr_valid ((void * )19 ) ||
823+ bpf_fentry_test13_void_double_ptr ((void * * )invalid_addr ) != virt_addr_valid (invalid_addr ) ||
824+ bpf_fentry_test13_void_double_ptr ((void * * )ERR_PTR (- ENOMEM )) != virt_addr_valid (ERR_PTR (- ENOMEM )) ||
825+ bpf_fentry_test14_void_triple_ptr ((void * * const * volatile )ERR_PTR (- ENOMEM )) != (int )(long )ERR_PTR (- ENOMEM ))
699826 goto out ;
700827 break ;
701828 case BPF_MODIFY_RETURN :
@@ -717,6 +844,7 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
717844
718845 err = 0 ;
719846out :
847+ free_invalid_test_address (invalid_addr );
720848 trace_bpf_test_finish (& err );
721849 return err ;
722850}
0 commit comments