2022-03-15 17:02:35 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* test_fprobe . c - simple sanity test for fprobe
*/
# include <linux/kernel.h>
# include <linux/fprobe.h>
# include <linux/random.h>
# include <kunit/test.h>
# define div_factor 3
static struct kunit * current_test ;
static u32 rand1 , entry_val , exit_val ;
/* Use indirect calls to avoid inlining the target functions */
static u32 ( * target ) ( u32 value ) ;
static u32 ( * target2 ) ( u32 value ) ;
2023-02-01 18:56:28 +03:00
static u32 ( * target_nest ) ( u32 value , u32 ( * nest ) ( u32 ) ) ;
2022-03-15 17:02:35 +03:00
static unsigned long target_ip ;
static unsigned long target2_ip ;
2023-02-01 18:56:28 +03:00
static unsigned long target_nest_ip ;
2023-02-01 18:56:46 +03:00
static int entry_return_value ;
2022-03-15 17:02:35 +03:00
static noinline u32 fprobe_selftest_target ( u32 value )
{
return ( value / div_factor ) ;
}
static noinline u32 fprobe_selftest_target2 ( u32 value )
{
return ( value / div_factor ) + 1 ;
}
2023-02-01 18:56:28 +03:00
static noinline u32 fprobe_selftest_nest_target ( u32 value , u32 ( * nest ) ( u32 ) )
{
return nest ( value + 2 ) ;
}
2023-02-01 18:56:38 +03:00
static notrace int fp_entry_handler ( struct fprobe * fp , unsigned long ip ,
2023-06-06 15:39:55 +03:00
unsigned long ret_ip ,
struct pt_regs * regs , void * data )
2022-03-15 17:02:35 +03:00
{
KUNIT_EXPECT_FALSE ( current_test , preemptible ( ) ) ;
/* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
if ( ip ! = target_ip )
KUNIT_EXPECT_EQ ( current_test , ip , target2_ip ) ;
entry_val = ( rand1 / div_factor ) ;
2023-02-01 18:56:10 +03:00
if ( fp - > entry_data_size ) {
KUNIT_EXPECT_NOT_NULL ( current_test , data ) ;
if ( data )
* ( u32 * ) data = entry_val ;
} else
KUNIT_EXPECT_NULL ( current_test , data ) ;
2023-02-01 18:56:38 +03:00
2023-02-01 18:56:46 +03:00
return entry_return_value ;
2022-03-15 17:02:35 +03:00
}
2023-02-01 18:56:01 +03:00
static notrace void fp_exit_handler ( struct fprobe * fp , unsigned long ip ,
2023-06-06 15:39:55 +03:00
unsigned long ret_ip ,
2023-02-01 18:56:01 +03:00
struct pt_regs * regs , void * data )
2022-03-15 17:02:35 +03:00
{
unsigned long ret = regs_return_value ( regs ) ;
KUNIT_EXPECT_FALSE ( current_test , preemptible ( ) ) ;
if ( ip ! = target_ip ) {
KUNIT_EXPECT_EQ ( current_test , ip , target2_ip ) ;
KUNIT_EXPECT_EQ ( current_test , ret , ( rand1 / div_factor ) + 1 ) ;
} else
KUNIT_EXPECT_EQ ( current_test , ret , ( rand1 / div_factor ) ) ;
KUNIT_EXPECT_EQ ( current_test , entry_val , ( rand1 / div_factor ) ) ;
exit_val = entry_val + div_factor ;
2023-02-01 18:56:10 +03:00
if ( fp - > entry_data_size ) {
KUNIT_EXPECT_NOT_NULL ( current_test , data ) ;
if ( data )
KUNIT_EXPECT_EQ ( current_test , * ( u32 * ) data , entry_val ) ;
} else
KUNIT_EXPECT_NULL ( current_test , data ) ;
2022-03-15 17:02:35 +03:00
}
2023-02-01 18:56:38 +03:00
static notrace int nest_entry_handler ( struct fprobe * fp , unsigned long ip ,
2023-06-06 15:39:55 +03:00
unsigned long ret_ip ,
struct pt_regs * regs , void * data )
2023-02-01 18:56:28 +03:00
{
KUNIT_EXPECT_FALSE ( current_test , preemptible ( ) ) ;
2023-02-01 18:56:38 +03:00
return 0 ;
2023-02-01 18:56:28 +03:00
}
static notrace void nest_exit_handler ( struct fprobe * fp , unsigned long ip ,
2023-06-06 15:39:55 +03:00
unsigned long ret_ip ,
struct pt_regs * regs , void * data )
2023-02-01 18:56:28 +03:00
{
KUNIT_EXPECT_FALSE ( current_test , preemptible ( ) ) ;
KUNIT_EXPECT_EQ ( current_test , ip , target_nest_ip ) ;
2022-03-15 17:02:35 +03:00
}
/* Test entry only (no rethook) */
static void test_fprobe_entry ( struct kunit * test )
{
struct fprobe fp_entry = {
. entry_handler = fp_entry_handler ,
} ;
current_test = test ;
/* Before register, unregister should be failed. */
KUNIT_EXPECT_NE ( test , 0 , unregister_fprobe ( & fp_entry ) ) ;
KUNIT_EXPECT_EQ ( test , 0 , register_fprobe ( & fp_entry , " fprobe_selftest_target* " , NULL ) ) ;
entry_val = 0 ;
exit_val = 0 ;
target ( rand1 ) ;
KUNIT_EXPECT_NE ( test , 0 , entry_val ) ;
KUNIT_EXPECT_EQ ( test , 0 , exit_val ) ;
entry_val = 0 ;
exit_val = 0 ;
target2 ( rand1 ) ;
KUNIT_EXPECT_NE ( test , 0 , entry_val ) ;
KUNIT_EXPECT_EQ ( test , 0 , exit_val ) ;
KUNIT_EXPECT_EQ ( test , 0 , unregister_fprobe ( & fp_entry ) ) ;
}
static void test_fprobe ( struct kunit * test )
{
struct fprobe fp = {
. entry_handler = fp_entry_handler ,
. exit_handler = fp_exit_handler ,
} ;
current_test = test ;
KUNIT_EXPECT_EQ ( test , 0 , register_fprobe ( & fp , " fprobe_selftest_target* " , NULL ) ) ;
entry_val = 0 ;
exit_val = 0 ;
target ( rand1 ) ;
KUNIT_EXPECT_NE ( test , 0 , entry_val ) ;
KUNIT_EXPECT_EQ ( test , entry_val + div_factor , exit_val ) ;
entry_val = 0 ;
exit_val = 0 ;
target2 ( rand1 ) ;
KUNIT_EXPECT_NE ( test , 0 , entry_val ) ;
KUNIT_EXPECT_EQ ( test , entry_val + div_factor , exit_val ) ;
KUNIT_EXPECT_EQ ( test , 0 , unregister_fprobe ( & fp ) ) ;
}
static void test_fprobe_syms ( struct kunit * test )
{
static const char * syms [ ] = { " fprobe_selftest_target " , " fprobe_selftest_target2 " } ;
struct fprobe fp = {
. entry_handler = fp_entry_handler ,
. exit_handler = fp_exit_handler ,
} ;
current_test = test ;
KUNIT_EXPECT_EQ ( test , 0 , register_fprobe_syms ( & fp , syms , 2 ) ) ;
entry_val = 0 ;
exit_val = 0 ;
target ( rand1 ) ;
KUNIT_EXPECT_NE ( test , 0 , entry_val ) ;
KUNIT_EXPECT_EQ ( test , entry_val + div_factor , exit_val ) ;
entry_val = 0 ;
exit_val = 0 ;
target2 ( rand1 ) ;
KUNIT_EXPECT_NE ( test , 0 , entry_val ) ;
KUNIT_EXPECT_EQ ( test , entry_val + div_factor , exit_val ) ;
KUNIT_EXPECT_EQ ( test , 0 , unregister_fprobe ( & fp ) ) ;
}
2023-02-01 18:56:10 +03:00
/* Test private entry_data */
static void test_fprobe_data ( struct kunit * test )
{
struct fprobe fp = {
. entry_handler = fp_entry_handler ,
. exit_handler = fp_exit_handler ,
. entry_data_size = sizeof ( u32 ) ,
} ;
current_test = test ;
KUNIT_EXPECT_EQ ( test , 0 , register_fprobe ( & fp , " fprobe_selftest_target " , NULL ) ) ;
target ( rand1 ) ;
KUNIT_EXPECT_EQ ( test , 0 , unregister_fprobe ( & fp ) ) ;
}
2023-02-01 18:56:28 +03:00
/* Test nr_maxactive */
static void test_fprobe_nest ( struct kunit * test )
{
static const char * syms [ ] = { " fprobe_selftest_target " , " fprobe_selftest_nest_target " } ;
struct fprobe fp = {
. entry_handler = nest_entry_handler ,
. exit_handler = nest_exit_handler ,
. nr_maxactive = 1 ,
} ;
current_test = test ;
KUNIT_EXPECT_EQ ( test , 0 , register_fprobe_syms ( & fp , syms , 2 ) ) ;
target_nest ( rand1 , target ) ;
KUNIT_EXPECT_EQ ( test , 1 , fp . nmissed ) ;
KUNIT_EXPECT_EQ ( test , 0 , unregister_fprobe ( & fp ) ) ;
}
2023-02-01 18:56:46 +03:00
static void test_fprobe_skip ( struct kunit * test )
{
struct fprobe fp = {
. entry_handler = fp_entry_handler ,
. exit_handler = fp_exit_handler ,
} ;
current_test = test ;
KUNIT_EXPECT_EQ ( test , 0 , register_fprobe ( & fp , " fprobe_selftest_target " , NULL ) ) ;
entry_return_value = 1 ;
entry_val = 0 ;
exit_val = 0 ;
target ( rand1 ) ;
KUNIT_EXPECT_NE ( test , 0 , entry_val ) ;
KUNIT_EXPECT_EQ ( test , 0 , exit_val ) ;
KUNIT_EXPECT_EQ ( test , 0 , fp . nmissed ) ;
entry_return_value = 0 ;
KUNIT_EXPECT_EQ ( test , 0 , unregister_fprobe ( & fp ) ) ;
}
2022-03-15 17:02:35 +03:00
static unsigned long get_ftrace_location ( void * func )
{
unsigned long size , addr = ( unsigned long ) func ;
if ( ! kallsyms_lookup_size_offset ( addr , & size , NULL ) | | ! size )
return 0 ;
return ftrace_location_range ( addr , addr + size - 1 ) ;
}
static int fprobe_test_init ( struct kunit * test )
{
2022-10-10 05:44:02 +03:00
rand1 = get_random_u32_above ( div_factor ) ;
2022-03-15 17:02:35 +03:00
target = fprobe_selftest_target ;
target2 = fprobe_selftest_target2 ;
2023-02-01 18:56:28 +03:00
target_nest = fprobe_selftest_nest_target ;
2022-03-15 17:02:35 +03:00
target_ip = get_ftrace_location ( target ) ;
target2_ip = get_ftrace_location ( target2 ) ;
2023-02-01 18:56:28 +03:00
target_nest_ip = get_ftrace_location ( target_nest ) ;
2022-03-15 17:02:35 +03:00
return 0 ;
}
static struct kunit_case fprobe_testcases [ ] = {
KUNIT_CASE ( test_fprobe_entry ) ,
KUNIT_CASE ( test_fprobe ) ,
KUNIT_CASE ( test_fprobe_syms ) ,
2023-02-01 18:56:10 +03:00
KUNIT_CASE ( test_fprobe_data ) ,
2023-02-01 18:56:28 +03:00
KUNIT_CASE ( test_fprobe_nest ) ,
2023-02-01 18:56:46 +03:00
KUNIT_CASE ( test_fprobe_skip ) ,
2022-03-15 17:02:35 +03:00
{ }
} ;
static struct kunit_suite fprobe_test_suite = {
. name = " fprobe_test " ,
. init = fprobe_test_init ,
. test_cases = fprobe_testcases ,
} ;
kunit_test_suites ( & fprobe_test_suite ) ;