Skip to content

Commit ec19e02

Browse files
author
Russell King
committed
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: 39c13c2 ("arm: eBPF JIT compiler") Signed-off-by: Russell King <[email protected]>
1 parent 02088d9 commit ec19e02

File tree

1 file changed

+33
-28
lines changed

1 file changed

+33
-28
lines changed

arch/arm/net/bpf_jit_32.c

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -913,33 +913,53 @@ static inline void emit_str_r(const u8 dst, const u8 src, bool dstk,
913913
}
914914

915915
/* dst = *(size*)(src + off) */
916-
static inline void emit_ldx_r(const u8 dst, const u8 src, bool dstk,
917-
const s32 off, struct jit_ctx *ctx, const u8 sz){
916+
static inline void emit_ldx_r(const u8 dst[], const u8 src, bool dstk,
917+
s32 off, struct jit_ctx *ctx, const u8 sz){
918918
const u8 *tmp = bpf2a32[TMP_REG_1];
919-
u8 rd = dstk ? tmp[1] : dst;
919+
const u8 *rd = dstk ? tmp : dst;
920920
u8 rm = src;
921+
s32 off_max;
921922

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) {
923929
emit_a32_mov_i(tmp[0], off, false, ctx);
924930
emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx);
925931
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];
926936
}
927937
switch (sz) {
928-
case BPF_W:
929-
/* Load a Word */
930-
emit(ARM_LDR_I(rd, rm, 0), ctx);
938+
case BPF_B:
939+
/* Load a Byte */
940+
emit(ARM_LDRB_I(rd[1], rm, off), ctx);
941+
emit_a32_mov_i(dst[0], 0, dstk, ctx);
931942
break;
932943
case BPF_H:
933944
/* 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);
935947
break;
936-
case BPF_B:
937-
/* Load a Byte */
938-
emit(ARM_LDRB_I(rd, rm, 0), ctx);
948+
case BPF_W:
949+
/* Load a Word */
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);
939957
break;
940958
}
941959
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);
943963
}
944964

945965
/* Arithmatic Operation */
@@ -1440,22 +1460,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
14401460
rn = sstk ? tmp2[1] : src_lo;
14411461
if (sstk)
14421462
emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src_lo)), ctx);
1443-
switch (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-
}
1463+
emit_ldx_r(dst, rn, dstk, off, ctx, BPF_SIZE(code));
14591464
break;
14601465
/* R0 = ntohx(*(size *)(((struct sk_buff *)R6)->data + imm)) */
14611466
case BPF_LD | BPF_ABS | BPF_W:

0 commit comments

Comments
 (0)