| From 19fc99d0c6ba7d9b65456496b5bb2169d5f74cd0 Mon Sep 17 00:00:00 2001 |
| From: Nicolas Schichan <nschichan@freebox.fr> |
| Date: Wed, 6 May 2015 18:31:56 +0200 |
| Subject: ARM: net fix emit_udiv() for BPF_ALU | BPF_DIV | BPF_K intruction. |
| |
| From: Nicolas Schichan <nschichan@freebox.fr> |
| |
| commit 19fc99d0c6ba7d9b65456496b5bb2169d5f74cd0 upstream. |
| |
| In that case, emit_udiv() will be called with rn == ARM_R0 (r_scratch) |
| and loading rm first into ARM_R0 will result in jit_udiv() function |
| being called the same dividend and divisor. Fix that by loading rn |
| first into ARM_R1 and then rm into ARM_R0. |
| |
| Signed-off-by: Nicolas Schichan <nschichan@freebox.fr> |
| Fixes: aee636c4809f (bpf: do not use reciprocal divide) |
| Acked-by: Mircea Gherzan <mgherzan@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/arm/net/bpf_jit_32.c | 15 +++++++++++++-- |
| 1 file changed, 13 insertions(+), 2 deletions(-) |
| |
| --- a/arch/arm/net/bpf_jit_32.c |
| +++ b/arch/arm/net/bpf_jit_32.c |
| @@ -449,10 +449,21 @@ static inline void emit_udiv(u8 rd, u8 r |
| return; |
| } |
| #endif |
| - if (rm != ARM_R0) |
| - emit(ARM_MOV_R(ARM_R0, rm), ctx); |
| + |
| + /* |
| + * For BPF_ALU | BPF_DIV | BPF_K instructions, rm is ARM_R4 |
| + * (r_A) and rn is ARM_R0 (r_scratch) so load rn first into |
| + * ARM_R1 to avoid accidentally overwriting ARM_R0 with rm |
| + * before using it as a source for ARM_R1. |
| + * |
| + * For BPF_ALU | BPF_DIV | BPF_X rm is ARM_R4 (r_A) and rn is |
| + * ARM_R5 (r_X) so there is no particular register overlap |
| + * issues. |
| + */ |
| if (rn != ARM_R1) |
| emit(ARM_MOV_R(ARM_R1, rn), ctx); |
| + if (rm != ARM_R0) |
| + emit(ARM_MOV_R(ARM_R0, rm), ctx); |
| |
| ctx->seen |= SEEN_CALL; |
| emit_mov_i(ARM_R3, (u32)jit_udiv, ctx); |