| From 142fdaea7f23a87eeb0430e41fe54452806773e8 Mon Sep 17 00:00:00 2001 |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| Date: Mon, 8 May 2017 00:04:09 +0200 |
| Subject: [PATCH] bpf: don't let ldimm64 leak map addresses on unprivileged |
| |
| commit 0d0e57697f162da4aa218b5feafe614fb666db07 upstream. |
| |
| The patch fixes two things at once: |
| |
| 1) It checks the env->allow_ptr_leaks and only prints the map address to |
| the log if we have the privileges to do so, otherwise it just dumps 0 |
| as we would when kptr_restrict is enabled on %pK. Given the latter is |
| off by default and not every distro sets it, I don't want to rely on |
| this, hence the 0 by default for unprivileged. |
| |
| 2) Printing of ldimm64 in the verifier log is currently broken in that |
| we don't print the full immediate, but only the 32 bit part of the |
| first insn part for ldimm64. Thus, fix this up as well; it's okay to |
| access, since we verified all ldimm64 earlier already (including just |
| constants) through replace_map_fd_with_map_ptr(). |
| |
| Fixes: 1be7f75d1668 ("bpf: enable non-root eBPF programs") |
| Fixes: cbd357008604 ("bpf: verifier (add ability to receive verification log)") |
| Reported-by: Jann Horn <jannh@google.com> |
| Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> |
| Acked-by: Alexei Starovoitov <ast@kernel.org> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c |
| index daea765d72e6..48fe5d4da143 100644 |
| --- a/kernel/bpf/verifier.c |
| +++ b/kernel/bpf/verifier.c |
| @@ -328,7 +328,8 @@ static const char *const bpf_jmp_string[16] = { |
| [BPF_EXIT >> 4] = "exit", |
| }; |
| |
| -static void print_bpf_insn(struct bpf_insn *insn) |
| +static void print_bpf_insn(struct verifier_env *env, |
| + const struct bpf_insn *insn) |
| { |
| u8 class = BPF_CLASS(insn->code); |
| |
| @@ -392,9 +393,19 @@ static void print_bpf_insn(struct bpf_insn *insn) |
| insn->code, |
| bpf_ldst_string[BPF_SIZE(insn->code) >> 3], |
| insn->src_reg, insn->imm); |
| - } else if (BPF_MODE(insn->code) == BPF_IMM) { |
| - verbose("(%02x) r%d = 0x%x\n", |
| - insn->code, insn->dst_reg, insn->imm); |
| + } else if (BPF_MODE(insn->code) == BPF_IMM && |
| + BPF_SIZE(insn->code) == BPF_DW) { |
| + /* At this point, we already made sure that the second |
| + * part of the ldimm64 insn is accessible. |
| + */ |
| + u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm; |
| + bool map_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD; |
| + |
| + if (map_ptr && !env->allow_ptr_leaks) |
| + imm = 0; |
| + |
| + verbose("(%02x) r%d = 0x%llx\n", insn->code, |
| + insn->dst_reg, (unsigned long long)imm); |
| } else { |
| verbose("BUG_ld_%02x\n", insn->code); |
| return; |
| @@ -2273,7 +2284,7 @@ static int do_check(struct verifier_env *env) |
| |
| if (log_level) { |
| verbose("%d: ", insn_idx); |
| - print_bpf_insn(insn); |
| + print_bpf_insn(env, insn); |
| } |
| |
| if (class == BPF_ALU || class == BPF_ALU64) { |
| -- |
| 2.12.0 |
| |