-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Add a series of tests for bpf_snprintf
The "positive" part tests all format specifiers when things go well. The "negative" part makes sure that incorrect format strings fail at load time. Signed-off-by: Florent Revest <revest@chromium.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20210419155243.1632274-7-revest@chromium.org
- Loading branch information
Florent Revest
authored and
Alexei Starovoitov
committed
Apr 19, 2021
1 parent
58c2b1f
commit c2e39c6
Showing
3 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2021 Google LLC. */ | ||
|
||
#include <test_progs.h> | ||
#include "test_snprintf.skel.h" | ||
#include "test_snprintf_single.skel.h" | ||
|
||
#define EXP_NUM_OUT "-8 9 96 -424242 1337 DABBAD00" | ||
#define EXP_NUM_RET sizeof(EXP_NUM_OUT) | ||
|
||
#define EXP_IP_OUT "127.000.000.001 0000:0000:0000:0000:0000:0000:0000:0001" | ||
#define EXP_IP_RET sizeof(EXP_IP_OUT) | ||
|
||
/* The third specifier, %pB, depends on compiler inlining so don't check it */ | ||
#define EXP_SYM_OUT "schedule schedule+0x0/" | ||
#define MIN_SYM_RET sizeof(EXP_SYM_OUT) | ||
|
||
/* The third specifier, %p, is a hashed pointer which changes on every reboot */ | ||
#define EXP_ADDR_OUT "0000000000000000 ffff00000add4e55 " | ||
#define EXP_ADDR_RET sizeof(EXP_ADDR_OUT "unknownhashedptr") | ||
|
||
#define EXP_STR_OUT "str1 longstr" | ||
#define EXP_STR_RET sizeof(EXP_STR_OUT) | ||
|
||
#define EXP_OVER_OUT "%over" | ||
#define EXP_OVER_RET 10 | ||
|
||
#define EXP_PAD_OUT " 4 000" | ||
#define EXP_PAD_RET 900007 | ||
|
||
#define EXP_NO_ARG_OUT "simple case" | ||
#define EXP_NO_ARG_RET 12 | ||
|
||
#define EXP_NO_BUF_RET 29 | ||
|
||
void test_snprintf_positive(void) | ||
{ | ||
char exp_addr_out[] = EXP_ADDR_OUT; | ||
char exp_sym_out[] = EXP_SYM_OUT; | ||
struct test_snprintf *skel; | ||
|
||
skel = test_snprintf__open_and_load(); | ||
if (!ASSERT_OK_PTR(skel, "skel_open")) | ||
return; | ||
|
||
if (!ASSERT_OK(test_snprintf__attach(skel), "skel_attach")) | ||
goto cleanup; | ||
|
||
/* trigger tracepoint */ | ||
usleep(1); | ||
|
||
ASSERT_STREQ(skel->bss->num_out, EXP_NUM_OUT, "num_out"); | ||
ASSERT_EQ(skel->bss->num_ret, EXP_NUM_RET, "num_ret"); | ||
|
||
ASSERT_STREQ(skel->bss->ip_out, EXP_IP_OUT, "ip_out"); | ||
ASSERT_EQ(skel->bss->ip_ret, EXP_IP_RET, "ip_ret"); | ||
|
||
ASSERT_OK(memcmp(skel->bss->sym_out, exp_sym_out, | ||
sizeof(exp_sym_out) - 1), "sym_out"); | ||
ASSERT_LT(MIN_SYM_RET, skel->bss->sym_ret, "sym_ret"); | ||
|
||
ASSERT_OK(memcmp(skel->bss->addr_out, exp_addr_out, | ||
sizeof(exp_addr_out) - 1), "addr_out"); | ||
ASSERT_EQ(skel->bss->addr_ret, EXP_ADDR_RET, "addr_ret"); | ||
|
||
ASSERT_STREQ(skel->bss->str_out, EXP_STR_OUT, "str_out"); | ||
ASSERT_EQ(skel->bss->str_ret, EXP_STR_RET, "str_ret"); | ||
|
||
ASSERT_STREQ(skel->bss->over_out, EXP_OVER_OUT, "over_out"); | ||
ASSERT_EQ(skel->bss->over_ret, EXP_OVER_RET, "over_ret"); | ||
|
||
ASSERT_STREQ(skel->bss->pad_out, EXP_PAD_OUT, "pad_out"); | ||
ASSERT_EQ(skel->bss->pad_ret, EXP_PAD_RET, "pad_ret"); | ||
|
||
ASSERT_STREQ(skel->bss->noarg_out, EXP_NO_ARG_OUT, "no_arg_out"); | ||
ASSERT_EQ(skel->bss->noarg_ret, EXP_NO_ARG_RET, "no_arg_ret"); | ||
|
||
ASSERT_EQ(skel->bss->nobuf_ret, EXP_NO_BUF_RET, "no_buf_ret"); | ||
|
||
cleanup: | ||
test_snprintf__destroy(skel); | ||
} | ||
|
||
#define min(a, b) ((a) < (b) ? (a) : (b)) | ||
|
||
/* Loads an eBPF object calling bpf_snprintf with up to 10 characters of fmt */ | ||
static int load_single_snprintf(char *fmt) | ||
{ | ||
struct test_snprintf_single *skel; | ||
int ret; | ||
|
||
skel = test_snprintf_single__open(); | ||
if (!skel) | ||
return -EINVAL; | ||
|
||
memcpy(skel->rodata->fmt, fmt, min(strlen(fmt) + 1, 10)); | ||
|
||
ret = test_snprintf_single__load(skel); | ||
test_snprintf_single__destroy(skel); | ||
|
||
return ret; | ||
} | ||
|
||
void test_snprintf_negative(void) | ||
{ | ||
ASSERT_OK(load_single_snprintf("valid %d"), "valid usage"); | ||
|
||
ASSERT_ERR(load_single_snprintf("0123456789"), "no terminating zero"); | ||
ASSERT_ERR(load_single_snprintf("%d %d"), "too many specifiers"); | ||
ASSERT_ERR(load_single_snprintf("%pi5"), "invalid specifier 1"); | ||
ASSERT_ERR(load_single_snprintf("%a"), "invalid specifier 2"); | ||
ASSERT_ERR(load_single_snprintf("%"), "invalid specifier 3"); | ||
ASSERT_ERR(load_single_snprintf("%12345678"), "invalid specifier 4"); | ||
ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); | ||
ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); | ||
ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); | ||
} | ||
|
||
void test_snprintf(void) | ||
{ | ||
if (test__start_subtest("snprintf_positive")) | ||
test_snprintf_positive(); | ||
if (test__start_subtest("snprintf_negative")) | ||
test_snprintf_negative(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2021 Google LLC. */ | ||
|
||
#include <linux/bpf.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
char num_out[64] = {}; | ||
long num_ret = 0; | ||
|
||
char ip_out[64] = {}; | ||
long ip_ret = 0; | ||
|
||
char sym_out[64] = {}; | ||
long sym_ret = 0; | ||
|
||
char addr_out[64] = {}; | ||
long addr_ret = 0; | ||
|
||
char str_out[64] = {}; | ||
long str_ret = 0; | ||
|
||
char over_out[6] = {}; | ||
long over_ret = 0; | ||
|
||
char pad_out[10] = {}; | ||
long pad_ret = 0; | ||
|
||
char noarg_out[64] = {}; | ||
long noarg_ret = 0; | ||
|
||
long nobuf_ret = 0; | ||
|
||
extern const void schedule __ksym; | ||
|
||
SEC("raw_tp/sys_enter") | ||
int handler(const void *ctx) | ||
{ | ||
/* Convenient values to pretty-print */ | ||
const __u8 ex_ipv4[] = {127, 0, 0, 1}; | ||
const __u8 ex_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; | ||
static const char str1[] = "str1"; | ||
static const char longstr[] = "longstr"; | ||
|
||
/* Integer types */ | ||
num_ret = BPF_SNPRINTF(num_out, sizeof(num_out), | ||
"%d %u %x %li %llu %lX", | ||
-8, 9, 150, -424242, 1337, 0xDABBAD00); | ||
/* IP addresses */ | ||
ip_ret = BPF_SNPRINTF(ip_out, sizeof(ip_out), "%pi4 %pI6", | ||
&ex_ipv4, &ex_ipv6); | ||
/* Symbol lookup formatting */ | ||
sym_ret = BPF_SNPRINTF(sym_out, sizeof(sym_out), "%ps %pS %pB", | ||
&schedule, &schedule, &schedule); | ||
/* Kernel pointers */ | ||
addr_ret = BPF_SNPRINTF(addr_out, sizeof(addr_out), "%pK %px %p", | ||
0, 0xFFFF00000ADD4E55, 0xFFFF00000ADD4E55); | ||
/* Strings embedding */ | ||
str_ret = BPF_SNPRINTF(str_out, sizeof(str_out), "%s %+05s", | ||
str1, longstr); | ||
/* Overflow */ | ||
over_ret = BPF_SNPRINTF(over_out, sizeof(over_out), "%%overflow"); | ||
/* Padding of fixed width numbers */ | ||
pad_ret = BPF_SNPRINTF(pad_out, sizeof(pad_out), "%5d %0900000X", 4, 4); | ||
/* No args */ | ||
noarg_ret = BPF_SNPRINTF(noarg_out, sizeof(noarg_out), "simple case"); | ||
/* No buffer */ | ||
nobuf_ret = BPF_SNPRINTF(NULL, 0, "only interested in length %d", 60); | ||
|
||
return 0; | ||
} | ||
|
||
char _license[] SEC("license") = "GPL"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2021 Google LLC. */ | ||
|
||
#include <linux/bpf.h> | ||
#include <bpf/bpf_helpers.h> | ||
|
||
/* The format string is filled from the userspace such that loading fails */ | ||
static const char fmt[10]; | ||
|
||
SEC("raw_tp/sys_enter") | ||
int handler(const void *ctx) | ||
{ | ||
unsigned long long arg = 42; | ||
|
||
bpf_snprintf(NULL, 0, fmt, &arg, sizeof(arg)); | ||
|
||
return 0; | ||
} | ||
|
||
char _license[] SEC("license") = "GPL"; |