mirror of https://gitee.com/openkylin/linux.git
Merge branch 'bpf-improvements'
Alexei Starovoitov says: ==================== bpf improvements Two bpf improvements: 1. allow bpf helpers like bpf_map_lookup_elem() access packet data directly for XDP programs 2. enable bpf_get_prandom_u32() for tracing programs ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
1c238763aa
|
@ -930,14 +930,14 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
|
|||
enum bpf_arg_type arg_type,
|
||||
struct bpf_call_arg_meta *meta)
|
||||
{
|
||||
struct reg_state *reg = env->cur_state.regs + regno;
|
||||
enum bpf_reg_type expected_type;
|
||||
struct reg_state *regs = env->cur_state.regs, *reg = ®s[regno];
|
||||
enum bpf_reg_type expected_type, type = reg->type;
|
||||
int err = 0;
|
||||
|
||||
if (arg_type == ARG_DONTCARE)
|
||||
return 0;
|
||||
|
||||
if (reg->type == NOT_INIT) {
|
||||
if (type == NOT_INIT) {
|
||||
verbose("R%d !read_ok\n", regno);
|
||||
return -EACCES;
|
||||
}
|
||||
|
@ -950,16 +950,29 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (type == PTR_TO_PACKET && !may_write_pkt_data(env->prog->type)) {
|
||||
verbose("helper access to the packet is not allowed for clsact\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (arg_type == ARG_PTR_TO_MAP_KEY ||
|
||||
arg_type == ARG_PTR_TO_MAP_VALUE) {
|
||||
expected_type = PTR_TO_STACK;
|
||||
if (type != PTR_TO_PACKET && type != expected_type)
|
||||
goto err_type;
|
||||
} else if (arg_type == ARG_CONST_STACK_SIZE ||
|
||||
arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
|
||||
expected_type = CONST_IMM;
|
||||
if (type != expected_type)
|
||||
goto err_type;
|
||||
} else if (arg_type == ARG_CONST_MAP_PTR) {
|
||||
expected_type = CONST_PTR_TO_MAP;
|
||||
if (type != expected_type)
|
||||
goto err_type;
|
||||
} else if (arg_type == ARG_PTR_TO_CTX) {
|
||||
expected_type = PTR_TO_CTX;
|
||||
if (type != expected_type)
|
||||
goto err_type;
|
||||
} else if (arg_type == ARG_PTR_TO_STACK ||
|
||||
arg_type == ARG_PTR_TO_RAW_STACK) {
|
||||
expected_type = PTR_TO_STACK;
|
||||
|
@ -967,20 +980,16 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
|
|||
* passed in as argument, it's a CONST_IMM type. Final test
|
||||
* happens during stack boundary checking.
|
||||
*/
|
||||
if (reg->type == CONST_IMM && reg->imm == 0)
|
||||
expected_type = CONST_IMM;
|
||||
if (type == CONST_IMM && reg->imm == 0)
|
||||
/* final test in check_stack_boundary() */;
|
||||
else if (type != PTR_TO_PACKET && type != expected_type)
|
||||
goto err_type;
|
||||
meta->raw_mode = arg_type == ARG_PTR_TO_RAW_STACK;
|
||||
} else {
|
||||
verbose("unsupported arg_type %d\n", arg_type);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (reg->type != expected_type) {
|
||||
verbose("R%d type=%s expected=%s\n", regno,
|
||||
reg_type_str[reg->type], reg_type_str[expected_type]);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (arg_type == ARG_CONST_MAP_PTR) {
|
||||
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
|
||||
meta->map_ptr = reg->map_ptr;
|
||||
|
@ -998,8 +1007,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
|
|||
verbose("invalid map_ptr to access map->key\n");
|
||||
return -EACCES;
|
||||
}
|
||||
err = check_stack_boundary(env, regno, meta->map_ptr->key_size,
|
||||
false, NULL);
|
||||
if (type == PTR_TO_PACKET)
|
||||
err = check_packet_access(env, regno, 0,
|
||||
meta->map_ptr->key_size);
|
||||
else
|
||||
err = check_stack_boundary(env, regno,
|
||||
meta->map_ptr->key_size,
|
||||
false, NULL);
|
||||
} else if (arg_type == ARG_PTR_TO_MAP_VALUE) {
|
||||
/* bpf_map_xxx(..., map_ptr, ..., value) call:
|
||||
* check [value, value + map->value_size) validity
|
||||
|
@ -1009,9 +1023,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
|
|||
verbose("invalid map_ptr to access map->value\n");
|
||||
return -EACCES;
|
||||
}
|
||||
err = check_stack_boundary(env, regno,
|
||||
meta->map_ptr->value_size,
|
||||
false, NULL);
|
||||
if (type == PTR_TO_PACKET)
|
||||
err = check_packet_access(env, regno, 0,
|
||||
meta->map_ptr->value_size);
|
||||
else
|
||||
err = check_stack_boundary(env, regno,
|
||||
meta->map_ptr->value_size,
|
||||
false, NULL);
|
||||
} else if (arg_type == ARG_CONST_STACK_SIZE ||
|
||||
arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
|
||||
bool zero_size_allowed = (arg_type == ARG_CONST_STACK_SIZE_OR_ZERO);
|
||||
|
@ -1025,11 +1043,18 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
|
|||
verbose("ARG_CONST_STACK_SIZE cannot be first argument\n");
|
||||
return -EACCES;
|
||||
}
|
||||
err = check_stack_boundary(env, regno - 1, reg->imm,
|
||||
zero_size_allowed, meta);
|
||||
if (regs[regno - 1].type == PTR_TO_PACKET)
|
||||
err = check_packet_access(env, regno - 1, 0, reg->imm);
|
||||
else
|
||||
err = check_stack_boundary(env, regno - 1, reg->imm,
|
||||
zero_size_allowed, meta);
|
||||
}
|
||||
|
||||
return err;
|
||||
err_type:
|
||||
verbose("R%d type=%s expected=%s\n", regno,
|
||||
reg_type_str[type], reg_type_str[expected_type]);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static int check_map_func_compatibility(struct bpf_map *map, int func_id)
|
||||
|
|
|
@ -437,6 +437,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
|
|||
return bpf_get_probe_write_proto();
|
||||
case BPF_FUNC_current_task_under_cgroup:
|
||||
return &bpf_current_task_under_cgroup_proto;
|
||||
case BPF_FUNC_get_prandom_u32:
|
||||
return &bpf_get_prandom_u32_proto;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1449,7 +1449,7 @@ static struct bpf_test tests[] = {
|
|||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"pkt: test1",
|
||||
"direct packet access: test1",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
|
@ -1466,7 +1466,7 @@ static struct bpf_test tests[] = {
|
|||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"pkt: test2",
|
||||
"direct packet access: test2",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
|
||||
|
@ -1499,7 +1499,7 @@ static struct bpf_test tests[] = {
|
|||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||
},
|
||||
{
|
||||
"pkt: test3",
|
||||
"direct packet access: test3",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
|
@ -1511,7 +1511,7 @@ static struct bpf_test tests[] = {
|
|||
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
|
||||
},
|
||||
{
|
||||
"pkt: test4",
|
||||
"direct packet access: test4",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct __sk_buff, data)),
|
||||
|
@ -1528,6 +1528,112 @@ static struct bpf_test tests[] = {
|
|||
.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,
|
||||
offsetof(struct xdp_md, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct xdp_md, 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_unpriv = ACCEPT,
|
||||
.result = ACCEPT,
|
||||
.prog_type = BPF_PROG_TYPE_XDP,
|
||||
},
|
||||
{
|
||||
"helper access to packet: test2, unchecked packet_ptr",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct xdp_md, 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_XDP,
|
||||
},
|
||||
{
|
||||
"helper access to packet: test3, variable add",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct xdp_md, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct xdp_md, 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_XDP,
|
||||
},
|
||||
{
|
||||
"helper access to packet: test4, packet_ptr with bad range",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct xdp_md, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct xdp_md, 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_XDP,
|
||||
},
|
||||
{
|
||||
"helper access to packet: test5, packet_ptr with too short range",
|
||||
.insns = {
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
|
||||
offsetof(struct xdp_md, data)),
|
||||
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
|
||||
offsetof(struct xdp_md, 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_XDP,
|
||||
},
|
||||
};
|
||||
|
||||
static int probe_filter_length(struct bpf_insn *fp)
|
||||
|
|
Loading…
Reference in New Issue