[PATCH] D51432: [AArch64] Unwinding support for return address signing

2018-09-24 Thread Luke Cheeseman via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL342895: [AArch64] Unwinding support for return address 
signing (authored by LukeCheeseman, committed by ).
Herald added subscribers: llvm-commits, christof.

Changed prior to commit:
  https://reviews.llvm.org/D51432?vs=165775=166700#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D51432

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

Index: libunwind/trunk/src/DwarfInstructions.hpp
===
--- libunwind/trunk/src/DwarfInstructions.hpp
+++ libunwind/trunk/src/DwarfInstructions.hpp
@@ -198,6 +198,24 @@
   // 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) {
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+return UNW_ECROSSRASIGNING;
+#else
+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
+  }
+#endif
+
   // Return address is address after call site instruction, so setting IP to
   // that does simualates a return.
   newRegisters.setIP(returnAddress);
Index: libunwind/trunk/src/dwarf2.h
===
--- libunwind/trunk/src/dwarf2.h
+++ libunwind/trunk/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: libunwind/trunk/src/DwarfParser.hpp
===
--- libunwind/trunk/src/DwarfParser.hpp
+++ libunwind/trunk/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: libunwind/trunk/src/Registers.hpp
===
--- libunwind/trunk/src/Registers.hpp
+++ libunwind/trunk/src/Registers.hpp
@@ -1786,7 +1786,7 @@
 uint64_t __lr;// Link register x30
 uint64_t __sp;// Stack pointer x31
 uint64_t __pc;// Program counter
-uint64_t padding; // 16-byte align
+uint64_t __ra_sign_state; // RA sign state register
   };
 
   GPRs_registers;
@@ -1822,6 +1822,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;
@@ -1832,16 +1834,21 @@
 return _registers.__pc;
   if (regNum == UNW_REG_SP)
 return _registers.__sp;
+  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+return _registers.__ra_sign_state;
   if ((regNum >= 0) && (regNum < 32))
 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 == UNW_ARM64_RA_SIGN_STATE)
+_registers.__ra_sign_state = value;
   else if ((regNum >= 0) && (regNum < 32))
 _registers.__x[regNum] = value;
   else
Index: libunwind/trunk/include/libunwind.h
===
--- libunwind/trunk/include/libunwind.h
+++ libunwind/trunk/include/libunwind.h
@@ -57,6 +57,9 @@
   UNW_EINVAL= -6547, /* unsupported operation or bad value */
   UNW_EBADVERSION   = -6548, /* unwind info has unsupported version */
   UNW_ENOINFO   = -6549  /* no unwind info found */
+#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */
+#endif
 };
 
 struct unw_context_t {
@@ -547,6 +550,8 @@
   

[PATCH] D51432: [AArch64] Unwinding support for return address signing

2018-09-20 Thread Oliver Stannard via Phabricator via cfe-commits
olista01 accepted this revision.
olista01 added a comment.
This revision is now accepted and ready to land.

LGTM, thanks!


https://reviews.llvm.org/D51432



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51432: [AArch64] Unwinding support for return address signing

2018-09-17 Thread Luke Cheeseman via Phabricator via cfe-commits
LukeCheeseman updated this revision to Diff 165775.
LukeCheeseman added a comment.

return an error code when trying to sign return addresses and cross unwinding


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
@@ -1783,7 +1783,7 @@
 uint64_t __lr;// Link register x30
 uint64_t __sp;// Stack pointer x31
 uint64_t __pc;// Program counter
-uint64_t padding; // 16-byte align
+uint64_t __ra_sign_state; // RA sign state register
   };
 
   GPRs_registers;
@@ -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,16 +1831,21 @@
 return _registers.__pc;
   if (regNum == UNW_REG_SP)
 return _registers.__sp;
+  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+return _registers.__ra_sign_state;
   if ((regNum >= 0) && (regNum < 32))
 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 == UNW_ARM64_RA_SIGN_STATE)
+_registers.__ra_sign_state = value;
   else if ((regNum >= 0) && (regNum < 32))
 _registers.__x[regNum] = value;
   else
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,24 @@
   // 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) {
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+return UNW_ECROSSRASIGNING;
+#else
+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
+  }
+#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
@@ -57,6 +57,9 @@
   UNW_EINVAL= -6547, /* unsupported operation or bad value */
   UNW_EBADVERSION   = -6548, /* unwind info has unsupported version */
   UNW_ENOINFO   = -6549  /* no unwind info found */
+#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */
+#endif
 };
 
 struct unw_context_t {
@@ -547,6 +550,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


[PATCH] D51432: [AArch64] Unwinding support for return address signing

2018-09-17 Thread Luke Cheeseman via Phabricator via cfe-commits
LukeCheeseman added inline comments.



Comment at: src/Registers.hpp:1835
+  if (((regNum >= 0) && (regNum < 32)) || regNum == UNW_ARM64_RA_SIGN_STATE)
 return _registers.__x[regNum];
+

olista01 wrote:
> When regNum == UNW_ARM64_RA_SIGN_STATE, the index into __x is out of range. 
> We'll need to add new storage to hold this value, I'd suggest replacing the 
> current padding value in the GPRs struct, as that will avoid changing the 
> layout expected by the context save/restore functions.
Good catch. Thanks, I didn't check the struct definition.


Repository:
  rUNW libunwind

https://reviews.llvm.org/D51432



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51432: [AArch64] Unwinding support for return address signing

2018-09-13 Thread Oliver Stannard via Phabricator via cfe-commits
olista01 added inline comments.



Comment at: src/DwarfInstructions.hpp:210
+register unsigned long long x16 __asm("x16") = cfa;
+asm("autia1716": "+r"(x17): "r"(x16));
+returnAddress = x17;

I don't think this will work for cross-unwinding builds: for them, 
_LIBUNWIND_TARGET_AARCH64 is defined even when the compilation target is not 
AArch64, so this instruction won't exist.

Fully supporting cross-unwinding looks non-trivial: we'd need to either provide 
some way to ask the client to authenticate a pointer on the target, or strip 
the high bits of the pointer (which requires knowing the virtual address size 
of the target). For now, I think it's OK to not support cross-unwinding.



Comment at: src/Registers.hpp:1835
+  if (((regNum >= 0) && (regNum < 32)) || regNum == UNW_ARM64_RA_SIGN_STATE)
 return _registers.__x[regNum];
+

When regNum == UNW_ARM64_RA_SIGN_STATE, the index into __x is out of range. 
We'll need to add new storage to hold this value, I'd suggest replacing the 
current padding value in the GPRs struct, as that will avoid changing the 
layout expected by the context save/restore functions.



Comment at: src/Registers.hpp:1845
 _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;

Ditto.


Repository:
  rUNW libunwind

https://reviews.llvm.org/D51432



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51432: [AArch64] Unwinding support for return address signing

2018-08-29 Thread Luke Cheeseman via Phabricator via cfe-commits
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