BPF direct packet access improvements
Subsystems (5)
Daniel Borkmann
maintainercover BPF direct packet access improvements
This set adds write support to the currently available read support for {cls,act}_bpf programs. First one is a fix for affected commit sitting in net-next and prerequisite for the second one, last patch adds a number of test cases against the verifier. For details, please see individual patches.
Thanks!
Daniel Borkmann (3):
bpf, verifier: enforce larger zero range for pkt on overloading stack buffs
bpf: direct packet write and access for helpers for clsact progs
bpf: add test cases for direct packet access
include/linux/bpf.h | 4 +- include/linux/skbuff.h | 14 +- include/uapi/linux/bpf.h | 21 +++ kernel/bpf/helpers.c | 3 + kernel/bpf/verifier.c | 56 ++++-- net/core/filter.c | 134 ++++++++++++-- samples/bpf/test_verifier.c | 433 +++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 627 insertions(+), 38 deletions(-)
Signature · 1 line
1.9.3
Daniel Borkmann
maintainerPATCH 1/3 bpf, verifier: enforce larger zero range for pkt on overloading stack buffs
Current contract for the following two helper argument types is:
* ARG_CONST_STACK_SIZE: passed argument pair must be (ptr, >0).
* ARG_CONST_STACK_SIZE_OR_ZERO: passed argument pair can be either
(NULL, 0) or (ptr, >0).
With 6841de8b0d03 ("bpf: allow helpers access the packet directly"), we can pass also raw packet data to helpers, so depending on the argument type being PTR_TO_PACKET, we now either assert memory via check_packet_access() or check_stack_boundary(). As a result, the tests in check_packet_access() currently allow more than intended with regards to reg->imm.
Back in 969bf05eb3ce ("bpf: direct packet access"), check_packet_access() was fine to ignore size argument since in check_mem_access() size was bpf_size_to_bytes() derived and prior to the call to check_packet_access() guaranteed to be larger than zero.
However, for the above two argument types, it currently means, we can have a <= 0 size and thus breaking current guarantees for helpers. Enforce a check for size <= 0 and bail out if so.
check_stack_boundary() doesn't have such an issue since it already tests for access_size <= 0 and bails out, resp. access_size == 0 in case of NULL pointer passed when allowed.
---
Affected commit sits in net-next only.
kernel/bpf/verifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/verifier.c +1 -1
@@ -671,7 +671,7 @@ static int check_packet_access(struct verifier_env *env, u32 regno, int off,struct reg_state *reg = ®s[regno]; off += reg->off; -if (off <0 || off + size > reg->range) { +if (off <0 || size <=0 || off + size > reg->range) {verbose ("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 ;
Signature · 1 line
1.9.3
Daniel Borkmann
maintainerPATCH 2/3 bpf: direct packet write and access for helpers for clsact progs
In reply to Daniel BorkmannThis work implements direct packet access for helpers and direct packet write in a similar fashion as already available for XDP types via commits 4acf6c0b84c9 ("bpf: enable direct packet data write for xdp progs") and 6841de8b0d03 ("bpf: allow helpers access the packet directly"), and as a complementary feature to the already available direct packet read for tc (cls/act) programs.
For enabling this, we need to introduce two helpers, bpf_skb_pull_data() and bpf_csum_update(). The first is generally needed for both, read and write, because they would otherwise only be limited to the current linear skb head. Usually, when the data_end test fails, programs just bail out, or, in the direct read case, use bpf_skb_load_bytes() as an alternative to overcome this limitation. If such data sits in non-linear parts, we can just pull them in once with the new helper, retest and eventually access them.
At the same time, this also makes sure the skb is uncloned, which is, of course, a necessary condition for direct write. As this needs to be an invariant for the write part only, the verifier detects writes and adds a prologue that is calling bpf_skb_pull_data() to effectively unclone the skb from the very beginning in case it is indeed cloned. The heuristic makes use of a similar trick that was done in 233577a22089 ("net: filter:
constify detection of pkt_type_offset"). This comes at zero cost for other programs that do not use the direct write feature. Should a program use this feature only sparsely and has read access for the most parts with, for example, drop return codes, then such write action can be delegated to a tail called program for mitigating this cost of potential uncloning to a late point in time where it would have been paid similarly with the bpf_skb_store_bytes() as well. Advantage of direct write is that the writes are inlined whereas the helper cannot make any length assumptions and thus needs to generate a call to memcpy() also for small sizes, as well as cost of helper call itself with sanity checks are avoided. Plus, when direct read is already used, we don't need to cache or perform rechecks on the data boundaries (due to verifier invalidating previous checks for helpers that change skb->data), so more complex programs using rewrites can benefit from switching to direct read plus write.
For direct packet access to helpers, we save the otherwise needed copy into a temp struct sitting on stack memory when use-case allows. Both facilities are enabled via may_access_direct_pkt_data() in verifier. For now, we limit this to map helpers and csum_diff, and can successively enable other helpers where we find it makes sense. Helpers that definitely cannot be allowed for this are those part of bpf_helper_changes_skb_data() since they can change underlying data, and those that write into memory as this could happen for packet typed args when still cloned. bpf_csum_update() helper accommodates for the fact that we need to fixup checksum_complete when using direct write instead of bpf_skb_store_bytes(), meaning the programs can use available helpers like bpf_csum_diff(), and implement csum_add(), csum_sub(), csum_block_add(), csum_block_sub() equivalents in eBPF together with the new helper. A usage example will be provided for iproute2's examples/bpf/ directory.
--- include/linux/bpf.h | 4 +- include/linux/skbuff.h | 14 ++++- include/uapi/linux/bpf.h | 21 ++++++++ kernel/bpf/helpers.c | 3 ++ kernel/bpf/verifier.c | 54 ++++++++++++++----- net/core/filter.c | 134 +++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 196 insertions(+), 34 deletions(-)
include/linux/bpf.h +3 -1
@@ -96,6 +96,7 @@ enum bpf_return_type {struct bpf_func_proto {u64 (*func)(u64 r1,u64 r2,u64 r3,u64 r4,u64 r5);bool gpl_only; +bool pkt_access;enum bpf_return_type ret_type;enum bpf_arg_type arg1_type;enum bpf_arg_type arg2_type;
@@ -151,7 +152,8 @@ struct bpf_verifier_ops {*/ bool (*is_valid_access)(int off,int size,enum bpf_access_type type,enum bpf_reg_type *reg_type); - +int (*gen_prologue)(struct bpf_insn *insn,bool direct_write, +const struct bpf_prog *prog);u32 (*convert_ctx_access)(enum bpf_access_type type,int dst_reg,int src_reg,int ctx_off,struct bpf_insn *insn,struct bpf_prog *prog);
include/linux/skbuff.h +12 -2
@@ -676,13 +676,23 @@ struct sk_buff {*/ kmemcheck_bitfield_begin (flags1);__u16 queue_mapping; + +/* if you move cloned around you also must adapt those constants */ +#ifdef __BIG_ENDIAN_BITFIELD +#define CLONED_MASK (1 << 7) +#else +#define CLONED_MASK 1 +#endif +#define CLONED_OFFSET () offsetof(struct sk_buff, __cloned_offset) + +__u8 __cloned_offset[0 ]; __u8 cloned:1, nohdr:1, fclone:2, peeked:1, head_frag:1, - xmit_more:1; -/* one bit hole */ + xmit_more:1, + __unused:1; /* one bit hole */kmemcheck_bitfield_end (flags1);/* fields enclosed in headers_start/headers_end are copied
include/uapi/linux/bpf.h +21 -0
@@ -398,6 +398,27 @@ enum bpf_func_id {*/ BPF_FUNC_skb_change_tail, +/** +* bpf_skb_pull_data(skb, len) +* The helper will pull in non-linear data in case the +* skb is non-linear and not all of len are part of the +* linear section. Only needed for read/write with direct +* packet access. +* @skb: pointer to skb +* @len: len to make read/writeable +* Return: 0 on success or negative error +*/ + BPF_FUNC_skb_pull_data, + +/** +* bpf_csum_update(skb, csum) +* Adds csum into skb->csum in case of CHECKSUM_COMPLETE. +* @skb: pointer to skb +* @csum: csum to add +* Return: csum on success or negative error +*/ + BPF_FUNC_csum_update, + __BPF_FUNC_MAX_ID, };
kernel/bpf/helpers.c +3 -0
@@ -36,6 +36,7 @@ BPF_CALL_2(bpf_map_lookup_elem, struct bpf_map *, map, void *, key)const struct bpf_func_proto bpf_map_lookup_elem_proto = { .func = bpf_map_lookup_elem, .gpl_only = false, + .pkt_access = true, .ret_type =RET_PTR_TO_MAP_VALUE_OR_NULL , .arg1_type =ARG_CONST_MAP_PTR , .arg2_type =ARG_PTR_TO_MAP_KEY ,
@@ -51,6 +52,7 @@ BPF_CALL_4(bpf_map_update_elem, struct bpf_map *, map, void *, key,const struct bpf_func_proto bpf_map_update_elem_proto = { .func = bpf_map_update_elem, .gpl_only = false, + .pkt_access = true, .ret_type =RET_INTEGER , .arg1_type =ARG_CONST_MAP_PTR , .arg2_type =ARG_PTR_TO_MAP_KEY ,
@@ -67,6 +69,7 @@ BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key)const struct bpf_func_proto bpf_map_delete_elem_proto = { .func = bpf_map_delete_elem, .gpl_only = false, + .pkt_access = true, .ret_type =RET_INTEGER , .arg1_type =ARG_CONST_MAP_PTR , .arg2_type =ARG_PTR_TO_MAP_KEY ,
kernel/bpf/verifier.c +40 -14
110 lines not on this page · raw message
net/core/filter.c +117 -17
200 lines not on this page · raw message
Signature · 1 line
1.9.3
Daniel Borkmann
maintainerPATCH 3/3 bpf: add test cases for direct packet access
In reply to Daniel BorkmannAdd couple of test cases for direct write and the negative size issue, and also adjust the direct packet access test4 since it asserts that writes are not possible, but since we've just added support for writes, we need to invert the verdict to ACCEPT, of course. Summary: 133 PASSED, 0 FAILED.
--- samples/bpf/test_verifier.c | 433 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 430 insertions(+), 3 deletions(-)
samples/bpf/test_verifier.c +430 -3
@@ -291,6 +291,29 @@ static struct bpf_test tests[] = { .result = REJECT, }, { + "invalid argument register", + .insns = { +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_get_cgroup_classid), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_get_cgroup_classid), + BPF_EXIT_INSN(), + }, + .errstr ="R1 !read_ok" , + .result = REJECT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"non-invalid argument register" , + .insns = { +BPF_ALU64_REG (BPF_MOV ,BPF_REG_6 ,BPF_REG_1 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_get_cgroup_classid), +BPF_ALU64_REG (BPF_MOV ,BPF_REG_1 ,BPF_REG_6 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_get_cgroup_classid), + BPF_EXIT_INSN(), + }, + .result =ACCEPT , + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + {"check valid spill/fill" , .insns = {/* spill R1(ctx) into stack */
@@ -1210,6 +1233,54 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, { + "raw_stack: skb_load_bytes, negative len", + .insns = { +BPF_MOV64_IMM (BPF_REG_2 ,4 ), +BPF_ALU64_REG (BPF_MOV ,BPF_REG_6 ,BPF_REG_10 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,-8 ), +BPF_MOV64_REG (BPF_REG_3 ,BPF_REG_6 ), +BPF_MOV64_IMM (BPF_REG_4 ,-8 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_skb_load_bytes), +BPF_LDX_MEM (BPF_DW ,BPF_REG_0 ,BPF_REG_6 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid stack type R3", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"raw_stack: skb_load_bytes, negative len 2" , + .insns = { +BPF_MOV64_IMM (BPF_REG_2 ,4 ), +BPF_ALU64_REG (BPF_MOV ,BPF_REG_6 ,BPF_REG_10 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,-8 ), +BPF_MOV64_REG (BPF_REG_3 ,BPF_REG_6 ), +BPF_MOV64_IMM (BPF_REG_4 , ~0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_skb_load_bytes), +BPF_LDX_MEM (BPF_DW ,BPF_REG_0 ,BPF_REG_6 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid stack type R3", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"raw_stack: skb_load_bytes, zero len" , + .insns = { +BPF_MOV64_IMM (BPF_REG_2 ,4 ), +BPF_ALU64_REG (BPF_MOV ,BPF_REG_6 ,BPF_REG_10 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,-8 ), +BPF_MOV64_REG (BPF_REG_3 ,BPF_REG_6 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_skb_load_bytes), +BPF_LDX_MEM (BPF_DW ,BPF_REG_0 ,BPF_REG_6 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid stack type R3", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + {"raw_stack: skb_load_bytes, no init" , .insns = { BPF_MOV64_IMM(BPF_REG_2, 4),
@@ -1511,7 +1582,7 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, }, { - "direct packet access: test4", + "direct packet access: test4 (write)", .insns = {BPF_LDX_MEM (BPF_W ,BPF_REG_2 ,BPF_REG_1 , offsetof(struct __sk_buff, data)),
@@ -1524,8 +1595,7 @@ static struct bpf_test tests[] = {BPF_MOV64_IMM (BPF_REG_0 ,0 ), BPF_EXIT_INSN(), }, - .errstr ="cannot write" , - .result = REJECT, + .result =ACCEPT , .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, {
@@ -1631,6 +1701,26 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, { + "direct packet access: test10 (write invalid)", + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_2 ,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_2 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_0 ,8 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_0 ,BPF_REG_3 ,2 ), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), +BPF_EXIT_INSN (), +BPF_STX_MEM (BPF_B ,BPF_REG_2 ,BPF_REG_2 ,0 ), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .errstr ="invalid access to packet" , + .result = REJECT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + {"helper access to packet: test1, valid packet_ptr range" , .insns = { BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
@@ -1736,6 +1826,343 @@ static struct bpf_test tests[] = { .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_XDP, }, + { + "helper access to packet: test6, cls valid packet_ptr range", + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_2 ,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_1 ,BPF_REG_2 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,8 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_3 ,5 ), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_MOV64_REG (BPF_REG_3 ,BPF_REG_2 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_map_update_elem), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .fixup = {5}, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test7, cls unchecked packet_ptr" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_2 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_map_lookup_elem), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .fixup = {1}, + .result = REJECT, + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test8, cls variable add" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_2 ,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_4 ,BPF_REG_2 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_4 ,8 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_4 ,BPF_REG_3 ,10 ), +BPF_LDX_MEM (BPF_B ,BPF_REG_5 ,BPF_REG_2 ,0 ), +BPF_MOV64_REG (BPF_REG_4 ,BPF_REG_2 ), +BPF_ALU64_REG (BPF_ADD ,BPF_REG_4 ,BPF_REG_5 ), +BPF_MOV64_REG (BPF_REG_5 ,BPF_REG_4 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_5 ,8 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_5 ,BPF_REG_3 ,4 ), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_MOV64_REG (BPF_REG_2 ,BPF_REG_4 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_map_lookup_elem), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .fixup = {11}, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test9, cls packet_ptr with bad range" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_2 ,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_4 ,BPF_REG_2 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_4 ,4 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_4 ,BPF_REG_3 ,2 ), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), +BPF_EXIT_INSN (), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_map_lookup_elem), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .fixup = {7}, + .result = REJECT, + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test10, cls packet_ptr with too short range" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_2 ,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_ALU64_IMM (BPF_ADD ,BPF_REG_2 ,1 ), +BPF_MOV64_REG (BPF_REG_4 ,BPF_REG_2 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_4 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_4 ,BPF_REG_3 ,3 ), +BPF_LD_MAP_FD (BPF_REG_1 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_map_lookup_elem), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .fixup = {6}, + .result = REJECT, + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test11, cls unsuitable helper 1" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_3 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_3 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_3 ,BPF_REG_7 ,4 ), +BPF_MOV64_IMM (BPF_REG_2 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,42 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_skb_store_bytes), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "helper access to the packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test12, cls unsuitable helper 2" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_MOV64_REG (BPF_REG_3 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,8 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_6 ,BPF_REG_7 ,3 ), +BPF_MOV64_IMM (BPF_REG_2 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,4 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_skb_load_bytes), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "helper access to the packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test13, cls helper ok" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_MOV64_IMM (BPF_REG_2 ,4 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =ACCEPT , + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test14, cls helper fail sub" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_ALU64_IMM (BPF_SUB ,BPF_REG_1 ,4 ), +BPF_MOV64_IMM (BPF_REG_2 ,4 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "type=inv expected=fp", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test15, cls helper fail range 1" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_MOV64_IMM (BPF_REG_2 ,8 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test16, cls helper fail range 2" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_MOV64_IMM (BPF_REG_2 ,-9 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test17, cls helper fail range 3" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +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_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test18, cls helper fail range zero" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +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_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test19, pkt end as input" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_7 ), +BPF_MOV64_IMM (BPF_REG_2 ,4 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "R1 type=pkt_end expected=fp", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { +"helper access to packet: test20, wrong reg" , + .insns = { +BPF_LDX_MEM (BPF_W ,BPF_REG_6 ,BPF_REG_1 , + offsetof(struct __sk_buff , data)), +BPF_LDX_MEM (BPF_W ,BPF_REG_7 ,BPF_REG_1 , + offsetof(struct __sk_buff , data_end)), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_6 ,1 ), +BPF_MOV64_REG (BPF_REG_1 ,BPF_REG_6 ), +BPF_ALU64_IMM (BPF_ADD ,BPF_REG_1 ,7 ), +BPF_JMP_REG (BPF_JGT ,BPF_REG_1 ,BPF_REG_7 ,6 ), +BPF_MOV64_IMM (BPF_REG_2 ,4 ), +BPF_MOV64_IMM (BPF_REG_3 ,0 ), +BPF_MOV64_IMM (BPF_REG_4 ,0 ), +BPF_MOV64_IMM (BPF_REG_5 ,0 ), +BPF_RAW_INSN (BPF_JMP |BPF_CALL ,0 ,0 ,0 , BPF_FUNC_csum_diff), +BPF_MOV64_IMM (BPF_REG_0 ,0 ), + BPF_EXIT_INSN(), + }, + .result =REJECT , + .errstr = "invalid access to packet", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, };static int probe_filter_length (struct bpf_insn *fp)
Signature · 1 line
1.9.3
David Miller
maintainerFrom: Daniel Borkmann <[email protected]>
Date: Tue, 20 Sep 2016 00:26:11 +0200
Quoted 5 lines
This set adds write support to the currently available read support for {cls,act}_bpf programs. First one is a fix for affected commit sitting in net-next and prerequisite for the second one, last patch adds a number of test cases against the verifier. For details, please see individual patches.
Series applied.