Skip to content

Commit 5722569

Browse files
gianlucaborellodavem330
authored andcommitted
bpf: allow helpers access to map element values
Enable helpers to directly access a map element value by passing a register type PTR_TO_MAP_VALUE (or PTR_TO_MAP_VALUE_ADJ) to helper arguments ARG_PTR_TO_STACK or ARG_PTR_TO_RAW_STACK. This enables several use cases. For example, a typical tracing program might want to capture pathnames passed to sys_open() with: struct trace_data { char pathname[PATHLEN]; }; SEC("kprobe/sys_open") void bpf_sys_open(struct pt_regs *ctx) { struct trace_data data; bpf_probe_read(data.pathname, sizeof(data.pathname), ctx->di); /* consume data.pathname, for example via * bpf_trace_printk() or bpf_perf_event_output() */ } Such a program could easily hit the stack limit in case PATHLEN needs to be large or more local variables need to exist, both of which are quite common scenarios. Allowing direct helper access to map element values, one could do: struct bpf_map_def SEC("maps") scratch_map = { .type = BPF_MAP_TYPE_PERCPU_ARRAY, .key_size = sizeof(u32), .value_size = sizeof(struct trace_data), .max_entries = 1, }; SEC("kprobe/sys_open") int bpf_sys_open(struct pt_regs *ctx) { int id = 0; struct trace_data *p = bpf_map_lookup_elem(&scratch_map, &id); if (!p) return; bpf_probe_read(p->pathname, sizeof(p->pathname), ctx->di); /* consume p->pathname, for example via * bpf_trace_printk() or bpf_perf_event_output() */ } And wouldn't risk exhausting the stack. Code changes are loosely modeled after commit 6841de8 ("bpf: allow helpers access the packet directly"). Unlike with PTR_TO_PACKET, these changes just work with ARG_PTR_TO_STACK and ARG_PTR_TO_RAW_STACK (not ARG_PTR_TO_MAP_KEY, ARG_PTR_TO_MAP_VALUE, ...): adding those would be trivial, but since there is not currently a use case for that, it's reasonable to limit the set of changes. Also, add new tests to make sure accesses to map element values from helpers never go out of boundary, even when adjusted. Signed-off-by: Gianluca Borello <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dbcfe5f commit 5722569

File tree

2 files changed

+498
-2
lines changed

2 files changed

+498
-2
lines changed

kernel/bpf/verifier.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, int off,
627627
{
628628
struct bpf_map *map = env->cur_state.regs[regno].map_ptr;
629629

630-
if (off < 0 || off + size > map->value_size) {
630+
if (off < 0 || size <= 0 || off + size > map->value_size) {
631631
verbose("invalid access to map value, value_size=%d off=%d size=%d\n",
632632
map->value_size, off, size);
633633
return -EACCES;
@@ -1025,7 +1025,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
10251025
*/
10261026
if (type == CONST_IMM && reg->imm == 0)
10271027
/* final test in check_stack_boundary() */;
1028-
else if (type != PTR_TO_PACKET && type != expected_type)
1028+
else if (type != PTR_TO_PACKET && type != PTR_TO_MAP_VALUE &&
1029+
type != PTR_TO_MAP_VALUE_ADJ && type != expected_type)
10291030
goto err_type;
10301031
meta->raw_mode = arg_type == ARG_PTR_TO_RAW_STACK;
10311032
} else {
@@ -1088,6 +1089,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
10881089
}
10891090
if (regs[regno - 1].type == PTR_TO_PACKET)
10901091
err = check_packet_access(env, regno - 1, 0, reg->imm);
1092+
else if (regs[regno - 1].type == PTR_TO_MAP_VALUE)
1093+
err = check_map_access(env, regno - 1, 0, reg->imm);
1094+
else if (regs[regno - 1].type == PTR_TO_MAP_VALUE_ADJ)
1095+
err = check_map_access_adj(env, regno - 1, 0, reg->imm);
10911096
else
10921097
err = check_stack_boundary(env, regno - 1, reg->imm,
10931098
zero_size_allowed, meta);

0 commit comments

Comments
 (0)