bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics
Subsystems (9)
v2 cover bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics
This patch set intends to change verifier ARG_CONST_SIZE_OR_ZERO semantics so that simpler bpf programs can be written with verifier acceptance. Patch #1 comment provided the detailed examples and the patch itself implements the new semantics. Patch #2 changes bpf_probe_read helper arg2 type from ARG_CONST_SIZE to ARG_CONST_SIZE_OR_ZERO. Patch #3 fixed a few test cases and added some for better coverage.
Changelog:
v1 -> v2:
Fix typo in commit message pointed by Sergei Shtylyov
Yonghong Song (3):
bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics
bpf: change helper bpf_probe_read arg2 type to ARG_CONST_SIZE_OR_ZERO
bpf: fix and add test cases for ARG_CONST_SIZE_OR_ZERO semantics
change
kernel/bpf/verifier.c | 40 +++++---- kernel/trace/bpf_trace.c | 8 +- tools/testing/selftests/bpf/test_verifier.c | 131 ++++++++++++++++++++++++---- 3 files changed, 142 insertions(+), 37 deletions(-)
Signature · 1 line
2.9.5
PATCH v2 1/3 bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics
For helpers, the argument type ARG_CONST_SIZE_OR_ZERO permits the access size to be 0 when accessing the previous argument (arg). Right now, it requires the arg needs to be NULL when size passed is 0 or could be 0. It also requires a non-NULL arg when the size is proved to be non-0.
This patch changes verifier ARG_CONST_SIZE_OR_ZERO behavior such that for size-0 or possible size-0, it is not required the arg equal to NULL.
There are a couple of reasons for this semantics change, and all of them intends to simplify user bpf programs which may improve user experience and/or increase chances of verifier acceptance. Together with the next patch which changes bpf_probe_read arg2 type from ARG_CONST_SIZE to ARG_CONST_SIZE_OR_ZERO, the following two examples, which fail the verifier currently, are able to get verifier acceptance.
Example 1:
==========
unsigned long len = pend - pstart;
len = len > MAX_PAYLOAD_LEN ? MAX_PAYLOAD_LEN : len; len &= MAX_PAYLOAD_LEN; bpf_probe_read(data->payload, len, pstart);
It does not have test for "len > 0" and it failed the verifier. Users may not be aware that they have to add this test. Converting the bpf_probe_read helper to have ARG_CONST_SIZE_OR_ZERO helps the above code get verifier acceptance.
Example 2:
==========
Here is one example where llvm "messed up" the code and the verifier fails.
......
unsigned long len = pend - pstart;
if (len > 0 && len <= MAX_PAYLOAD_LEN)
bpf_probe_read(data->payload, len, pstart);
......
The compiler generates the following code and verifier fails:
......
39: (79) r2 = *(u64 *)(r10 -16)
40: (1f) r2 -= r8
41: (bf) r1 = r2
42: (07) r1 += -1
43: (25) if r1 > 0xffe goto pc+3
R0=inv(id=0) R1=inv(id=0,umax_value=4094,var_off=(0x0; 0xfff)) R2=inv(id=0) R6=map_value(id=0,off=0,ks=4,vs=4095,imm=0) R7=inv(id=0) R8=inv(id=0) R9=inv0 R10=fp0
44: (bf) r1 = r6
45: (bf) r3 = r8
46: (85) call bpf_probe_read#45
R2 min value is negative, either use unsigned or 'var &= const'
......
The compiler optimization is correct. If r1 = 0,
r1 - 1 = 0xffffffffffffffff > 0xffe. If r1 != 0, r1 - 1 will not wrap. r1 > 0xffe at insn #43 can actually capture
both "r1 > 0" and "len <= MAX_PAYLOAD_LEN".
This however causes an issue in verifier as the value range of arg2 "r2" does not properly get refined and lead to verification failure.
Relaxing bpf_prog_read arg2 from ARG_CONST_SIZE to ARG_CONST_SIZE_OR_ZERO allows the following simplied code:
unsigned long len = pend - pstart;
if (len <= MAX_PAYLOAD_LEN)
bpf_probe_read(data->payload, len, pstart);
The llvm compiler will generate less complex code and the verifier is able to verify that the program is okay.
--- kernel/bpf/verifier.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-)
kernel/bpf/verifier.c +24 -16
@@ -799,12 +799,13 @@ static int check_stack_read(struct bpf_verifier_env *env,/* check read/write into map element returned by bpf_map_lookup_elem() */ static int __check_map_access (struct bpf_verifier_env *env,u32 regno,int off, -int size) +int size,bool zero_size_allowed) {struct bpf_reg_state *regs =cur_regs (env);struct bpf_map *map = regs[regno].map_ptr; -if (off <0 || size <=0 || off + size > map->value_size) { +if (off <0 || size <0 || (size ==0 && !zero_size_allowed) || + off + size > map->value_size) {verbose (env,"invalid access to map value, value_size=%d off=%d size=%d\n" , map->value_size, off, size);return -EACCES ;
@@ -814,7 +815,7 @@ static int __check_map_access(struct bpf_verifier_env *env, u32 regno, int off,/* check read/write into a map element with possible variable offset */ static int check_map_access (struct bpf_verifier_env *env,u32 regno, -int off,int size) +int off,int size,bool zero_size_allowed) {struct bpf_verifier_state *state = env->cur_state;struct bpf_reg_state *reg = &state->regs[regno];
@@ -837,7 +838,8 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, regno);return -EACCES ; } - err =__check_map_access (env, regno, reg->smin_value + off, size); + err =__check_map_access (env, regno, reg->smin_value + off, size, + zero_size_allowed);if (err) {verbose (env,"R%d min value is outside of the array range\n" , regno);
@@ -853,7 +855,8 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, regno);return -EACCES ; } - err =__check_map_access (env, regno, reg->umax_value + off, size); + err =__check_map_access (env, regno, reg->umax_value + off, size, + zero_size_allowed);if (err)verbose (env,"R%d max value is outside of the array range\n" , regno);
@@ -889,12 +892,13 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env, }static int __check_packet_access (struct bpf_verifier_env *env,u32 regno, -int off,int size) +int off,int size,bool zero_size_allowed) {struct bpf_reg_state *regs =cur_regs (env);struct bpf_reg_state *reg = ®s[regno]; -if (off <0 || size <=0 || (u64 )off + size > reg->range) { +if (off <0 || size <0 || (size ==0 && !zero_size_allowed) || + (u64 )off + size > reg->range) {verbose (env,"invalid access to packet, off=%d size=%d, R%d(id=%d,off=%d,r=%d)\n" , off, size, regno, reg->id, reg->off, reg->range);return -EACCES ;
@@ -903,7 +907,7 @@ static int __check_packet_access(struct bpf_verifier_env *env, u32 regno, }static int check_packet_access (struct bpf_verifier_env *env,u32 regno,int off, -int size) +int size,bool zero_size_allowed) {struct bpf_reg_state *regs =cur_regs (env);struct bpf_reg_state *reg = ®s[regno];
@@ -922,7 +926,7 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off, regno);return -EACCES ; } - err =__check_packet_access (env, regno, off, size); + err =__check_packet_access (env, regno, off, size, zero_size_allowed);if (err) {verbose (env,"R%d offset is outside of the packet\n" , regno);return err;
@@ -1097,7 +1101,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regnreturn -EACCES ; } - err =check_map_access (env, regno, off, size); + err =check_map_access (env, regno, off, size, false);if (!err && t ==BPF_READ && value_regno >=0 )mark_reg_unknown (env, regs, value_regno);
@@ -1184,7 +1188,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn value_regno);return -EACCES ; } - err =check_packet_access (env, regno, off, size); + err =check_packet_access (env, regno, off, size, false);if (!err && t ==BPF_READ && value_regno >=0 )mark_reg_unknown (env, regs, value_regno); }else {
@@ -1281,7 +1285,7 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno, } off = regs[regno].off + regs[regno].var_off.value;if (off >=0 || off < -MAX_BPF_STACK || off + access_size >0 || - access_size <=0 ) { + access_size <0 || (access_size ==0 && !zero_size_allowed)) {verbose (env,"invalid stack type R%d off=%d access_size=%d\n" , regno, off, access_size);return -EACCES ;
@@ -1319,9 +1323,11 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,switch (reg->type) {case PTR_TO_PACKET :case PTR_TO_PACKET_META : -return check_packet_access (env, regno, reg->off, access_size); +return check_packet_access (env, regno, reg->off, access_size, + zero_size_allowed);case PTR_TO_MAP_VALUE : -return check_map_access (env, regno, reg->off, access_size); +return check_map_access (env, regno, reg->off, access_size, + zero_size_allowed);default :/* scalar_value|ptr_to_stack or invalid ptr */ return check_stack_boundary (env, regno, access_size, zero_size_allowed, meta);
@@ -1415,7 +1421,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, }if (type_is_pkt_pointer (type)) err =check_packet_access (env, regno, reg->off, - meta->map_ptr->key_size); + meta->map_ptr->key_size, + false);else err = check_stack_boundary(env, regno, meta->map_ptr->key_size,
@@ -1431,7 +1438,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, }if (type_is_pkt_pointer (type)) err =check_packet_access (env, regno, reg->off, - meta->map_ptr->value_size); + meta->map_ptr->value_size, + false);else err = check_stack_boundary(env, regno, meta->map_ptr->value_size,
Signature · 1 line
2.9.5
Quoted 18 lines · Yonghong Song
For helpers, the argument type
ARG_CONST_SIZE_OR_ZEROpermits the access size to be 0 when accessing the previous argument (arg). Right now, it requires the arg needs to be NULL when size passed is 0 or could be 0. It also requires a non-NULL arg when the size is proved to be non-0.This patch changes verifier
ARG_CONST_SIZE_OR_ZERObehavior such that for size-0 or possible size-0, it is not required the arg equal to NULL.There are a couple of reasons for this semantics change, and all of them intends to simplify user bpf programs which may improve user experience and/or increase chances of verifier acceptance. Together with the next patch which changes
bpf_probe_readarg2 type fromARG_CONST_SIZEtoARG_CONST_SIZE_OR_ZERO, the following two examples, which fail the verifier currently, are able to get verifier acceptance.
Quoted 1 line
Example 1:
Looks like patchwork messes up your patch description, see:
http://patchwork.ozlabs.org/patch/837213/
I think it matches the '===' line with start of the patch. Would be good if this can be fixed.
Quoted 52 lines
==========
unsigned long len = pend - pstart; len = len > MAX_PAYLOAD_LEN ? MAX_PAYLOAD_LEN : len; len &= MAX_PAYLOAD_LEN; bpf_probe_read(data->payload, len, pstart);It does not have test for "len > 0" and it failed the verifier. Users may not be aware that they have to add this test. Converting the
bpf_probe_readhelper to haveARG_CONST_SIZE_OR_ZEROhelps the above code get verifier acceptance.Example 2:
==========
Here is one example where llvm "messed up" the code and the verifier fails.......
unsigned long len = pend - pstart; if (len > 0 && len <= MAX_PAYLOAD_LEN) bpf_probe_read(data->payload, len, pstart);......
The compiler generates the following code and verifier fails:
......
39: (79) r2 = *(u64 *)(r10 -16)
40: (1f) r2 -= r8
41: (bf) r1 = r2
42: (07) r1 += -1
43: (25) if r1 >0xffegoto pc+3
R0=inv(id=0) R1=inv(id=0,umax_value=4094,var_off=(0x0;0xfff)) R2=inv(id=0) R6=map_value(id=0,off=0,ks=4,vs=4095,imm=0) R7=inv(id=0) R8=inv(id=0) R9=inv0 R10=fp0
44: (bf) r1 = r6
45: (bf) r3 = r8
46: (85) call bpf_probe_read#45
R2 min value is negative, either use unsigned or 'var &= const'
......The compiler optimization is correct. If r1 = 0,
r1 - 1 =0xffffffffffffffff>0xffe. If r1 != 0, r1 - 1 will not wrap. r1 >0xffeat insn #43 can actually capture
both "r1 > 0" and "len <=MAX_PAYLOAD_LEN".
This however causes an issue in verifier as the value range of arg2 "r2" does not properly get refined and lead to verification failure.Relaxing
bpf_prog_readarg2 fromARG_CONST_SIZEtoARG_CONST_SIZE_OR_ZEROallows the following simplied code:unsigned long len = pend - pstart; if (len <= MAX_PAYLOAD_LEN) bpf_probe_read(data->payload, len, pstart);
Quoted 5 lines
The llvm compiler will generate less complex code and the verifier is able to verify that the program is okay.
Signed-off-by Yonghong Song <[email protected]>
PATCH v2 2/3 bpf: change helper bpf_probe_read arg2 type to ARG_CONST_SIZE_OR_ZERO
In reply to Yonghong SongThe helper bpf_probe_read arg2 type is changed
from ARG_CONST_SIZE to ARG_CONST_SIZE_OR_ZERO to permit size-0 buffer. Together with newer ARG_CONST_SIZE_OR_ZERO semantics which allows non-NULL buffer with size 0, this allows simpler bpf programs with verifier acceptance. The previous commit which changes ARG_CONST_SIZE_OR_ZERO semantics has details on examples.
--- kernel/trace/bpf_trace.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
kernel/trace/bpf_trace.c +6 -2
@@ -78,12 +78,16 @@ EXPORT_SYMBOL_GPL(trace_call_bpf); BPF_CALL_3(bpf_probe_read, void *, dst, u32, size, const void *, unsafe_ptr) { -int ret; +int ret =0 ; + +if (unlikely (size ==0 )) + goto out; ret =probe_kernel_read (dst, unsafe_ptr, size);if (unlikely (ret <0 ))memset (dst,0 , size); + out:return ret; }
@@ -92,7 +96,7 @@ static const struct bpf_func_proto bpf_probe_read_proto = { .gpl_only = true, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_UNINIT_MEM, - .arg2_type = ARG_CONST_SIZE, + .arg2_type = ARG_CONST_SIZE_OR_ZERO, .arg3_type = ARG_ANYTHING, };
Signature · 1 line
2.9.5
Re: [PATCH net-next 2/3 v2] bpf: change helper bpf_probe_read arg2 type to ARG_CONST_SIZE_OR_ZERO
Quoted 10 lines · Yonghong Song
The helper
bpf_probe_readarg2 type is changed
fromARG_CONST_SIZEtoARG_CONST_SIZE_OR_ZEROto permit size-0 buffer. Together with newerARG_CONST_SIZE_OR_ZEROsemantics which allows non-NULL buffer with size 0, this allows simpler bpf programs with verifier acceptance. The previous commit which changesARG_CONST_SIZE_OR_ZEROsemantics has details on examples.Signed-off-by Yonghong Song <[email protected]>
PATCH v2 3/3 bpf: fix and add test cases for ARG_CONST_SIZE_OR_ZERO semantics change
In reply to Yonghong SongFix a few test cases to allow non-NULL map/packet/stack pointer with size = 0. Change a few tests using bpf_probe_read to use bpf_probe_write_user so ARG_CONST_SIZE arg can still be properly tested. One existing test case already covers size = 0 with non-NULL packet pointer, so add additional tests so all cases of size = 0 and 0 <= size <= legal_upper_bound with non-NULL map/packet/stack pointer are covered.
--- tools/testing/selftests/bpf/test_verifier.c | 131 ++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 19 deletions(-)
tools/testing/selftests/bpf/test_verifier.c +112 -19
@@ -3579,7 +3579,7 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, { - "helper access to packet: test19, cls helper fail range zero", + "helper access to packet: test19, cls helper range zero", .insns = {BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , offsetof(struct __sk_buff, data)),
@@ -3599,8 +3599,7 @@ static struct bpf_test tests[] = {BPF_MOV64_IMM (BPF_REG_0 ,0 ), BPF_EXIT_INSN(), }, - .result =REJECT , - .errstr = "invalid access to packet", + .result =ACCEPT , .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, {
@@ -4379,10 +4378,10 @@ static struct bpf_test tests[] = {BPF_LD_MAP_FD (BPF_REG_1 ,0 ),BPF_EMIT_CALL (BPF_FUNC_map_lookup_elem),BPF_JMP_IMM (BPF_JEQ ,BPF_REG_0 ,0 ,4 ), -BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_0 ), -BPF_MOV64_IMM (BPF_REG_2 ,0 ), +BPF_MOV64_IMM (BPF_REG_1 ,0 ), +BPF_MOV64_REG (BPF_REG_2 ,BPF_REG_0 ),BPF_MOV64_IMM (BPF_REG_3 ,0 ), -BPF_EMIT_CALL (BPF_FUNC_probe_read), +BPF_EMIT_CALL (BPF_FUNC_probe_write_user), BPF_EXIT_INSN(), }, .fixup_map2 = { 3 },
@@ -4486,9 +4485,10 @@ static struct bpf_test tests[] = {BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_0 ),BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 , offsetof(struct test_val , foo)), -BPF_MOV64_IMM (BPF_REG_2 ,0 ), +BPF_MOV64_REG (BPF_REG_2 ,BPF_REG_1 ), +BPF_MOV64_IMM (BPF_REG_1 ,0 ),BPF_MOV64_IMM (BPF_REG_3 ,0 ), -BPF_EMIT_CALL (BPF_FUNC_probe_read), +BPF_EMIT_CALL (BPF_FUNC_probe_write_user), BPF_EXIT_INSN(), }, .fixup_map2 = { 3 },
@@ -4622,13 +4622,14 @@ static struct bpf_test tests[] = { BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), BPF_MOV64_IMM(BPF_REG_3, 0), BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), - BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), + BPF_MOV64_IMM(BPF_REG_1, 0), BPF_MOV64_IMM(BPF_REG_3, 0), -BPF_EMIT_CALL (BPF_FUNC_probe_read), +BPF_EMIT_CALL (BPF_FUNC_probe_write_user),BPF_EXIT_INSN (), }, .fixup_map2 = { 3 }, - .errstr = "R1 min value is outside of the array range", + .errstr = "R2 min value is outside of the array range", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, },
@@ -4765,13 +4766,14 @@ static struct bpf_test tests[] = { BPF_JMP_IMM(BPF_JGT, BPF_REG_3, offsetof(struct test_val, foo), 4), BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), - BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), + BPF_MOV64_IMM(BPF_REG_1, 0), BPF_MOV64_IMM(BPF_REG_3, 0), -BPF_EMIT_CALL (BPF_FUNC_probe_read), +BPF_EMIT_CALL (BPF_FUNC_probe_write_user),BPF_EXIT_INSN (), }, .fixup_map2 = { 3 }, - .errstr = "R1 min value is outside of the array range", + .errstr = "R2 min value is outside of the array range", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, },
@@ -5350,7 +5352,7 @@ static struct bpf_test tests[] = {BPF_EMIT_CALL (BPF_FUNC_probe_read),BPF_EXIT_INSN (), }, - .errstr = "invalid stack type R1 off=-64 access_size=0", + .errstr = "invalid indirect read from stack off -64+0 size 64", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, },
@@ -5505,7 +5507,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .errstr = "invalid stack type R1 off=-64 access_size=0", + .errstr = "invalid indirect read from stack off -64+0 size 64", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, },
@@ -5668,7 +5670,7 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, { - "helper access to variable memory: size = 0 not allowed on != NULL", + "helper access to variable memory: size = 0 allowed on != NULL stack pointer", .insns = {BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_10 ), BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
@@ -5681,8 +5683,99 @@ static struct bpf_test tests[] = {BPF_EMIT_CALL (BPF_FUNC_csum_diff), BPF_EXIT_INSN(), }, - .errstr ="invalid stack type R1 off=-8 access_size=0" , - .result = REJECT, + .result =ACCEPT , + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to variable memory: size = 0 allowed on != NULL map pointer" , + .insns = { +BPF_ST_MEM (BPF_DW ,BPF_REG_10 ,-8 ,0 ), +BPF_MOV64_REG (BPF_REG_2 ,BPF_REG_10 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_2 ,-8 ), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , + BPF_FUNC_map_lookup_elem), +BPF_JMP_IMM (BPF_JEQ ,BPF_REG_0 ,0 ,6 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_0 ), +BPF_MOV64_IMM (BPF_REG_2 ,0 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_EMIT_CALL (BPF_FUNC_csum_diff), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to variable memory: size possible = 0 allowed on != NULL stack pointer" , + .insns = { +BPF_ST_MEM (BPF_DW ,BPF_REG_10 ,-8 ,0 ), +BPF_MOV64_REG (BPF_REG_2 ,BPF_REG_10 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_2 ,-8 ), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , + BPF_FUNC_map_lookup_elem), +BPF_JMP_IMM (BPF_JEQ ,BPF_REG_0 ,0 ,9 ), +BPF_LDX_MEM (BPF_DW ,BPF_REG_2 ,BPF_REG_0 ,0 ), +BPF_JMP_IMM (BPF_JGT ,BPF_REG_2 ,8 ,7 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_10 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,-8 ), +BPF_STX_MEM (BPF_DW ,BPF_REG_1 ,BPF_REG_2 ,0 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_EMIT_CALL (BPF_FUNC_csum_diff), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to variable memory: size possible = 0 allowed on != NULL map pointer" , + .insns = { +BPF_ST_MEM (BPF_DW ,BPF_REG_10 ,-8 ,0 ), +BPF_MOV64_REG (BPF_REG_2 ,BPF_REG_10 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_2 ,-8 ), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , + BPF_FUNC_map_lookup_elem), +BPF_JMP_IMM (BPF_JEQ ,BPF_REG_0 ,0 ,7 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_0 ), +BPF_LDX_MEM (BPF_DW ,BPF_REG_2 ,BPF_REG_0 ,0 ), +BPF_JMP_IMM (BPF_JGT ,BPF_REG_2 ,8 ,4 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_EMIT_CALL (BPF_FUNC_csum_diff), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to variable memory: size possible = 0 allowed on != NULL packet pointer" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_3 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_MOV64_REG (BPF_REG_0 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_0 ,8 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_0 ,BPF_REG_3 ,7 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_LDX_MEM (BPF_DW ,BPF_REG_2 ,BPF_REG_6 ,0 ), +BPF_JMP_IMM (BPF_JGT ,BPF_REG_2 ,8 ,4 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_EMIT_CALL (BPF_FUNC_csum_diff), + BPF_EXIT_INSN(), + }, + .result =ACCEPT , .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, {
Signature · 1 line
2.9.5
Re: [PATCH net-next 3/3 v2] bpf: fix and add test cases for ARG_CONST_SIZE_OR_ZERO semantics change
Quoted 10 lines · Yonghong Song
Fix a few test cases to allow non-NULL map/packet/stack pointer with size = 0. Change a few tests using
bpf_probe_readto usebpf_probe_write_usersoARG_CONST_SIZEarg can still be properly tested. One existing test case already covers size = 0 with non-NULL packet pointer, so add additional tests so all cases of size = 0 and 0 <= size <=legal_upper_boundwith non-NULL map/packet/stack pointer are covered.Signed-off-by Yonghong Song <[email protected]>