The sign extending loads exist for bytes, halfwords and words. With the size of a doubleword, the opc of LDRSB, LDRSH and LDRSW encodes PRFM, so aarch64_insn_gen_load_store_imm() and aarch64_insn_gen_load_store_reg() returned a prefetch, which leaves the destination register as it was, instead of failing. The BPF JIT, their only user, does not ask for one, as BPF_MEMSX has no BPF_DW form and the verifier rejects the opcode, but return AARCH64_BREAK_FAULT for it as for the other invalid operands. Before/after for a sign extending load of 64 bits from x1 + 8 into x0: f9800420 prfm pldl1keep, [x1, #8] d4202000 brk #0x100 Signed-off-by: Daniel Borkmann --- arch/arm64/lib/insn.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c index dc483d1b8bd5..48a481aa9656 100644 --- a/arch/arm64/lib/insn.c +++ b/arch/arm64/lib/insn.c @@ -389,6 +389,12 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg, insn = aarch64_insn_get_ldr_reg_value(); break; case AARCH64_INSN_LDST_SIGNED_LOAD_REG_OFFSET: + /* With the size of 64 bits this encodes PRFM */ + if (size == AARCH64_INSN_SIZE_64) { + pr_err("%s: invalid size for a signed load %d\n", + __func__, size); + return AARCH64_BREAK_FAULT; + } insn = aarch64_insn_get_signed_ldr_reg_value(); break; case AARCH64_INSN_LDST_STORE_REG_OFFSET: @@ -437,6 +443,12 @@ u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg, insn = aarch64_insn_get_ldr_imm_value(); break; case AARCH64_INSN_LDST_SIGNED_LOAD_IMM_OFFSET: + /* With the size of 64 bits this encodes PRFM */ + if (size == AARCH64_INSN_SIZE_64) { + pr_err("%s: invalid size for a signed load %d\n", + __func__, size); + return AARCH64_BREAK_FAULT; + } insn = aarch64_insn_get_signed_load_imm_value(); break; case AARCH64_INSN_LDST_STORE_IMM_OFFSET: -- 2.43.0