| From foo@baz Mon Jan 29 13:22:08 CET 2018 |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| Date: Mon, 29 Jan 2018 02:49:00 +0100 |
| Subject: bpf: fix 32-bit divide by zero |
| To: gregkh@linuxfoundation.org |
| Cc: ast@kernel.org, stable@vger.kernel.org, Daniel Borkmann <daniel@iogearbox.net> |
| Message-ID: <0fe1fff7b023f38a11f9bebd975e29b78e5c788b.1517190207.git.daniel@iogearbox.net> |
| |
| From: Alexei Starovoitov <ast@kernel.org> |
| |
| [ upstream commit 68fda450a7df51cff9e5a4d4a4d9d0d5f2589153 ] |
| |
| due to some JITs doing if (src_reg == 0) check in 64-bit mode |
| for div/mod operations mask upper 32-bits of src register |
| before doing the check |
| |
| Fixes: 622582786c9e ("net: filter: x86: internal BPF JIT") |
| Fixes: 7a12b5031c6b ("sparc64: Add eBPF JIT.") |
| Reported-by: syzbot+48340bb518e88849e2e3@syzkaller.appspotmail.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 | 18 ++++++++++++++++++ |
| net/core/filter.c | 4 ++++ |
| 2 files changed, 22 insertions(+) |
| |
| --- a/kernel/bpf/verifier.c |
| +++ b/kernel/bpf/verifier.c |
| @@ -3391,6 +3391,24 @@ static int fixup_bpf_calls(struct bpf_ve |
| |
| |
| for (i = 0; i < insn_cnt; i++, insn++) { |
| + if (insn->code == (BPF_ALU | BPF_MOD | BPF_X) || |
| + insn->code == (BPF_ALU | BPF_DIV | BPF_X)) { |
| + /* due to JIT bugs clear upper 32-bits of src register |
| + * before div/mod operation |
| + */ |
| + insn_buf[0] = BPF_MOV32_REG(insn->src_reg, insn->src_reg); |
| + insn_buf[1] = *insn; |
| + cnt = 2; |
| + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); |
| + if (!new_prog) |
| + return -ENOMEM; |
| + |
| + delta += cnt - 1; |
| + env->prog = prog = new_prog; |
| + insn = new_prog->insnsi + i + delta; |
| + continue; |
| + } |
| + |
| if (insn->code != (BPF_JMP | BPF_CALL)) |
| continue; |
| |
| --- a/net/core/filter.c |
| +++ b/net/core/filter.c |
| @@ -441,6 +441,10 @@ do_pass: |
| convert_bpf_extensions(fp, &insn)) |
| break; |
| |
| + if (fp->code == (BPF_ALU | BPF_DIV | BPF_X) || |
| + fp->code == (BPF_ALU | BPF_MOD | BPF_X)) |
| + *insn++ = BPF_MOV32_REG(BPF_REG_X, BPF_REG_X); |
| + |
| *insn = BPF_RAW_INSN(fp->code, BPF_REG_A, BPF_REG_X, 0, fp->k); |
| break; |
| |