[llvm] f224425 - [BPF] Check jump and memory offsets to avoid truncation

Eduard Zingerman via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 23 09:52:58 PDT 2023


Author: Eduard Zingerman
Date: 2023-09-23T19:39:24+03:00
New Revision: f22442553b8e0840f2fb5345529172a345cfba7d

URL: https://github.com/llvm/llvm-project/commit/f22442553b8e0840f2fb5345529172a345cfba7d
DIFF: https://github.com/llvm/llvm-project/commit/f22442553b8e0840f2fb5345529172a345cfba7d.diff

LOG: [BPF] Check jump and memory offsets to avoid truncation

The following assembly code should issue two errors specifying that
both jump and load offsets are out of range:

  if r1 > r2 goto +100500
  r1 = *(u64 *)(r1 - 100500)

This commit updates BPFAsmParser to check that:
- offset specified for jump is either identifier (label) or a 16-bit
  signed constant;
- offset specified for memory operations is a signed 16-bit constant.

(Which matches expectations in the BPFELFObjectWriter and
 BPFMCCodeEmitter).

Differential Revision: https://reviews.llvm.org/D158425

Added: 
    llvm/test/MC/BPF/bad-offsets.s
    llvm/test/MC/BPF/expr-offset.s

Modified: 
    llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
    llvm/lib/Target/BPF/BPFInstrInfo.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
index e92fc1a999104da..90697c6645be2f9 100644
--- a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
+++ b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
@@ -135,10 +135,14 @@ struct BPFOperand : public MCParsedAsmOperand {
     return static_cast<const MCConstantExpr *>(Val)->getValue();
   }
 
-  bool isSImm12() const {
-    return (isConstantImm() && isInt<12>(getConstantImm()));
+  bool isSImm16() const {
+    return (isConstantImm() && isInt<16>(getConstantImm()));
   }
 
+  bool isSymbolRef() const { return isImm() && isa<MCSymbolRefExpr>(getImm()); }
+
+  bool isBrTarget() const { return isSymbolRef() || isSImm16(); }
+
   /// getStartLoc - Gets location of the first token of this operand
   SMLoc getStartLoc() const override { return StartLoc; }
   /// getEndLoc - Gets location of the last token of this operand
@@ -332,6 +336,12 @@ bool BPFAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     }
 
     return Error(ErrorLoc, "invalid operand for instruction");
+  case Match_InvalidBrTarget:
+    return Error(Operands[ErrorInfo]->getStartLoc(),
+                 "operand is not an identifier or 16-bit signed integer");
+  case Match_InvalidSImm16:
+    return Error(Operands[ErrorInfo]->getStartLoc(),
+                 "operand is not a 16-bit signed integer");
   }
 
   llvm_unreachable("Unknown match type detected!");

diff  --git a/llvm/lib/Target/BPF/BPFInstrInfo.td b/llvm/lib/Target/BPF/BPFInstrInfo.td
index fd5a4dee295219e..305cbbd34d2707d 100644
--- a/llvm/lib/Target/BPF/BPFInstrInfo.td
+++ b/llvm/lib/Target/BPF/BPFInstrInfo.td
@@ -61,8 +61,17 @@ def BPFNoMovsx : Predicate<"!Subtarget->hasMovsx()">;
 def BPFNoBswap : Predicate<"!Subtarget->hasBswap()">;
 def BPFHasStoreImm : Predicate<"Subtarget->hasStoreImm()">;
 
+class ImmediateAsmOperand<string name> : AsmOperandClass {
+  let Name = name;
+  let RenderMethod = "addImmOperands";
+  let DiagnosticType = !strconcat("Invalid", name);
+}
+
+def SImm16AsmOperand : ImmediateAsmOperand<"SImm16">;
+
 def brtarget : Operand<OtherVT> {
   let PrintMethod = "printBrTargetOperand";
+  let ParserMatchClass = ImmediateAsmOperand<"BrTarget">;
 }
 def calltarget : Operand<i64>;
 
@@ -70,6 +79,10 @@ def u64imm   : Operand<i64> {
   let PrintMethod = "printImm64Operand";
 }
 
+def s16imm : Operand<i16> {
+  let ParserMatchClass = SImm16AsmOperand;
+}
+
 def gpr_or_imm : Operand<i64>;
 
 def i64immSExt32 : PatLeaf<(i64 imm),
@@ -92,7 +105,7 @@ def MEMri : Operand<i64> {
   let PrintMethod = "printMemOperand";
   let EncoderMethod = "getMemoryOpValue";
   let DecoderMethod = "decodeMemoryOpValue";
-  let MIOperandInfo = (ops GPR, i16imm);
+  let MIOperandInfo = (ops GPR, s16imm);
 }
 
 // Conditional code predicates - used for pattern matching for jump instructions

diff  --git a/llvm/test/MC/BPF/bad-offsets.s b/llvm/test/MC/BPF/bad-offsets.s
new file mode 100644
index 000000000000000..cb5f87faa4cf9d4
--- /dev/null
+++ b/llvm/test/MC/BPF/bad-offsets.s
@@ -0,0 +1,33 @@
+# RUN: not llvm-mc -mcpu=v4 -triple bpfel < %s 2>&1 \
+# RUN:   | grep 'error: operand is not an identifier or 16-bit signed integer' \
+# RUN:   | count 2
+# RUN: not llvm-mc -mcpu=v4 -triple bpfel < %s 2>&1 \
+# RUN:   | grep 'error: operand is not a 16-bit signed integer' \
+# RUN:   | count 25
+        if r1 > r2 goto +70000
+        if r1 > r2 goto -70000
+        *(u64 *)(r1 + 70000) = 10
+        *(u32 *)(r1 - 70000) = 10
+        *(u16 *)(r1 - 70000) = 10
+        *(u8  *)(r1 - 70000) = 10
+        *(u64 *)(r1 + 70000) = r1
+        *(u32 *)(r1 - 70000) = r1
+        *(u16 *)(r1 - 70000) = r1
+        *(u8  *)(r1 - 70000) = r1
+        r1 = *(u64 *)(r1 + 70000)
+        r1 = *(u32 *)(r1 - 70000)
+        r1 = *(u16 *)(r1 - 70000)
+        r1 = *(u8  *)(r1 - 70000)
+        r1 = *(s32 *)(r1 + 70000)
+        r1 = *(s16 *)(r1 - 70000)
+        r1 = *(s8  *)(r1 - 70000)
+        lock *(u32*)(r1 + 70000) += w2
+        lock *(u32*)(r1 - 70000) &= w2
+        lock *(u32*)(r1 - 70000) |= w2
+        lock *(u32*)(r1 - 70000) ^= w2
+        r0 = atomic_fetch_add((u64 *)(r1 + 70000), r0)
+        r0 = atomic_fetch_and((u64 *)(r1 + 70000), r0)
+        r0 = atomic_fetch_xor((u64 *)(r1 + 70000), r0)
+        r0 = atomic_fetch_or((u64 *)(r1 + 70000), r0)
+        w0 = cmpxchg32_32(r1 + 70000, w0, w1)
+        r0 = cmpxchg_64(r1 + 70000, r0, r1)

diff  --git a/llvm/test/MC/BPF/expr-offset.s b/llvm/test/MC/BPF/expr-offset.s
new file mode 100644
index 000000000000000..95575939c953b99
--- /dev/null
+++ b/llvm/test/MC/BPF/expr-offset.s
@@ -0,0 +1,12 @@
+# RUN: llvm-mc -triple bpfel -filetype=obj < %s \
+# RUN:       | llvm-objdump --no-print-imm-hex --no-show-raw-insn -d - \
+# RUN:       | FileCheck %s
+
+.equ foo, -1
+        if r1 > r2 goto foo + 2
+        exit
+        exit
+
+# CHECK: if r1 > r2 goto +1
+# CHECK: exit
+# CHECK: exit


        


More information about the llvm-commits mailing list