Commit 93731ef0 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Alexei Starovoitov

bpf: migrate ebpf ld_abs/ld_ind tests to test_verifier

Remove all eBPF tests involving LD_ABS/LD_IND from test_bpf.ko. Reason
is that the eBPF tests from test_bpf module do not go via BPF verifier
and therefore any instruction rewrites from verifier cannot take place.

Therefore, move them into test_verifier which runs out of user space,
so that verfier can rewrite LD_ABS/LD_IND internally in upcoming patches.
It will have the same effect since runtime tests are also performed from
there. This also allows to finally unexport bpf_skb_vlan_{push,pop}_proto
and keep it internal to core kernel.

Additionally, also add further cBPF LD_ABS/LD_IND test coverage into
test_bpf.ko suite.
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent b390134c
...@@ -714,8 +714,6 @@ extern const struct bpf_func_proto bpf_ktime_get_ns_proto; ...@@ -714,8 +714,6 @@ extern const struct bpf_func_proto bpf_ktime_get_ns_proto;
extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto; extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto;
extern const struct bpf_func_proto bpf_get_current_uid_gid_proto; extern const struct bpf_func_proto bpf_get_current_uid_gid_proto;
extern const struct bpf_func_proto bpf_get_current_comm_proto; extern const struct bpf_func_proto bpf_get_current_comm_proto;
extern const struct bpf_func_proto bpf_skb_vlan_push_proto;
extern const struct bpf_func_proto bpf_skb_vlan_pop_proto;
extern const struct bpf_func_proto bpf_get_stackid_proto; extern const struct bpf_func_proto bpf_get_stackid_proto;
extern const struct bpf_func_proto bpf_get_stack_proto; extern const struct bpf_func_proto bpf_get_stack_proto;
extern const struct bpf_func_proto bpf_sock_map_update_proto; extern const struct bpf_func_proto bpf_sock_map_update_proto;
......
This diff is collapsed.
...@@ -2181,7 +2181,7 @@ BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto, ...@@ -2181,7 +2181,7 @@ BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto,
return ret; return ret;
} }
const struct bpf_func_proto bpf_skb_vlan_push_proto = { static const struct bpf_func_proto bpf_skb_vlan_push_proto = {
.func = bpf_skb_vlan_push, .func = bpf_skb_vlan_push,
.gpl_only = false, .gpl_only = false,
.ret_type = RET_INTEGER, .ret_type = RET_INTEGER,
...@@ -2189,7 +2189,6 @@ const struct bpf_func_proto bpf_skb_vlan_push_proto = { ...@@ -2189,7 +2189,6 @@ const struct bpf_func_proto bpf_skb_vlan_push_proto = {
.arg2_type = ARG_ANYTHING, .arg2_type = ARG_ANYTHING,
.arg3_type = ARG_ANYTHING, .arg3_type = ARG_ANYTHING,
}; };
EXPORT_SYMBOL_GPL(bpf_skb_vlan_push_proto);
BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb) BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb)
{ {
...@@ -2203,13 +2202,12 @@ BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb) ...@@ -2203,13 +2202,12 @@ BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb)
return ret; return ret;
} }
const struct bpf_func_proto bpf_skb_vlan_pop_proto = { static const struct bpf_func_proto bpf_skb_vlan_pop_proto = {
.func = bpf_skb_vlan_pop, .func = bpf_skb_vlan_pop,
.gpl_only = false, .gpl_only = false,
.ret_type = RET_INTEGER, .ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX, .arg1_type = ARG_PTR_TO_CTX,
}; };
EXPORT_SYMBOL_GPL(bpf_skb_vlan_pop_proto);
static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len) static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len)
{ {
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif #endif
#define MAX_INSNS 512 #define MAX_INSNS BPF_MAXINSNS
#define MAX_FIXUPS 8 #define MAX_FIXUPS 8
#define MAX_NR_MAPS 4 #define MAX_NR_MAPS 4
#define POINTER_VALUE 0xcafe4all #define POINTER_VALUE 0xcafe4all
...@@ -77,6 +77,8 @@ struct bpf_test { ...@@ -77,6 +77,8 @@ struct bpf_test {
} result, result_unpriv; } result, result_unpriv;
enum bpf_prog_type prog_type; enum bpf_prog_type prog_type;
uint8_t flags; uint8_t flags;
__u8 data[TEST_DATA_LEN];
void (*fill_helper)(struct bpf_test *self);
}; };
/* Note we want this to be 64 bit aligned so that the end of our array is /* Note we want this to be 64 bit aligned so that the end of our array is
...@@ -94,6 +96,62 @@ struct other_val { ...@@ -94,6 +96,62 @@ struct other_val {
long long bar; long long bar;
}; };
static void bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self)
{
/* test: {skb->data[0], vlan_push} x 68 + {skb->data[0], vlan_pop} x 68 */
#define PUSH_CNT 51
unsigned int len = BPF_MAXINSNS;
struct bpf_insn *insn = self->insns;
int i = 0, j, k = 0;
insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
loop:
for (j = 0; j < PUSH_CNT; j++) {
insn[i++] = BPF_LD_ABS(BPF_B, 0);
insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0x34, len - i - 2);
i++;
insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6);
insn[i++] = BPF_MOV64_IMM(BPF_REG_2, 1);
insn[i++] = BPF_MOV64_IMM(BPF_REG_3, 2);
insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_skb_vlan_push),
insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, len - i - 2);
i++;
}
for (j = 0; j < PUSH_CNT; j++) {
insn[i++] = BPF_LD_ABS(BPF_B, 0);
insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0x34, len - i - 2);
i++;
insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6);
insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_skb_vlan_pop),
insn[i] = BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, len - i - 2);
i++;
}
if (++k < 5)
goto loop;
for (; i < len - 1; i++)
insn[i] = BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 0xbef);
insn[len - 1] = BPF_EXIT_INSN();
}
static void bpf_fill_jump_around_ld_abs(struct bpf_test *self)
{
struct bpf_insn *insn = self->insns;
unsigned int len = BPF_MAXINSNS;
int i = 0;
insn[i++] = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1);
insn[i++] = BPF_LD_ABS(BPF_B, 0);
insn[i] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 10, len - i - 2);
i++;
while (i < len - 1)
insn[i++] = BPF_LD_ABS(BPF_B, 1);
insn[i] = BPF_EXIT_INSN();
}
static struct bpf_test tests[] = { static struct bpf_test tests[] = {
{ {
"add+sub+mul", "add+sub+mul",
...@@ -11725,6 +11783,197 @@ static struct bpf_test tests[] = { ...@@ -11725,6 +11783,197 @@ static struct bpf_test tests[] = {
.result = ACCEPT, .result = ACCEPT,
.prog_type = BPF_PROG_TYPE_TRACEPOINT, .prog_type = BPF_PROG_TYPE_TRACEPOINT,
}, },
{
"ld_abs: invalid op 1",
.insns = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
BPF_LD_ABS(BPF_DW, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
.errstr = "unknown opcode",
},
{
"ld_abs: invalid op 2",
.insns = {
BPF_MOV32_IMM(BPF_REG_0, 256),
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
BPF_LD_IND(BPF_DW, BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
.errstr = "unknown opcode",
},
{
"ld_abs: nmap reduced",
.insns = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
BPF_LD_ABS(BPF_H, 12),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0x806, 28),
BPF_LD_ABS(BPF_H, 12),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0x806, 26),
BPF_MOV32_IMM(BPF_REG_0, 18),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -64),
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_10, -64),
BPF_LD_IND(BPF_W, BPF_REG_7, 14),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -60),
BPF_MOV32_IMM(BPF_REG_0, 280971478),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -56),
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_10, -56),
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_10, -60),
BPF_ALU32_REG(BPF_SUB, BPF_REG_0, BPF_REG_7),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 15),
BPF_LD_ABS(BPF_H, 12),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0x806, 13),
BPF_MOV32_IMM(BPF_REG_0, 22),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -56),
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_10, -56),
BPF_LD_IND(BPF_H, BPF_REG_7, 14),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -52),
BPF_MOV32_IMM(BPF_REG_0, 17366),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -48),
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_10, -48),
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_10, -52),
BPF_ALU32_REG(BPF_SUB, BPF_REG_0, BPF_REG_7),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2),
BPF_MOV32_IMM(BPF_REG_0, 256),
BPF_EXIT_INSN(),
BPF_MOV32_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
.data = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x06, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x10, 0xbf, 0x48, 0xd6, 0x43, 0xd6,
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 256,
},
{
"ld_abs: div + abs, test 1",
.insns = {
BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_1),
BPF_LD_ABS(BPF_B, 3),
BPF_ALU64_IMM(BPF_MOV, BPF_REG_2, 2),
BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_2),
BPF_ALU64_REG(BPF_MOV, BPF_REG_8, BPF_REG_0),
BPF_LD_ABS(BPF_B, 4),
BPF_ALU64_REG(BPF_ADD, BPF_REG_8, BPF_REG_0),
BPF_LD_IND(BPF_B, BPF_REG_8, -70),
BPF_EXIT_INSN(),
},
.data = {
10, 20, 30, 40, 50,
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 10,
},
{
"ld_abs: div + abs, test 2",
.insns = {
BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_1),
BPF_LD_ABS(BPF_B, 3),
BPF_ALU64_IMM(BPF_MOV, BPF_REG_2, 2),
BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_2),
BPF_ALU64_REG(BPF_MOV, BPF_REG_8, BPF_REG_0),
BPF_LD_ABS(BPF_B, 128),
BPF_ALU64_REG(BPF_ADD, BPF_REG_8, BPF_REG_0),
BPF_LD_IND(BPF_B, BPF_REG_8, -70),
BPF_EXIT_INSN(),
},
.data = {
10, 20, 30, 40, 50,
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 0,
},
{
"ld_abs: div + abs, test 3",
.insns = {
BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_1),
BPF_ALU64_IMM(BPF_MOV, BPF_REG_7, 0),
BPF_LD_ABS(BPF_B, 3),
BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_7),
BPF_EXIT_INSN(),
},
.data = {
10, 20, 30, 40, 50,
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 0,
},
{
"ld_abs: div + abs, test 4",
.insns = {
BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_1),
BPF_ALU64_IMM(BPF_MOV, BPF_REG_7, 0),
BPF_LD_ABS(BPF_B, 256),
BPF_ALU32_REG(BPF_DIV, BPF_REG_0, BPF_REG_7),
BPF_EXIT_INSN(),
},
.data = {
10, 20, 30, 40, 50,
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 0,
},
{
"ld_abs: vlan + abs, test 1",
.insns = { },
.data = {
0x34,
},
.fill_helper = bpf_fill_ld_abs_vlan_push_pop,
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 0xbef,
},
{
"ld_abs: vlan + abs, test 2",
.insns = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
BPF_LD_ABS(BPF_B, 0),
BPF_LD_ABS(BPF_H, 0),
BPF_LD_ABS(BPF_W, 0),
BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
BPF_MOV64_IMM(BPF_REG_6, 0),
BPF_MOV64_REG(BPF_REG_1, BPF_REG_7),
BPF_MOV64_IMM(BPF_REG_2, 1),
BPF_MOV64_IMM(BPF_REG_3, 2),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_skb_vlan_push),
BPF_MOV64_REG(BPF_REG_6, BPF_REG_7),
BPF_LD_ABS(BPF_B, 0),
BPF_LD_ABS(BPF_H, 0),
BPF_LD_ABS(BPF_W, 0),
BPF_MOV64_IMM(BPF_REG_0, 42),
BPF_EXIT_INSN(),
},
.data = {
0x34,
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 42,
},
{
"ld_abs: jump around ld_abs",
.insns = { },
.data = {
10, 11,
},
.fill_helper = bpf_fill_jump_around_ld_abs,
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 10,
},
}; };
static int probe_filter_length(const struct bpf_insn *fp) static int probe_filter_length(const struct bpf_insn *fp)
...@@ -11828,7 +12077,7 @@ static int create_map_in_map(void) ...@@ -11828,7 +12077,7 @@ static int create_map_in_map(void)
return outer_map_fd; return outer_map_fd;
} }
static char bpf_vlog[32768]; static char bpf_vlog[UINT_MAX >> 8];
static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
int *map_fds) int *map_fds)
...@@ -11839,6 +12088,9 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, ...@@ -11839,6 +12088,9 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
int *fixup_prog = test->fixup_prog; int *fixup_prog = test->fixup_prog;
int *fixup_map_in_map = test->fixup_map_in_map; int *fixup_map_in_map = test->fixup_map_in_map;
if (test->fill_helper)
test->fill_helper(test);
/* Allocating HTs with 1 elem is fine here, since we only test /* Allocating HTs with 1 elem is fine here, since we only test
* for verifier and not do a runtime lookup, so the only thing * for verifier and not do a runtime lookup, so the only thing
* that really matters is value size in this case. * that really matters is value size in this case.
...@@ -11888,10 +12140,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -11888,10 +12140,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
int *passes, int *errors) int *passes, int *errors)
{ {
int fd_prog, expected_ret, reject_from_alignment; int fd_prog, expected_ret, reject_from_alignment;
int prog_len, prog_type = test->prog_type;
struct bpf_insn *prog = test->insns; struct bpf_insn *prog = test->insns;
int prog_len = probe_filter_length(prog);
char data_in[TEST_DATA_LEN] = {};
int prog_type = test->prog_type;
int map_fds[MAX_NR_MAPS]; int map_fds[MAX_NR_MAPS];
const char *expected_err; const char *expected_err;
uint32_t retval; uint32_t retval;
...@@ -11901,6 +12151,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -11901,6 +12151,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
map_fds[i] = -1; map_fds[i] = -1;
do_test_fixup(test, prog, map_fds); do_test_fixup(test, prog, map_fds);
prog_len = probe_filter_length(prog);
fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT, prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT,
...@@ -11940,8 +12191,9 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -11940,8 +12191,9 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
} }
if (fd_prog >= 0) { if (fd_prog >= 0) {
err = bpf_prog_test_run(fd_prog, 1, data_in, sizeof(data_in), err = bpf_prog_test_run(fd_prog, 1, test->data,
NULL, NULL, &retval, NULL); sizeof(test->data), NULL, NULL,
&retval, NULL);
if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) { if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
printf("Unexpected bpf_prog_test_run error\n"); printf("Unexpected bpf_prog_test_run error\n");
goto fail_log; goto fail_log;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment