2019-11-14 21:57:20 +03:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 Facebook */
# include <test_progs.h>
2020-05-08 20:46:09 +03:00
# include <network_helpers.h>
2020-09-29 15:45:54 +03:00
# include <bpf/btf.h>
typedef int ( * test_cb ) ( struct bpf_object * obj ) ;
static int check_data_map ( struct bpf_object * obj , int prog_cnt , bool reset )
{
struct bpf_map * data_map = NULL , * map ;
__u64 * result = NULL ;
const int zero = 0 ;
__u32 duration = 0 ;
int ret = - 1 , i ;
result = malloc ( ( prog_cnt + 32 /* spare */ ) * sizeof ( __u64 ) ) ;
if ( CHECK ( ! result , " alloc_memory " , " failed to alloc memory " ) )
return - ENOMEM ;
bpf_object__for_each_map ( map , obj )
if ( bpf_map__is_internal ( map ) ) {
data_map = map ;
break ;
}
if ( CHECK ( ! data_map , " find_data_map " , " data map not found \n " ) )
goto out ;
ret = bpf_map_lookup_elem ( bpf_map__fd ( data_map ) , & zero , result ) ;
if ( CHECK ( ret , " get_result " ,
" failed to get output data: %d \n " , ret ) )
goto out ;
for ( i = 0 ; i < prog_cnt ; i + + ) {
if ( CHECK ( result [ i ] ! = 1 , " result " ,
" fexit_bpf2bpf result[%d] failed err %llu \n " ,
i , result [ i ] ) )
goto out ;
result [ i ] = 0 ;
}
if ( reset ) {
ret = bpf_map_update_elem ( bpf_map__fd ( data_map ) , & zero , result , 0 ) ;
if ( CHECK ( ret , " reset_result " , " failed to reset result \n " ) )
goto out ;
}
ret = 0 ;
out :
free ( result ) ;
return ret ;
}
2019-11-14 21:57:20 +03:00
2019-12-05 04:06:07 +03:00
static void test_fexit_bpf2bpf_common ( const char * obj_file ,
const char * target_obj_file ,
int prog_cnt ,
2020-04-24 16:34:28 +03:00
const char * * prog_name ,
2020-09-29 15:45:54 +03:00
bool run_prog ,
test_cb cb )
2019-11-14 21:57:20 +03:00
{
2020-09-29 15:45:54 +03:00
struct bpf_object * obj = NULL , * tgt_obj ;
2022-02-03 02:54:20 +03:00
__u32 tgt_prog_id , info_len ;
2021-04-13 12:16:07 +03:00
struct bpf_prog_info prog_info = { } ;
2021-09-16 04:58:34 +03:00
struct bpf_program * * prog = NULL , * p ;
2020-09-29 15:45:54 +03:00
struct bpf_link * * link = NULL ;
int err , tgt_fd , i ;
2021-04-13 12:16:07 +03:00
struct btf * btf ;
2022-02-03 02:54:20 +03:00
LIBBPF_OPTS ( bpf_test_run_opts , topts ,
. data_in = & pkt_v6 ,
. data_size_in = sizeof ( pkt_v6 ) ,
. repeat = 1 ,
) ;
2019-11-14 21:57:20 +03:00
2021-11-04 01:08:44 +03:00
err = bpf_prog_test_load ( target_obj_file , BPF_PROG_TYPE_UNSPEC ,
2020-09-29 15:45:54 +03:00
& tgt_obj , & tgt_fd ) ;
2021-04-13 12:16:07 +03:00
if ( ! ASSERT_OK ( err , " tgt_prog_load " ) )
2019-11-14 21:57:20 +03:00
return ;
2021-04-13 12:16:07 +03:00
info_len = sizeof ( prog_info ) ;
err = bpf_obj_get_info_by_fd ( tgt_fd , & prog_info , & info_len ) ;
if ( ! ASSERT_OK ( err , " tgt_fd_get_info " ) )
goto close_prog ;
tgt_prog_id = prog_info . id ;
btf = bpf_object__btf ( tgt_obj ) ;
2019-12-05 04:06:07 +03:00
link = calloc ( sizeof ( struct bpf_link * ) , prog_cnt ) ;
2021-04-13 12:16:07 +03:00
if ( ! ASSERT_OK_PTR ( link , " link_ptr " ) )
goto close_prog ;
2019-12-05 04:06:07 +03:00
prog = calloc ( sizeof ( struct bpf_program * ) , prog_cnt ) ;
2021-04-13 12:16:07 +03:00
if ( ! ASSERT_OK_PTR ( prog , " prog_ptr " ) )
2019-12-05 04:06:07 +03:00
goto close_prog ;
2021-09-16 04:58:34 +03:00
obj = bpf_object__open_file ( obj_file , NULL ) ;
2021-04-13 12:16:07 +03:00
if ( ! ASSERT_OK_PTR ( obj , " obj_open " ) )
2019-11-14 21:57:20 +03:00
goto close_prog ;
2021-09-16 04:58:34 +03:00
bpf_object__for_each_program ( p , obj ) {
err = bpf_program__set_attach_target ( p , tgt_fd , NULL ) ;
ASSERT_OK ( err , " set_attach_target " ) ;
}
2019-11-14 21:57:20 +03:00
err = bpf_object__load ( obj ) ;
2021-04-13 12:16:07 +03:00
if ( ! ASSERT_OK ( err , " obj_load " ) )
2019-11-14 21:57:20 +03:00
goto close_prog ;
2019-12-05 04:06:07 +03:00
for ( i = 0 ; i < prog_cnt ; i + + ) {
2021-04-13 12:16:07 +03:00
struct bpf_link_info link_info ;
2021-12-14 06:59:28 +03:00
struct bpf_program * pos ;
const char * pos_sec_name ;
2021-04-13 12:16:07 +03:00
char * tgt_name ;
__s32 btf_id ;
tgt_name = strstr ( prog_name [ i ] , " / " ) ;
if ( ! ASSERT_OK_PTR ( tgt_name , " tgt_name " ) )
goto close_prog ;
btf_id = btf__find_by_name_kind ( btf , tgt_name + 1 , BTF_KIND_FUNC ) ;
2021-12-14 06:59:28 +03:00
prog [ i ] = NULL ;
bpf_object__for_each_program ( pos , obj ) {
pos_sec_name = bpf_program__section_name ( pos ) ;
if ( pos_sec_name & & ! strcmp ( pos_sec_name , prog_name [ i ] ) ) {
prog [ i ] = pos ;
break ;
}
}
2021-04-13 12:16:07 +03:00
if ( ! ASSERT_OK_PTR ( prog [ i ] , prog_name [ i ] ) )
2019-11-14 21:57:20 +03:00
goto close_prog ;
2021-04-13 12:16:07 +03:00
2019-11-14 21:57:20 +03:00
link [ i ] = bpf_program__attach_trace ( prog [ i ] ) ;
2021-04-13 12:16:07 +03:00
if ( ! ASSERT_OK_PTR ( link [ i ] , " attach_trace " ) )
2019-11-14 21:57:20 +03:00
goto close_prog ;
2021-04-13 12:16:07 +03:00
info_len = sizeof ( link_info ) ;
memset ( & link_info , 0 , sizeof ( link_info ) ) ;
err = bpf_obj_get_info_by_fd ( bpf_link__fd ( link [ i ] ) ,
& link_info , & info_len ) ;
ASSERT_OK ( err , " link_fd_get_info " ) ;
ASSERT_EQ ( link_info . tracing . attach_type ,
2022-01-24 22:42:52 +03:00
bpf_program__expected_attach_type ( prog [ i ] ) ,
2021-04-13 12:16:07 +03:00
" link_attach_type " ) ;
ASSERT_EQ ( link_info . tracing . target_obj_id , tgt_prog_id , " link_tgt_obj_id " ) ;
ASSERT_EQ ( link_info . tracing . target_btf_id , btf_id , " link_tgt_btf_id " ) ;
2019-11-14 21:57:20 +03:00
}
2020-04-24 16:34:28 +03:00
2020-09-29 15:45:54 +03:00
if ( cb ) {
err = cb ( obj ) ;
if ( err )
goto close_prog ;
}
2020-04-24 16:34:28 +03:00
2020-09-29 15:45:54 +03:00
if ( ! run_prog )
2019-11-14 21:57:20 +03:00
goto close_prog ;
2022-02-03 02:54:20 +03:00
err = bpf_prog_test_run_opts ( tgt_fd , & topts ) ;
2021-04-13 12:16:07 +03:00
ASSERT_OK ( err , " prog_run " ) ;
2022-02-03 02:54:20 +03:00
ASSERT_EQ ( topts . retval , 0 , " prog_run_ret " ) ;
2019-11-14 21:57:20 +03:00
2020-09-29 15:45:54 +03:00
if ( check_data_map ( obj , prog_cnt , false ) )
2019-11-14 21:57:20 +03:00
goto close_prog ;
close_prog :
2019-12-05 04:06:07 +03:00
for ( i = 0 ; i < prog_cnt ; i + + )
2021-05-25 06:59:32 +03:00
bpf_link__destroy ( link [ i ] ) ;
bpf_object__close ( obj ) ;
2020-09-29 15:45:54 +03:00
bpf_object__close ( tgt_obj ) ;
2019-12-05 04:06:07 +03:00
free ( link ) ;
free ( prog ) ;
}
static void test_target_no_callees ( void )
{
const char * prog_name [ ] = {
" fexit/test_pkt_md_access " ,
} ;
test_fexit_bpf2bpf_common ( " ./fexit_bpf2bpf_simple.o " ,
" ./test_pkt_md_access.o " ,
ARRAY_SIZE ( prog_name ) ,
2020-09-29 15:45:54 +03:00
prog_name , true , NULL ) ;
2019-12-05 04:06:07 +03:00
}
static void test_target_yes_callees ( void )
{
const char * prog_name [ ] = {
" fexit/test_pkt_access " ,
" fexit/test_pkt_access_subprog1 " ,
" fexit/test_pkt_access_subprog2 " ,
2020-01-10 09:41:21 +03:00
" fexit/test_pkt_access_subprog3 " ,
2019-12-05 04:06:07 +03:00
} ;
test_fexit_bpf2bpf_common ( " ./fexit_bpf2bpf.o " ,
" ./test_pkt_access.o " ,
ARRAY_SIZE ( prog_name ) ,
2020-09-29 15:45:54 +03:00
prog_name , true , NULL ) ;
2019-12-05 04:06:07 +03:00
}
2020-01-21 03:53:48 +03:00
static void test_func_replace ( void )
{
const char * prog_name [ ] = {
" fexit/test_pkt_access " ,
" fexit/test_pkt_access_subprog1 " ,
" fexit/test_pkt_access_subprog2 " ,
" fexit/test_pkt_access_subprog3 " ,
" freplace/get_skb_len " ,
" freplace/get_skb_ifindex " ,
" freplace/get_constant " ,
2020-08-26 02:20:01 +03:00
" freplace/test_pkt_write_access_subprog " ,
2020-01-21 03:53:48 +03:00
} ;
test_fexit_bpf2bpf_common ( " ./fexit_bpf2bpf.o " ,
" ./test_pkt_access.o " ,
ARRAY_SIZE ( prog_name ) ,
2020-09-29 15:45:54 +03:00
prog_name , true , NULL ) ;
2020-04-24 16:34:28 +03:00
}
static void test_func_replace_verify ( void )
{
const char * prog_name [ ] = {
" freplace/do_bind " ,
} ;
test_fexit_bpf2bpf_common ( " ./freplace_connect4.o " ,
" ./connect4_prog.o " ,
ARRAY_SIZE ( prog_name ) ,
2020-09-29 15:45:54 +03:00
prog_name , false , NULL ) ;
}
static int test_second_attach ( struct bpf_object * obj )
{
2021-12-14 06:59:28 +03:00
const char * prog_name = " security_new_get_constant " ;
const char * tgt_name = " get_constant " ;
2020-09-29 15:45:54 +03:00
const char * tgt_obj_file = " ./test_pkt_access.o " ;
struct bpf_program * prog = NULL ;
struct bpf_object * tgt_obj ;
struct bpf_link * link ;
int err = 0 , tgt_fd ;
2022-02-03 02:54:20 +03:00
LIBBPF_OPTS ( bpf_test_run_opts , topts ,
. data_in = & pkt_v6 ,
. data_size_in = sizeof ( pkt_v6 ) ,
. repeat = 1 ,
) ;
2020-09-29 15:45:54 +03:00
2021-12-14 06:59:28 +03:00
prog = bpf_object__find_program_by_name ( obj , prog_name ) ;
2022-02-03 02:54:20 +03:00
if ( ! ASSERT_OK_PTR ( prog , " find_prog " ) )
2020-09-29 15:45:54 +03:00
return - ENOENT ;
2021-11-04 01:08:44 +03:00
err = bpf_prog_test_load ( tgt_obj_file , BPF_PROG_TYPE_UNSPEC ,
2020-09-29 15:45:54 +03:00
& tgt_obj , & tgt_fd ) ;
2022-02-03 02:54:20 +03:00
if ( ! ASSERT_OK ( err , " second_prog_load " ) )
2020-09-29 15:45:54 +03:00
return err ;
link = bpf_program__attach_freplace ( prog , tgt_fd , tgt_name ) ;
2021-05-25 06:59:32 +03:00
if ( ! ASSERT_OK_PTR ( link , " second_link " ) )
2020-09-29 15:45:54 +03:00
goto out ;
2022-02-03 02:54:20 +03:00
err = bpf_prog_test_run_opts ( tgt_fd , & topts ) ;
if ( ! ASSERT_OK ( err , " ipv6 test_run " ) )
goto out ;
if ( ! ASSERT_OK ( topts . retval , " ipv6 retval " ) )
2020-09-29 15:45:54 +03:00
goto out ;
err = check_data_map ( obj , 1 , true ) ;
if ( err )
goto out ;
out :
bpf_link__destroy ( link ) ;
bpf_object__close ( tgt_obj ) ;
return err ;
}
static void test_func_replace_multi ( void )
{
const char * prog_name [ ] = {
" freplace/get_constant " ,
} ;
test_fexit_bpf2bpf_common ( " ./freplace_get_constant.o " ,
" ./test_pkt_access.o " ,
ARRAY_SIZE ( prog_name ) ,
prog_name , true , test_second_attach ) ;
2020-01-21 03:53:48 +03:00
}
2020-09-29 15:45:57 +03:00
static void test_fmod_ret_freplace ( void )
{
struct bpf_object * freplace_obj = NULL , * pkt_obj , * fmod_obj = NULL ;
const char * freplace_name = " ./freplace_get_constant.o " ;
const char * fmod_ret_name = " ./fmod_ret_freplace.o " ;
DECLARE_LIBBPF_OPTS ( bpf_object_open_opts , opts ) ;
const char * tgt_name = " ./test_pkt_access.o " ;
struct bpf_link * freplace_link = NULL ;
struct bpf_program * prog ;
__u32 duration = 0 ;
2021-09-16 04:58:34 +03:00
int err , pkt_fd , attach_prog_fd ;
2020-09-29 15:45:57 +03:00
2021-11-04 01:08:44 +03:00
err = bpf_prog_test_load ( tgt_name , BPF_PROG_TYPE_UNSPEC ,
2020-09-29 15:45:57 +03:00
& pkt_obj , & pkt_fd ) ;
/* the target prog should load fine */
if ( CHECK ( err , " tgt_prog_load " , " file %s err %d errno %d \n " ,
tgt_name , err , errno ) )
return ;
2021-09-16 04:58:34 +03:00
freplace_obj = bpf_object__open_file ( freplace_name , NULL ) ;
2021-05-25 06:59:32 +03:00
if ( ! ASSERT_OK_PTR ( freplace_obj , " freplace_obj_open " ) )
2020-09-29 15:45:57 +03:00
goto out ;
2021-10-03 19:58:44 +03:00
prog = bpf_object__next_program ( freplace_obj , NULL ) ;
2021-09-16 04:58:34 +03:00
err = bpf_program__set_attach_target ( prog , pkt_fd , NULL ) ;
ASSERT_OK ( err , " freplace__set_attach_target " ) ;
2020-09-29 15:45:57 +03:00
err = bpf_object__load ( freplace_obj ) ;
if ( CHECK ( err , " freplace_obj_load " , " err %d \n " , err ) )
goto out ;
freplace_link = bpf_program__attach_trace ( prog ) ;
2021-05-25 06:59:32 +03:00
if ( ! ASSERT_OK_PTR ( freplace_link , " freplace_attach_trace " ) )
2020-09-29 15:45:57 +03:00
goto out ;
2021-09-16 04:58:34 +03:00
fmod_obj = bpf_object__open_file ( fmod_ret_name , NULL ) ;
2021-05-25 06:59:32 +03:00
if ( ! ASSERT_OK_PTR ( fmod_obj , " fmod_obj_open " ) )
2020-09-29 15:45:57 +03:00
goto out ;
2021-09-16 04:58:34 +03:00
attach_prog_fd = bpf_program__fd ( prog ) ;
2021-10-03 19:58:44 +03:00
prog = bpf_object__next_program ( fmod_obj , NULL ) ;
2021-09-16 04:58:34 +03:00
err = bpf_program__set_attach_target ( prog , attach_prog_fd , NULL ) ;
ASSERT_OK ( err , " fmod_ret_set_attach_target " ) ;
2020-09-29 15:45:57 +03:00
err = bpf_object__load ( fmod_obj ) ;
if ( CHECK ( ! err , " fmod_obj_load " , " loading fmod_ret should fail \n " ) )
goto out ;
out :
bpf_link__destroy ( freplace_link ) ;
bpf_object__close ( freplace_obj ) ;
bpf_object__close ( fmod_obj ) ;
bpf_object__close ( pkt_obj ) ;
}
2020-08-26 02:20:03 +03:00
static void test_func_sockmap_update ( void )
{
const char * prog_name [ ] = {
" freplace/cls_redirect " ,
} ;
test_fexit_bpf2bpf_common ( " ./freplace_cls_redirect.o " ,
" ./test_cls_redirect.o " ,
ARRAY_SIZE ( prog_name ) ,
2020-09-29 15:45:54 +03:00
prog_name , false , NULL ) ;
2020-08-26 02:20:03 +03:00
}
static void test_obj_load_failure_common ( const char * obj_file ,
2021-09-16 04:58:34 +03:00
const char * target_obj_file )
2020-08-26 02:20:02 +03:00
{
/*
* standalone test that asserts failure to load freplace prog
* because of invalid return code .
*/
struct bpf_object * obj = NULL , * pkt_obj ;
2021-09-16 04:58:34 +03:00
struct bpf_program * prog ;
2020-08-26 02:20:02 +03:00
int err , pkt_fd ;
__u32 duration = 0 ;
2021-11-04 01:08:44 +03:00
err = bpf_prog_test_load ( target_obj_file , BPF_PROG_TYPE_UNSPEC ,
2020-08-26 02:20:02 +03:00
& pkt_obj , & pkt_fd ) ;
/* the target prog should load fine */
if ( CHECK ( err , " tgt_prog_load " , " file %s err %d errno %d \n " ,
target_obj_file , err , errno ) )
return ;
2021-09-16 04:58:34 +03:00
obj = bpf_object__open_file ( obj_file , NULL ) ;
2021-05-25 06:59:32 +03:00
if ( ! ASSERT_OK_PTR ( obj , " obj_open " ) )
2020-08-26 02:20:02 +03:00
goto close_prog ;
2021-10-03 19:58:44 +03:00
prog = bpf_object__next_program ( obj , NULL ) ;
2021-09-16 04:58:34 +03:00
err = bpf_program__set_attach_target ( prog , pkt_fd , NULL ) ;
ASSERT_OK ( err , " set_attach_target " ) ;
2020-08-26 02:20:02 +03:00
/* It should fail to load the program */
err = bpf_object__load ( obj ) ;
if ( CHECK ( ! err , " bpf_obj_load should fail " , " err %d \n " , err ) )
goto close_prog ;
close_prog :
2021-05-25 06:59:32 +03:00
bpf_object__close ( obj ) ;
2020-08-26 02:20:02 +03:00
bpf_object__close ( pkt_obj ) ;
}
2020-08-26 02:20:03 +03:00
static void test_func_replace_return_code ( void )
{
/* test invalid return code in the replaced program */
test_obj_load_failure_common ( " ./freplace_connect_v4_prog.o " ,
" ./connect4_prog.o " ) ;
}
static void test_func_map_prog_compatibility ( void )
{
/* test with spin lock map value in the replaced program */
test_obj_load_failure_common ( " ./freplace_attach_probe.o " ,
" ./test_attach_probe.o " ) ;
}
2021-10-06 21:56:19 +03:00
/* NOTE: affect other tests, must run in serial mode */
void serial_test_fexit_bpf2bpf ( void )
2019-12-05 04:06:07 +03:00
{
2020-09-03 23:35:39 +03:00
if ( test__start_subtest ( " target_no_callees " ) )
test_target_no_callees ( ) ;
if ( test__start_subtest ( " target_yes_callees " ) )
test_target_yes_callees ( ) ;
if ( test__start_subtest ( " func_replace " ) )
test_func_replace ( ) ;
if ( test__start_subtest ( " func_replace_verify " ) )
test_func_replace_verify ( ) ;
if ( test__start_subtest ( " func_sockmap_update " ) )
test_func_sockmap_update ( ) ;
if ( test__start_subtest ( " func_replace_return_code " ) )
test_func_replace_return_code ( ) ;
if ( test__start_subtest ( " func_map_prog_compatibility " ) )
test_func_map_prog_compatibility ( ) ;
2020-09-29 15:45:54 +03:00
if ( test__start_subtest ( " func_replace_multi " ) )
test_func_replace_multi ( ) ;
2020-09-29 15:45:57 +03:00
if ( test__start_subtest ( " fmod_ret_freplace " ) )
test_fmod_ret_freplace ( ) ;
2019-11-14 21:57:20 +03:00
}