diff options
author | Zi Shen Lim <zlim.lnx@gmail.com> | 2015-11-04 23:43:59 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2015-11-06 11:58:48 -0500 |
commit | 14e589ff4aa3f28a5424e92b6495ecb8950080f7 (patch) | |
tree | 7ca405fec1a9c34a6d1e2fd00ceb50cdbc9995b5 /arch | |
parent | 251599e1d6906621f49218d7b474ddd159e58f3b (diff) |
arm64: bpf: fix mod-by-zero case
Turns out in the case of modulo by zero in a BPF program:
A = A % X; (X == 0)
the expected behavior is to terminate with return value 0.
The bug in JIT is exposed by a new test case [1].
[1] https://lkml.org/lkml/2015/11/4/499
Signed-off-by: Zi Shen Lim <zlim.lnx@gmail.com>
Reported-by: Yang Shi <yang.shi@linaro.org>
Reported-by: Xi Wang <xi.wang@gmail.com>
CC: Alexei Starovoitov <ast@plumgrid.com>
Fixes: e54bcde3d69d ("arm64: eBPF JIT compiler")
Cc: <stable@vger.kernel.org> # 3.18+
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm64/net/bpf_jit_comp.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 9ae6f2373a6d..6217f80702d2 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c | |||
@@ -269,6 +269,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) | |||
269 | break; | 269 | break; |
270 | case BPF_ALU | BPF_DIV | BPF_X: | 270 | case BPF_ALU | BPF_DIV | BPF_X: |
271 | case BPF_ALU64 | BPF_DIV | BPF_X: | 271 | case BPF_ALU64 | BPF_DIV | BPF_X: |
272 | case BPF_ALU | BPF_MOD | BPF_X: | ||
273 | case BPF_ALU64 | BPF_MOD | BPF_X: | ||
272 | { | 274 | { |
273 | const u8 r0 = bpf2a64[BPF_REG_0]; | 275 | const u8 r0 = bpf2a64[BPF_REG_0]; |
274 | 276 | ||
@@ -281,16 +283,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) | |||
281 | check_imm26(jmp_offset); | 283 | check_imm26(jmp_offset); |
282 | emit(A64_B(jmp_offset), ctx); | 284 | emit(A64_B(jmp_offset), ctx); |
283 | /* else */ | 285 | /* else */ |
284 | emit(A64_UDIV(is64, dst, dst, src), ctx); | 286 | switch (BPF_OP(code)) { |
287 | case BPF_DIV: | ||
288 | emit(A64_UDIV(is64, dst, dst, src), ctx); | ||
289 | break; | ||
290 | case BPF_MOD: | ||
291 | ctx->tmp_used = 1; | ||
292 | emit(A64_UDIV(is64, tmp, dst, src), ctx); | ||
293 | emit(A64_MUL(is64, tmp, tmp, src), ctx); | ||
294 | emit(A64_SUB(is64, dst, dst, tmp), ctx); | ||
295 | break; | ||
296 | } | ||
285 | break; | 297 | break; |
286 | } | 298 | } |
287 | case BPF_ALU | BPF_MOD | BPF_X: | ||
288 | case BPF_ALU64 | BPF_MOD | BPF_X: | ||
289 | ctx->tmp_used = 1; | ||
290 | emit(A64_UDIV(is64, tmp, dst, src), ctx); | ||
291 | emit(A64_MUL(is64, tmp, tmp, src), ctx); | ||
292 | emit(A64_SUB(is64, dst, dst, tmp), ctx); | ||
293 | break; | ||
294 | case BPF_ALU | BPF_LSH | BPF_X: | 299 | case BPF_ALU | BPF_LSH | BPF_X: |
295 | case BPF_ALU64 | BPF_LSH | BPF_X: | 300 | case BPF_ALU64 | BPF_LSH | BPF_X: |
296 | emit(A64_LSLV(is64, dst, dst, src), ctx); | 301 | emit(A64_LSLV(is64, dst, dst, src), ctx); |