aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2018-01-13 16:06:16 -0500
committerRussell King <rmk+kernel@armlinux.org.uk>2018-01-17 14:38:21 -0500
commitec19e02b343db991d2d1610c409efefebf4e2ca9 (patch)
treec631847a3e173367ef9ec46d38d1ebc4a4815278
parent02088d9b392f605c892894b46aa8c83e3abd0115 (diff)
ARM: net: bpf: fix LDX instructions
When the source and destination register are identical, our JIT does not generate correct code, which leads to kernel oopses. Fix this by (a) generating more efficient code, and (b) making use of the temporary earlier if we will overwrite the address register. Fixes: 39c13c204bb1 ("arm: eBPF JIT compiler") Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--arch/arm/net/bpf_jit_32.c61
1 files changed, 33 insertions, 28 deletions
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 95bb3f896c8f..715e7250de86 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -913,33 +913,53 @@ static inline void emit_str_r(const u8 dst, const u8 src, bool dstk,
913} 913}
914 914
915/* dst = *(size*)(src + off) */ 915/* dst = *(size*)(src + off) */
916static inline void emit_ldx_r(const u8 dst, const u8 src, bool dstk, 916static inline void emit_ldx_r(const u8 dst[], const u8 src, bool dstk,
917 const s32 off, struct jit_ctx *ctx, const u8 sz){ 917 s32 off, struct jit_ctx *ctx, const u8 sz){
918 const u8 *tmp = bpf2a32[TMP_REG_1]; 918 const u8 *tmp = bpf2a32[TMP_REG_1];
919 u8 rd = dstk ? tmp[1] : dst; 919 const u8 *rd = dstk ? tmp : dst;
920 u8 rm = src; 920 u8 rm = src;
921 s32 off_max;
921 922
922 if (off) { 923 if (sz == BPF_H)
924 off_max = 0xff;
925 else
926 off_max = 0xfff;
927
928 if (off < 0 || off > off_max) {
923 emit_a32_mov_i(tmp[0], off, false, ctx); 929 emit_a32_mov_i(tmp[0], off, false, ctx);
924 emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx); 930 emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx);
925 rm = tmp[0]; 931 rm = tmp[0];
932 off = 0;
933 } else if (rd[1] == rm) {
934 emit(ARM_MOV_R(tmp[0], rm), ctx);
935 rm = tmp[0];
926 } 936 }
927 switch (sz) { 937 switch (sz) {
928 case BPF_W: 938 case BPF_B:
929 /* Load a Word */ 939 /* Load a Byte */
930 emit(ARM_LDR_I(rd, rm, 0), ctx); 940 emit(ARM_LDRB_I(rd[1], rm, off), ctx);
941 emit_a32_mov_i(dst[0], 0, dstk, ctx);
931 break; 942 break;
932 case BPF_H: 943 case BPF_H:
933 /* Load a HalfWord */ 944 /* Load a HalfWord */
934 emit(ARM_LDRH_I(rd, rm, 0), ctx); 945 emit(ARM_LDRH_I(rd[1], rm, off), ctx);
946 emit_a32_mov_i(dst[0], 0, dstk, ctx);
935 break; 947 break;
936 case BPF_B: 948 case BPF_W:
937 /* Load a Byte */ 949 /* Load a Word */
938 emit(ARM_LDRB_I(rd, rm, 0), ctx); 950 emit(ARM_LDR_I(rd[1], rm, off), ctx);
951 emit_a32_mov_i(dst[0], 0, dstk, ctx);
952 break;
953 case BPF_DW:
954 /* Load a Double Word */
955 emit(ARM_LDR_I(rd[1], rm, off), ctx);
956 emit(ARM_LDR_I(rd[0], rm, off + 4), ctx);
939 break; 957 break;
940 } 958 }
941 if (dstk) 959 if (dstk)
942 emit(ARM_STR_I(rd, ARM_SP, STACK_VAR(dst)), ctx); 960 emit(ARM_STR_I(rd[1], ARM_SP, STACK_VAR(dst[1])), ctx);
961 if (dstk && sz == BPF_DW)
962 emit(ARM_STR_I(rd[0], ARM_SP, STACK_VAR(dst[0])), ctx);
943} 963}
944 964
945/* Arithmatic Operation */ 965/* Arithmatic Operation */
@@ -1440,22 +1460,7 @@ exit:
1440 rn = sstk ? tmp2[1] : src_lo; 1460 rn = sstk ? tmp2[1] : src_lo;
1441 if (sstk) 1461 if (sstk)
1442 emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src_lo)), ctx); 1462 emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src_lo)), ctx);
1443 switch (BPF_SIZE(code)) { 1463 emit_ldx_r(dst, rn, dstk, off, ctx, BPF_SIZE(code));
1444 case BPF_W:
1445 /* Load a Word */
1446 case BPF_H:
1447 /* Load a Half-Word */
1448 case BPF_B:
1449 /* Load a Byte */
1450 emit_ldx_r(dst_lo, rn, dstk, off, ctx, BPF_SIZE(code));
1451 emit_a32_mov_i(dst_hi, 0, dstk, ctx);
1452 break;
1453 case BPF_DW:
1454 /* Load a double word */
1455 emit_ldx_r(dst_lo, rn, dstk, off, ctx, BPF_W);
1456 emit_ldx_r(dst_hi, rn, dstk, off+4, ctx, BPF_W);
1457 break;
1458 }
1459 break; 1464 break;
1460 /* R0 = ntohx(*(size *)(((struct sk_buff *)R6)->data + imm)) */ 1465 /* R0 = ntohx(*(size *)(((struct sk_buff *)R6)->data + imm)) */
1461 case BPF_LD | BPF_ABS | BPF_W: 1466 case BPF_LD | BPF_ABS | BPF_W: