| From foo@baz Fri Dec 22 16:57:35 CET 2017 |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| Date: Fri, 22 Dec 2017 16:29:05 +0100 |
| Subject: bpf: fix incorrect sign extension in check_alu_op() |
| To: gregkh@linuxfoundation.org |
| Cc: ast@kernel.org, daniel@iogearbox.net, jannh@google.com, stable@vger.kernel.org |
| Message-ID: <20171222152905.3455-5-daniel@iogearbox.net> |
| |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| |
| |
| From: Jann Horn <jannh@google.com> |
| |
| [ Upstream commit 95a762e2c8c942780948091f8f2a4f32fce1ac6f ] |
| |
| Distinguish between |
| BPF_ALU64|BPF_MOV|BPF_K (load 32-bit immediate, sign-extended to 64-bit) |
| and BPF_ALU|BPF_MOV|BPF_K (load 32-bit immediate, zero-padded to 64-bit); |
| only perform sign extension in the first case. |
| |
| Starting with v4.14, this is exploitable by unprivileged users as long as |
| the unprivileged_bpf_disabled sysctl isn't set. |
| |
| Debian assigned CVE-2017-16995 for this issue. |
| |
| v3: |
| - add CVE number (Ben Hutchings) |
| |
| Fixes: 484611357c19 ("bpf: allow access into map value arrays") |
| Signed-off-by: Jann Horn <jannh@google.com> |
| Acked-by: Edward Cree <ecree@solarflare.com> |
| Signed-off-by: Alexei Starovoitov <ast@kernel.org> |
| Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| kernel/bpf/verifier.c | 13 ++++++++++--- |
| 1 file changed, 10 insertions(+), 3 deletions(-) |
| |
| --- a/kernel/bpf/verifier.c |
| +++ b/kernel/bpf/verifier.c |
| @@ -1790,10 +1790,17 @@ static int check_alu_op(struct bpf_verif |
| /* case: R = imm |
| * remember the value we stored into this reg |
| */ |
| + u64 imm; |
| + |
| + if (BPF_CLASS(insn->code) == BPF_ALU64) |
| + imm = insn->imm; |
| + else |
| + imm = (u32)insn->imm; |
| + |
| regs[insn->dst_reg].type = CONST_IMM; |
| - regs[insn->dst_reg].imm = insn->imm; |
| - regs[insn->dst_reg].max_value = insn->imm; |
| - regs[insn->dst_reg].min_value = insn->imm; |
| + regs[insn->dst_reg].imm = imm; |
| + regs[insn->dst_reg].max_value = imm; |
| + regs[insn->dst_reg].min_value = imm; |
| } |
| |
| } else if (opcode > BPF_END) { |