LukeCheeseman created this revision.
LukeCheeseman added reviewers: pcc, kcc, eugenis, vlad.tsyrklevich.
Herald added a reviewer: javed.absar.
Herald added subscribers: cfe-commits, chrib, JDevlieghere, kristof.beyls.

- When return address signing is enabled, the LR may be signed on function entry
- When an exception is thrown the return address is inspected used to unwind 
the call stack
- Before this happens, the return address must be correctly authenticated to 
avoid causing an abort by dereferencing the signed pointer


Repository:
  rUNW libunwind

https://reviews.llvm.org/D51432

Files:
  include/libunwind.h
  src/DwarfInstructions.hpp
  src/DwarfParser.hpp
  src/Registers.hpp
  src/dwarf2.h

Index: src/dwarf2.h
===================================================================
--- src/dwarf2.h
+++ src/dwarf2.h
@@ -49,7 +49,10 @@
   // GNU extensions
   DW_CFA_GNU_window_save              = 0x2D,
   DW_CFA_GNU_args_size                = 0x2E,
-  DW_CFA_GNU_negative_offset_extended = 0x2F
+  DW_CFA_GNU_negative_offset_extended = 0x2F,
+
+  // AARCH64 extensions
+  DW_CFA_AARCH64_negate_ra_state      = 0x2D
 };
 
 
Index: src/Registers.hpp
===================================================================
--- src/Registers.hpp
+++ src/Registers.hpp
@@ -1819,6 +1819,8 @@
     return false;
   if (regNum > 95)
     return false;
+  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+    return true;
   if ((regNum > 31) && (regNum < 64))
     return false;
   return true;
@@ -1829,17 +1831,18 @@
     return _registers.__pc;
   if (regNum == UNW_REG_SP)
     return _registers.__sp;
-  if ((regNum >= 0) && (regNum < 32))
+  if (((regNum >= 0) && (regNum < 32)) || regNum == UNW_ARM64_RA_SIGN_STATE)
     return _registers.__x[regNum];
+
   _LIBUNWIND_ABORT("unsupported arm64 register");
 }
 
 inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
   if (regNum == UNW_REG_IP)
     _registers.__pc = value;
   else if (regNum == UNW_REG_SP)
     _registers.__sp = value;
-  else if ((regNum >= 0) && (regNum < 32))
+  else if ((regNum >= 0) && (regNum < 32) || regNum == UNW_ARM64_RA_SIGN_STATE)
     _registers.__x[regNum] = value;
   else
     _LIBUNWIND_ABORT("unsupported arm64 register");
Index: src/DwarfParser.hpp
===================================================================
--- src/DwarfParser.hpp
+++ src/DwarfParser.hpp
@@ -666,6 +666,14 @@
       _LIBUNWIND_TRACE_DWARF(
           "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
       break;
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+    case DW_CFA_AARCH64_negate_ra_state:
+      results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
+      _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
+      break;
+#endif
+
     default:
       operand = opcode & 0x3F;
       switch (opcode & 0xC0) {
Index: src/DwarfInstructions.hpp
===================================================================
--- src/DwarfInstructions.hpp
+++ src/DwarfInstructions.hpp
@@ -198,6 +198,20 @@
       // restoring SP means setting it to CFA.
       newRegisters.setSP(cfa);
 
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+      // If the target is aarch64 then the return address may have been signed
+      // using the v8.3 pointer authentication extensions. The original
+      // return address needs to be authenticated before the return address is
+      // restored. autia1716 is used instead of autia as autia1716 assembles
+      // to a NOP on pre-v8.3a architectures.
+      if (prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
+        register unsigned long long x17 __asm("x17") = returnAddress;
+        register unsigned long long x16 __asm("x16") = cfa;
+        asm("autia1716": "+r"(x17): "r"(x16));
+        returnAddress = x17;
+      }
+#endif
+
       // Return address is address after call site instruction, so setting IP to
       // that does simualates a return.
       newRegisters.setIP(returnAddress);
Index: include/libunwind.h
===================================================================
--- include/libunwind.h
+++ include/libunwind.h
@@ -547,6 +547,8 @@
   UNW_ARM64_X31 = 31,
   UNW_ARM64_SP  = 31,
   // reserved block
+  UNW_ARM64_RA_SIGN_STATE = 34,
+  // reserved block
   UNW_ARM64_D0  = 64,
   UNW_ARM64_D1  = 65,
   UNW_ARM64_D2  = 66,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to