From 954ba6045dd5af1d56f0698dc598528eefe41270 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Fri, 15 Apr 2022 14:57:48 -0700 Subject: [PATCH] [BPF] Emit fatal error if out of range for FK_PCRel_2 branch target Currently for the branch insn like "if $dst "#OpcodeStr#" $imm goto $BrDst" The $BrDst range needs to be in the range of [INT16_MIN, INT16_MAX]. When running bpf selftest with latest llvm, I found pyperf600.o generated insn with range outside of [INT16_MIN, INT16_MAX], which caused verifier failure. See below insn #12. 0000000000000000 : ; { 0: 7b 1a 00 ff 00 00 00 00 *(u64 *)(r10 - 256) = r1 ; uint64_t pid_tgid = bpf_get_current_pid_tgid(); 1: 85 00 00 00 0e 00 00 00 call 14 2: bf 06 00 00 00 00 00 00 r6 = r0 ; pid_t pid = (pid_t)(pid_tgid >> 32); 3: bf 61 00 00 00 00 00 00 r1 = r6 4: 77 01 00 00 20 00 00 00 r1 >>= 32 5: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r1 6: bf a2 00 00 00 00 00 00 r2 = r10 7: 07 02 00 00 fc ff ff ff r2 += -4 ; PidData* pidData = bpf_map_lookup_elem(&pidmap, &pid); 8: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll 10: 85 00 00 00 01 00 00 00 call 1 11: bf 08 00 00 00 00 00 00 r8 = r0 ; if (!pidData) 12: 15 08 15 e8 00 00 00 00 if r8 == 0 goto -6123 13: b4 01 00 00 00 00 00 00 w1 = 0 We may need to add new insn to extend the range of $BrDst. This patch added a fatal error if out of range so compiler can warn the otherwise incorrect code generation. Differential Revision: https://reviews.llvm.org/D123877 --- llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp index bacd00360f82..56fdd6766132 100644 --- a/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp +++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -87,6 +87,11 @@ void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, } } else { assert(Fixup.getKind() == FK_PCRel_2); + + int64_t ByteOff = (int64_t)Value - 8; + if (ByteOff > INT16_MAX * 8 || ByteOff < INT16_MIN * 8) + report_fatal_error("Branch target out of insn range"); + Value = (uint16_t)((Value - 8) / 8); support::endian::write(&Data[Fixup.getOffset() + 2], Value, Endian);