diff options
| author | Alexei Starovoitov <ast@fb.com> | 2016-09-01 21:37:23 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-09-02 13:46:44 -0400 |
| commit | fdc15d388d600d5a1599e14c700af105a5b60761 (patch) | |
| tree | 6c197edb2fc2040e8069ff372baebcda5770ba25 /kernel | |
| parent | 0515e5999a466dfe6e1924f460da599bb6821487 (diff) | |
bpf: perf_event progs should only use preallocated maps
Make sure that BPF_PROG_TYPE_PERF_EVENT programs only use
preallocated hash maps, since doing memory allocation
in overflow_handler can crash depending on where nmi got triggered.
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/verifier.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c1c9e441f0f5..48c2705db22c 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -2511,6 +2511,20 @@ process_bpf_exit: | |||
| 2511 | return 0; | 2511 | return 0; |
| 2512 | } | 2512 | } |
| 2513 | 2513 | ||
| 2514 | static int check_map_prog_compatibility(struct bpf_map *map, | ||
| 2515 | struct bpf_prog *prog) | ||
| 2516 | |||
| 2517 | { | ||
| 2518 | if (prog->type == BPF_PROG_TYPE_PERF_EVENT && | ||
| 2519 | (map->map_type == BPF_MAP_TYPE_HASH || | ||
| 2520 | map->map_type == BPF_MAP_TYPE_PERCPU_HASH) && | ||
| 2521 | (map->map_flags & BPF_F_NO_PREALLOC)) { | ||
| 2522 | verbose("perf_event programs can only use preallocated hash map\n"); | ||
| 2523 | return -EINVAL; | ||
| 2524 | } | ||
| 2525 | return 0; | ||
| 2526 | } | ||
| 2527 | |||
| 2514 | /* look for pseudo eBPF instructions that access map FDs and | 2528 | /* look for pseudo eBPF instructions that access map FDs and |
| 2515 | * replace them with actual map pointers | 2529 | * replace them with actual map pointers |
| 2516 | */ | 2530 | */ |
| @@ -2518,7 +2532,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) | |||
| 2518 | { | 2532 | { |
| 2519 | struct bpf_insn *insn = env->prog->insnsi; | 2533 | struct bpf_insn *insn = env->prog->insnsi; |
| 2520 | int insn_cnt = env->prog->len; | 2534 | int insn_cnt = env->prog->len; |
| 2521 | int i, j; | 2535 | int i, j, err; |
| 2522 | 2536 | ||
| 2523 | for (i = 0; i < insn_cnt; i++, insn++) { | 2537 | for (i = 0; i < insn_cnt; i++, insn++) { |
| 2524 | if (BPF_CLASS(insn->code) == BPF_LDX && | 2538 | if (BPF_CLASS(insn->code) == BPF_LDX && |
| @@ -2562,6 +2576,12 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) | |||
| 2562 | return PTR_ERR(map); | 2576 | return PTR_ERR(map); |
| 2563 | } | 2577 | } |
| 2564 | 2578 | ||
| 2579 | err = check_map_prog_compatibility(map, env->prog); | ||
| 2580 | if (err) { | ||
| 2581 | fdput(f); | ||
| 2582 | return err; | ||
| 2583 | } | ||
| 2584 | |||
| 2565 | /* store map pointer inside BPF_LD_IMM64 instruction */ | 2585 | /* store map pointer inside BPF_LD_IMM64 instruction */ |
| 2566 | insn[0].imm = (u32) (unsigned long) map; | 2586 | insn[0].imm = (u32) (unsigned long) map; |
| 2567 | insn[1].imm = ((u64) (unsigned long) map) >> 32; | 2587 | insn[1].imm = ((u64) (unsigned long) map) >> 32; |
