Message ID | 20200408181229.10909-1-luke.r.nels@gmail.com (mailing list archive) |
---|---|
State | Mainlined |
Commit | bb9562cf5c67813034c96afb50bd21130a504441 |
Headers | show |
Series | [bpf] arm: bpf: Fix bugs with ALU64 {RSH, ARSH} BPF_K shift by 0 | expand |
On 4/8/20 8:12 PM, Luke Nelson wrote: > The current arm BPF JIT does not correctly compile RSH or ARSH when the > immediate shift amount is 0. This causes the "rsh64 by 0 imm" and "arsh64 > by 0 imm" BPF selftests to hang the kernel by reaching an instruction > the verifier determines to be unreachable. > > The root cause is in how immediate right shifts are encoded on arm. > For LSR and ASR (logical and arithmetic right shift), a bit-pattern > of 00000 in the immediate encodes a shift amount of 32. When the BPF > immediate is 0, the generated code shifts by 32 instead of the expected > behavior (a no-op). > > This patch fixes the bugs by adding an additional check if the BPF > immediate is 0. After the change, the above mentioned BPF selftests pass. > > Fixes: 39c13c204bb11 ("arm: eBPF JIT compiler") > Co-developed-by: Xi Wang <xi.wang@gmail.com> > Signed-off-by: Xi Wang <xi.wang@gmail.com> > Signed-off-by: Luke Nelson <luke.r.nels@gmail.com> Yikes, thanks for fixing, applied. Looks like noone was running BPF kselftests on arm32 for quite a while. :(
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index cc29869d12a3..d124f78e20ac 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -929,7 +929,11 @@ static inline void emit_a32_rsh_i64(const s8 dst[], rd = arm_bpf_get_reg64(dst, tmp, ctx); /* Do LSR operation */ - if (val < 32) { + if (val == 0) { + /* An immediate value of 0 encodes a shift amount of 32 + * for LSR. To shift by 0, don't do anything. + */ + } else if (val < 32) { emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx); emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx); emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_LSR, val), ctx); @@ -955,7 +959,11 @@ static inline void emit_a32_arsh_i64(const s8 dst[], rd = arm_bpf_get_reg64(dst, tmp, ctx); /* Do ARSH operation */ - if (val < 32) { + if (val == 0) { + /* An immediate value of 0 encodes a shift amount of 32 + * for ASR. To shift by 0, don't do anything. + */ + } else if (val < 32) { emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx); emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx); emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_ASR, val), ctx);