Skip to content

Commit 4798c4b

Browse files
yonghong-songAlexei Starovoitov
authored andcommitted
tools/bpf: extends test_btf to test load/retrieve func_type info
A two function bpf program is loaded with btf and func_info. After successful prog load, the bpf_get_info syscall is called to retrieve prog info to ensure the types returned from the kernel matches the types passed to the kernel from the user space. Several negative tests are also added to test loading/retriving of func_type info. Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 7e0d0fb commit 4798c4b

File tree

1 file changed

+329
-3
lines changed

1 file changed

+329
-3
lines changed

tools/testing/selftests/bpf/test_btf.c

Lines changed: 329 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/btf.h>
66
#include <linux/err.h>
77
#include <linux/kernel.h>
8+
#include <linux/filter.h>
89
#include <bpf/bpf.h>
910
#include <sys/resource.h>
1011
#include <libelf.h>
@@ -22,9 +23,13 @@
2223
#include "bpf_rlimit.h"
2324
#include "bpf_util.h"
2425

26+
#define MAX_INSNS 512
27+
#define MAX_SUBPROGS 16
28+
2529
static uint32_t pass_cnt;
2630
static uint32_t error_cnt;
2731
static uint32_t skip_cnt;
32+
static bool jit_enabled;
2833

2934
#define CHECK(condition, format...) ({ \
3035
int __ret = !!(condition); \
@@ -60,6 +65,24 @@ static int __base_pr(const char *format, ...)
6065
return err;
6166
}
6267

68+
static bool is_jit_enabled(void)
69+
{
70+
const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable";
71+
bool enabled = false;
72+
int sysctl_fd;
73+
74+
sysctl_fd = open(jit_sysctl, 0, O_RDONLY);
75+
if (sysctl_fd != -1) {
76+
char tmpc;
77+
78+
if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1)
79+
enabled = (tmpc != '0');
80+
close(sysctl_fd);
81+
}
82+
83+
return enabled;
84+
}
85+
6386
#define BTF_INFO_ENC(kind, root, vlen) \
6487
((!!(root) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
6588

@@ -115,6 +138,7 @@ static struct args {
115138
bool get_info_test;
116139
bool pprint_test;
117140
bool always_log;
141+
bool func_type_test;
118142
} args;
119143

120144
static char btf_log_buf[BTF_LOG_BUF_SIZE];
@@ -2947,16 +2971,310 @@ static int test_pprint(void)
29472971
return err;
29482972
}
29492973

2974+
static struct btf_func_type_test {
2975+
const char *descr;
2976+
const char *str_sec;
2977+
__u32 raw_types[MAX_NR_RAW_TYPES];
2978+
__u32 str_sec_size;
2979+
struct bpf_insn insns[MAX_INSNS];
2980+
__u32 prog_type;
2981+
__u32 func_info[MAX_SUBPROGS][2];
2982+
__u32 func_info_rec_size;
2983+
__u32 func_info_cnt;
2984+
bool expected_prog_load_failure;
2985+
} func_type_test[] = {
2986+
{
2987+
.descr = "func_type (main func + one sub)",
2988+
.raw_types = {
2989+
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
2990+
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */
2991+
BTF_FUNC_PROTO_ENC(1, 2), /* [3] */
2992+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
2993+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
2994+
BTF_FUNC_PROTO_ENC(1, 2), /* [4] */
2995+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
2996+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
2997+
BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */
2998+
BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */
2999+
BTF_END_RAW,
3000+
},
3001+
.str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB",
3002+
.str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"),
3003+
.insns = {
3004+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
3005+
BPF_MOV64_IMM(BPF_REG_0, 1),
3006+
BPF_EXIT_INSN(),
3007+
BPF_MOV64_IMM(BPF_REG_0, 2),
3008+
BPF_EXIT_INSN(),
3009+
},
3010+
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
3011+
.func_info = { {0, 5}, {3, 6} },
3012+
.func_info_rec_size = 8,
3013+
.func_info_cnt = 2,
3014+
},
3015+
3016+
{
3017+
.descr = "func_type (Incorrect func_info_rec_size)",
3018+
.raw_types = {
3019+
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3020+
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */
3021+
BTF_FUNC_PROTO_ENC(1, 2), /* [3] */
3022+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3023+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
3024+
BTF_FUNC_PROTO_ENC(1, 2), /* [4] */
3025+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
3026+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3027+
BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */
3028+
BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */
3029+
BTF_END_RAW,
3030+
},
3031+
.str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB",
3032+
.str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"),
3033+
.insns = {
3034+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
3035+
BPF_MOV64_IMM(BPF_REG_0, 1),
3036+
BPF_EXIT_INSN(),
3037+
BPF_MOV64_IMM(BPF_REG_0, 2),
3038+
BPF_EXIT_INSN(),
3039+
},
3040+
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
3041+
.func_info = { {0, 5}, {3, 6} },
3042+
.func_info_rec_size = 4,
3043+
.func_info_cnt = 2,
3044+
.expected_prog_load_failure = true,
3045+
},
3046+
3047+
{
3048+
.descr = "func_type (Incorrect func_info_cnt)",
3049+
.raw_types = {
3050+
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3051+
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */
3052+
BTF_FUNC_PROTO_ENC(1, 2), /* [3] */
3053+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3054+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
3055+
BTF_FUNC_PROTO_ENC(1, 2), /* [4] */
3056+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
3057+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3058+
BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */
3059+
BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */
3060+
BTF_END_RAW,
3061+
},
3062+
.str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB",
3063+
.str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"),
3064+
.insns = {
3065+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
3066+
BPF_MOV64_IMM(BPF_REG_0, 1),
3067+
BPF_EXIT_INSN(),
3068+
BPF_MOV64_IMM(BPF_REG_0, 2),
3069+
BPF_EXIT_INSN(),
3070+
},
3071+
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
3072+
.func_info = { {0, 5}, {3, 6} },
3073+
.func_info_rec_size = 8,
3074+
.func_info_cnt = 1,
3075+
.expected_prog_load_failure = true,
3076+
},
3077+
3078+
{
3079+
.descr = "func_type (Incorrect bpf_func_info.insn_offset)",
3080+
.raw_types = {
3081+
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3082+
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */
3083+
BTF_FUNC_PROTO_ENC(1, 2), /* [3] */
3084+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3085+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
3086+
BTF_FUNC_PROTO_ENC(1, 2), /* [4] */
3087+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 2),
3088+
BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3089+
BTF_FUNC_ENC(NAME_TBD, 3), /* [5] */
3090+
BTF_FUNC_ENC(NAME_TBD, 4), /* [6] */
3091+
BTF_END_RAW,
3092+
},
3093+
.str_sec = "\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB",
3094+
.str_sec_size = sizeof("\0int\0unsigned int\0a\0b\0c\0d\0funcA\0funcB"),
3095+
.insns = {
3096+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
3097+
BPF_MOV64_IMM(BPF_REG_0, 1),
3098+
BPF_EXIT_INSN(),
3099+
BPF_MOV64_IMM(BPF_REG_0, 2),
3100+
BPF_EXIT_INSN(),
3101+
},
3102+
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
3103+
.func_info = { {0, 5}, {2, 6} },
3104+
.func_info_rec_size = 8,
3105+
.func_info_cnt = 2,
3106+
.expected_prog_load_failure = true,
3107+
},
3108+
3109+
};
3110+
3111+
static size_t probe_prog_length(const struct bpf_insn *fp)
3112+
{
3113+
size_t len;
3114+
3115+
for (len = MAX_INSNS - 1; len > 0; --len)
3116+
if (fp[len].code != 0 || fp[len].imm != 0)
3117+
break;
3118+
return len + 1;
3119+
}
3120+
3121+
static int do_test_func_type(int test_num)
3122+
{
3123+
const struct btf_func_type_test *test = &func_type_test[test_num];
3124+
unsigned int raw_btf_size, info_len, rec_size;
3125+
int i, btf_fd = -1, prog_fd = -1, err = 0;
3126+
struct bpf_load_program_attr attr = {};
3127+
void *raw_btf, *func_info = NULL;
3128+
struct bpf_prog_info info = {};
3129+
struct bpf_func_info *finfo;
3130+
3131+
fprintf(stderr, "%s......", test->descr);
3132+
raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
3133+
test->str_sec, test->str_sec_size,
3134+
&raw_btf_size);
3135+
3136+
if (!raw_btf)
3137+
return -1;
3138+
3139+
*btf_log_buf = '\0';
3140+
btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
3141+
btf_log_buf, BTF_LOG_BUF_SIZE,
3142+
args.always_log);
3143+
free(raw_btf);
3144+
3145+
if (CHECK(btf_fd == -1, "invalid btf_fd errno:%d", errno)) {
3146+
err = -1;
3147+
goto done;
3148+
}
3149+
3150+
if (*btf_log_buf && args.always_log)
3151+
fprintf(stderr, "\n%s", btf_log_buf);
3152+
3153+
attr.prog_type = test->prog_type;
3154+
attr.insns = test->insns;
3155+
attr.insns_cnt = probe_prog_length(attr.insns);
3156+
attr.license = "GPL";
3157+
attr.prog_btf_fd = btf_fd;
3158+
attr.func_info_rec_size = test->func_info_rec_size;
3159+
attr.func_info_cnt = test->func_info_cnt;
3160+
attr.func_info = test->func_info;
3161+
3162+
*btf_log_buf = '\0';
3163+
prog_fd = bpf_load_program_xattr(&attr, btf_log_buf,
3164+
BTF_LOG_BUF_SIZE);
3165+
if (test->expected_prog_load_failure && prog_fd == -1) {
3166+
err = 0;
3167+
goto done;
3168+
}
3169+
if (CHECK(prog_fd == -1, "invalid prog_id errno:%d", errno)) {
3170+
fprintf(stderr, "%s\n", btf_log_buf);
3171+
err = -1;
3172+
goto done;
3173+
}
3174+
if (!jit_enabled) {
3175+
skip_cnt++;
3176+
fprintf(stderr, "SKIPPED, please enable sysctl bpf_jit_enable\n");
3177+
err = 0;
3178+
goto done;
3179+
}
3180+
3181+
/* get necessary lens */
3182+
info_len = sizeof(struct bpf_prog_info);
3183+
err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
3184+
if (CHECK(err == -1, "invalid get info (1st) errno:%d", errno)) {
3185+
fprintf(stderr, "%s\n", btf_log_buf);
3186+
err = -1;
3187+
goto done;
3188+
}
3189+
if (CHECK(info.func_info_cnt != 2,
3190+
"incorrect info.func_info_cnt (1st) %d\n",
3191+
info.func_info_cnt)) {
3192+
err = -1;
3193+
goto done;
3194+
}
3195+
rec_size = info.func_info_rec_size;
3196+
if (CHECK(rec_size < 4,
3197+
"incorrect info.func_info_rec_size (1st) %d\n", rec_size)) {
3198+
err = -1;
3199+
goto done;
3200+
}
3201+
3202+
func_info = malloc(info.func_info_cnt * rec_size);
3203+
if (CHECK(!func_info, "out of memeory")) {
3204+
err = -1;
3205+
goto done;
3206+
}
3207+
3208+
/* reset info to only retrieve func_info related data */
3209+
memset(&info, 0, sizeof(info));
3210+
info.func_info_cnt = 2;
3211+
info.func_info_rec_size = rec_size;
3212+
info.func_info = ptr_to_u64(func_info);
3213+
err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
3214+
if (CHECK(err == -1, "invalid get info (2nd) errno:%d", errno)) {
3215+
fprintf(stderr, "%s\n", btf_log_buf);
3216+
err = -1;
3217+
goto done;
3218+
}
3219+
if (CHECK(info.func_info_cnt != 2,
3220+
"incorrect info.func_info_cnt (2nd) %d\n",
3221+
info.func_info_cnt)) {
3222+
err = -1;
3223+
goto done;
3224+
}
3225+
if (CHECK(info.func_info_rec_size != rec_size,
3226+
"incorrect info.func_info_rec_size (2nd) %d\n",
3227+
info.func_info_rec_size)) {
3228+
err = -1;
3229+
goto done;
3230+
}
3231+
3232+
finfo = func_info;
3233+
for (i = 0; i < 2; i++) {
3234+
if (CHECK(finfo->type_id != test->func_info[i][1],
3235+
"incorrect func_type %u expected %u",
3236+
finfo->type_id, test->func_info[i][1])) {
3237+
err = -1;
3238+
goto done;
3239+
}
3240+
finfo = (void *)finfo + rec_size;
3241+
}
3242+
3243+
done:
3244+
if (*btf_log_buf && (err || args.always_log))
3245+
fprintf(stderr, "\n%s", btf_log_buf);
3246+
3247+
if (btf_fd != -1)
3248+
close(btf_fd);
3249+
if (prog_fd != -1)
3250+
close(prog_fd);
3251+
free(func_info);
3252+
return err;
3253+
}
3254+
3255+
static int test_func_type(void)
3256+
{
3257+
unsigned int i;
3258+
int err = 0;
3259+
3260+
for (i = 0; i < ARRAY_SIZE(func_type_test); i++)
3261+
err |= count_result(do_test_func_type(i));
3262+
3263+
return err;
3264+
}
3265+
29503266
static void usage(const char *cmd)
29513267
{
2952-
fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n",
3268+
fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] |"
3269+
" [-g test_num (1 - %zu)] |"
3270+
" [-f test_num (1 - %zu)] | [-p] | [-k] ]\n",
29533271
cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests),
29543272
ARRAY_SIZE(file_tests));
29553273
}
29563274

29573275
static int parse_args(int argc, char **argv)
29583276
{
2959-
const char *optstr = "lpf:r:g:";
3277+
const char *optstr = "lpkf:r:g:";
29603278
int opt;
29613279

29623280
while ((opt = getopt(argc, argv, optstr)) != -1) {
@@ -2979,6 +3297,9 @@ static int parse_args(int argc, char **argv)
29793297
case 'p':
29803298
args.pprint_test = true;
29813299
break;
3300+
case 'k':
3301+
args.func_type_test = true;
3302+
break;
29823303
case 'h':
29833304
usage(argv[0]);
29843305
exit(0);
@@ -3032,6 +3353,8 @@ int main(int argc, char **argv)
30323353
if (args.always_log)
30333354
libbpf_set_print(__base_pr, __base_pr, __base_pr);
30343355

3356+
jit_enabled = is_jit_enabled();
3357+
30353358
if (args.raw_test)
30363359
err |= test_raw();
30373360

@@ -3044,8 +3367,11 @@ int main(int argc, char **argv)
30443367
if (args.pprint_test)
30453368
err |= test_pprint();
30463369

3370+
if (args.func_type_test)
3371+
err |= test_func_type();
3372+
30473373
if (args.raw_test || args.get_info_test || args.file_test ||
3048-
args.pprint_test)
3374+
args.pprint_test || args.func_type_test)
30493375
goto done;
30503376

30513377
err |= test_raw();

0 commit comments

Comments
 (0)