Commit fdc15d38 authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by David S. Miller

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: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0515e599
...@@ -2511,6 +2511,20 @@ static int do_check(struct verifier_env *env) ...@@ -2511,6 +2511,20 @@ static int do_check(struct verifier_env *env)
return 0; return 0;
} }
static int check_map_prog_compatibility(struct bpf_map *map,
struct bpf_prog *prog)
{
if (prog->type == BPF_PROG_TYPE_PERF_EVENT &&
(map->map_type == BPF_MAP_TYPE_HASH ||
map->map_type == BPF_MAP_TYPE_PERCPU_HASH) &&
(map->map_flags & BPF_F_NO_PREALLOC)) {
verbose("perf_event programs can only use preallocated hash map\n");
return -EINVAL;
}
return 0;
}
/* look for pseudo eBPF instructions that access map FDs and /* look for pseudo eBPF instructions that access map FDs and
* replace them with actual map pointers * replace them with actual map pointers
*/ */
...@@ -2518,7 +2532,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) ...@@ -2518,7 +2532,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env)
{ {
struct bpf_insn *insn = env->prog->insnsi; struct bpf_insn *insn = env->prog->insnsi;
int insn_cnt = env->prog->len; int insn_cnt = env->prog->len;
int i, j; int i, j, err;
for (i = 0; i < insn_cnt; i++, insn++) { for (i = 0; i < insn_cnt; i++, insn++) {
if (BPF_CLASS(insn->code) == BPF_LDX && if (BPF_CLASS(insn->code) == BPF_LDX &&
...@@ -2562,6 +2576,12 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) ...@@ -2562,6 +2576,12 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env)
return PTR_ERR(map); return PTR_ERR(map);
} }
err = check_map_prog_compatibility(map, env->prog);
if (err) {
fdput(f);
return err;
}
/* store map pointer inside BPF_LD_IMM64 instruction */ /* store map pointer inside BPF_LD_IMM64 instruction */
insn[0].imm = (u32) (unsigned long) map; insn[0].imm = (u32) (unsigned long) map;
insn[1].imm = ((u64) (unsigned long) map) >> 32; insn[1].imm = ((u64) (unsigned long) map) >> 32;
......
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