Commit 1c238763 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 03ff4979 8937bd80
...@@ -930,14 +930,14 @@ static int check_func_arg(struct verifier_env *env, u32 regno, ...@@ -930,14 +930,14 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
enum bpf_arg_type arg_type, enum bpf_arg_type arg_type,
struct bpf_call_arg_meta *meta) struct bpf_call_arg_meta *meta)
{ {
struct reg_state *reg = env->cur_state.regs + regno; struct reg_state *regs = env->cur_state.regs, *reg = &regs[regno];
enum bpf_reg_type expected_type; enum bpf_reg_type expected_type, type = reg->type;
int err = 0; int err = 0;
if (arg_type == ARG_DONTCARE) if (arg_type == ARG_DONTCARE)
return 0; return 0;
if (reg->type == NOT_INIT) { if (type == NOT_INIT) {
verbose("R%d !read_ok\n", regno); verbose("R%d !read_ok\n", regno);
return -EACCES; return -EACCES;
} }
...@@ -950,16 +950,29 @@ static int check_func_arg(struct verifier_env *env, u32 regno, ...@@ -950,16 +950,29 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
return 0; 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 || if (arg_type == ARG_PTR_TO_MAP_KEY ||
arg_type == ARG_PTR_TO_MAP_VALUE) { arg_type == ARG_PTR_TO_MAP_VALUE) {
expected_type = PTR_TO_STACK; expected_type = PTR_TO_STACK;
if (type != PTR_TO_PACKET && type != expected_type)
goto err_type;
} else if (arg_type == ARG_CONST_STACK_SIZE || } else if (arg_type == ARG_CONST_STACK_SIZE ||
arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) { arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
expected_type = CONST_IMM; expected_type = CONST_IMM;
if (type != expected_type)
goto err_type;
} else if (arg_type == ARG_CONST_MAP_PTR) { } else if (arg_type == ARG_CONST_MAP_PTR) {
expected_type = CONST_PTR_TO_MAP; expected_type = CONST_PTR_TO_MAP;
if (type != expected_type)
goto err_type;
} else if (arg_type == ARG_PTR_TO_CTX) { } else if (arg_type == ARG_PTR_TO_CTX) {
expected_type = PTR_TO_CTX; expected_type = PTR_TO_CTX;
if (type != expected_type)
goto err_type;
} else if (arg_type == ARG_PTR_TO_STACK || } else if (arg_type == ARG_PTR_TO_STACK ||
arg_type == ARG_PTR_TO_RAW_STACK) { arg_type == ARG_PTR_TO_RAW_STACK) {
expected_type = PTR_TO_STACK; expected_type = PTR_TO_STACK;
...@@ -967,20 +980,16 @@ static int check_func_arg(struct verifier_env *env, u32 regno, ...@@ -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 * passed in as argument, it's a CONST_IMM type. Final test
* happens during stack boundary checking. * happens during stack boundary checking.
*/ */
if (reg->type == CONST_IMM && reg->imm == 0) if (type == CONST_IMM && reg->imm == 0)
expected_type = CONST_IMM; /* 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; meta->raw_mode = arg_type == ARG_PTR_TO_RAW_STACK;
} else { } else {
verbose("unsupported arg_type %d\n", arg_type); verbose("unsupported arg_type %d\n", arg_type);
return -EFAULT; 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) { if (arg_type == ARG_CONST_MAP_PTR) {
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */ /* bpf_map_xxx(map_ptr) call: remember that map_ptr */
meta->map_ptr = reg->map_ptr; meta->map_ptr = reg->map_ptr;
...@@ -998,8 +1007,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno, ...@@ -998,8 +1007,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
verbose("invalid map_ptr to access map->key\n"); verbose("invalid map_ptr to access map->key\n");
return -EACCES; return -EACCES;
} }
err = check_stack_boundary(env, regno, meta->map_ptr->key_size, if (type == PTR_TO_PACKET)
false, NULL); 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) { } else if (arg_type == ARG_PTR_TO_MAP_VALUE) {
/* bpf_map_xxx(..., map_ptr, ..., value) call: /* bpf_map_xxx(..., map_ptr, ..., value) call:
* check [value, value + map->value_size) validity * check [value, value + map->value_size) validity
...@@ -1009,9 +1023,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno, ...@@ -1009,9 +1023,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
verbose("invalid map_ptr to access map->value\n"); verbose("invalid map_ptr to access map->value\n");
return -EACCES; return -EACCES;
} }
err = check_stack_boundary(env, regno, if (type == PTR_TO_PACKET)
meta->map_ptr->value_size, err = check_packet_access(env, regno, 0,
false, NULL); 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 || } else if (arg_type == ARG_CONST_STACK_SIZE ||
arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) { arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
bool zero_size_allowed = (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, ...@@ -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"); verbose("ARG_CONST_STACK_SIZE cannot be first argument\n");
return -EACCES; return -EACCES;
} }
err = check_stack_boundary(env, regno - 1, reg->imm, if (regs[regno - 1].type == PTR_TO_PACKET)
zero_size_allowed, meta); 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; 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) 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) ...@@ -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(); return bpf_get_probe_write_proto();
case BPF_FUNC_current_task_under_cgroup: case BPF_FUNC_current_task_under_cgroup:
return &bpf_current_task_under_cgroup_proto; return &bpf_current_task_under_cgroup_proto;
case BPF_FUNC_get_prandom_u32:
return &bpf_get_prandom_u32_proto;
default: default:
return NULL; return NULL;
} }
......
...@@ -1449,7 +1449,7 @@ static struct bpf_test tests[] = { ...@@ -1449,7 +1449,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS, .prog_type = BPF_PROG_TYPE_SCHED_CLS,
}, },
{ {
"pkt: test1", "direct packet access: test1",
.insns = { .insns = {
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
offsetof(struct __sk_buff, data)), offsetof(struct __sk_buff, data)),
...@@ -1466,7 +1466,7 @@ static struct bpf_test tests[] = { ...@@ -1466,7 +1466,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS, .prog_type = BPF_PROG_TYPE_SCHED_CLS,
}, },
{ {
"pkt: test2", "direct packet access: test2",
.insns = { .insns = {
BPF_MOV64_IMM(BPF_REG_0, 1), BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
...@@ -1499,7 +1499,7 @@ static struct bpf_test tests[] = { ...@@ -1499,7 +1499,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS, .prog_type = BPF_PROG_TYPE_SCHED_CLS,
}, },
{ {
"pkt: test3", "direct packet access: test3",
.insns = { .insns = {
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
offsetof(struct __sk_buff, data)), offsetof(struct __sk_buff, data)),
...@@ -1511,7 +1511,7 @@ static struct bpf_test tests[] = { ...@@ -1511,7 +1511,7 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER, .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
}, },
{ {
"pkt: test4", "direct packet access: test4",
.insns = { .insns = {
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
offsetof(struct __sk_buff, data)), offsetof(struct __sk_buff, data)),
...@@ -1528,6 +1528,112 @@ static struct bpf_test tests[] = { ...@@ -1528,6 +1528,112 @@ static struct bpf_test tests[] = {
.result = REJECT, .result = REJECT,
.prog_type = BPF_PROG_TYPE_SCHED_CLS, .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) static int probe_filter_length(struct bpf_insn *fp)
......
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