@@ -1829,19 +1829,18 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
18291829 struct GPRs ;
18301830
18311831private:
1832- // / The program counter is used effectively as a return address
1833- // / when the context is restored therefore protect it with PAC.
1834- // / The base address of the context is used with the A key for
1835- // / authentication and signing. Return address authentication is
1836- // / still managed according to the unwind info. In some cases
1837- // / the LR contains significant bits in the space for the PAC bits the
1838- // / value of the PC is stored in 2 halfs and each signed.
1839- inline uint64_t getDiscriminator () const {
1840- return reinterpret_cast <uint64_t >(this );
1841- }
18421832#if defined(_LIBUNWIND_AARCH64_PC_PROTECTION)
1833+ // / The program counter is effectively used as a return address when the
1834+ // / context is restored; therefore, it should be protected with PAC to prevent
1835+ // / arbitrary returns. The base address of the context is blended with a
1836+ // / discriminator using the A key for authentication and signing. Return
1837+ // / address authentication is still managed according to the unwind
1838+ // / information. In some cases, the LR contains significant bits in the space
1839+ // / reserved for PAC bits, so the value of the PC is stored in two halves.
1840+ // / The second half is signed using the first half as a discriminator to bind
1841+ // / the two halves together.
18431842#if defined(_LIBUNWIND_PTRAUTH_AVAILABLE)
1844- // / Use Pointer Authentication Intrinsics when available.
1843+ // / Use Pointer Authentication Intrinsics when available.
18451844#define __libunwind_ptrauth_auth_data (__value, __key, __discriminator ) \
18461845 ptrauth_auth_data (__value, __key, __discriminator)
18471846#define __libunwind_ptrauth_auth_and_resign (pointer, oldKey, oldDiscriminator, \
@@ -1850,6 +1849,8 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
18501849 newDiscriminator)
18511850#define __libunwind_ptrauth_sign_unauthenticated (__value, __key, __data ) \
18521851 ptrauth_sign_unauthenticated (__value, __key, __data)
1852+ #define __libunwind_ptrauth_blend_discriminator (__ptr, __data ) \
1853+ ptrauth_blend_discriminator (__ptr, __data)
18531854#else // !_LIBUNWIND_PTRAUTH_AVAILABLE
18541855 typedef enum {
18551856 ptrauth_key_asia = 0 ,
@@ -1900,14 +1901,21 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
19001901 __libunwind_ptrauth_auth_data (pointer, oldKey, oldDiscriminator),
19011902 newKey, newDiscriminator);
19021903 }
1904+ #define __libunwind_ptrauth_blend_discriminator (__ptr, __data ) \
1905+ ptrauth_blend_discriminator (__ptr, __data)
19031906#endif
1907+ inline uint64_t
1908+ __libunwind_ptrauth_blend_discriminator (uint64_t __ptr,
1909+ uint16_t __data) const {
1910+ return (__ptr & (~0 >> 16 )) | ((uint64_t )__data << 48 );
1911+ }
19041912 // Authenticate the currently stored PC and return it's raw value.
19051913 inline uint64_t authPC (const struct GPRs *gprs,
19061914 uint64_t discriminator) const {
1915+ uint64_t upper = (uint64_t )__libunwind_ptrauth_auth_data (
1916+ (void *)gprs->__pc2 , ptrauth_key_asia, gprs->__pc );
19071917 uint64_t lower = (uint64_t )__libunwind_ptrauth_auth_data (
19081918 (void *)gprs->__pc , ptrauth_key_asia, discriminator);
1909- uint64_t upper = (uint64_t )__libunwind_ptrauth_auth_data (
1910- (void *)gprs->__pc2 , ptrauth_key_asia, discriminator);
19111919 return (upper << 32 ) | lower;
19121920 }
19131921
@@ -1917,19 +1925,26 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
19171925 (void *)(value & (((uint64_t )~0 ) >> 32 )), ptrauth_key_asia,
19181926 getDiscriminator ());
19191927 _registers.__pc2 = (uint64_t )__libunwind_ptrauth_sign_unauthenticated (
1920- (void *)(value >> 32 ), ptrauth_key_asia, getDiscriminator () );
1928+ (void *)(value >> 32 ), ptrauth_key_asia, _registers. __pc );
19211929 }
19221930
19231931 // Update the signature on the current PC.
19241932 inline void resignPC (uint64_t oldDiscriminator) {
1933+ uint64_t old_signed_pc = _registers.__pc ;
19251934 _registers.__pc = (uint64_t )__libunwind_ptrauth_auth_and_resign (
19261935 (void *)_registers.__pc , ptrauth_key_asia, oldDiscriminator,
19271936 ptrauth_key_asia, getDiscriminator ());
19281937 _registers.__pc2 = (uint64_t )__libunwind_ptrauth_auth_and_resign (
1929- (void *)_registers.__pc2 , ptrauth_key_asia, oldDiscriminator ,
1930- ptrauth_key_asia, getDiscriminator () );
1938+ (void *)_registers.__pc2 , ptrauth_key_asia, old_signed_pc ,
1939+ ptrauth_key_asia, _registers. __pc );
19311940 }
19321941#else // ! defined(_LIBUNWIND_AARCH64_PC_PROTECTION))
1942+ inline uint64_t
1943+ __libunwind_ptrauth_blend_discriminator (uint64_t __ptr,
1944+ uint16_t __data) const {
1945+ (void )__data;
1946+ return __ptr;
1947+ }
19331948 // Remote unwinding is not supported by this protection.
19341949 inline uint64_t authPC (const struct GPRs *gprs,
19351950 const uint64_t discriminator) const {
@@ -1940,6 +1955,11 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
19401955 inline void resignPC (uint64_t oldDiscriminator) { (void )oldDiscriminator; }
19411956#endif
19421957
1958+ inline uint64_t getDiscriminator () const {
1959+ return __libunwind_ptrauth_blend_discriminator (
1960+ reinterpret_cast <uint64_t >(this ), 0xface );
1961+ }
1962+
19431963public:
19441964 Registers_arm64 ();
19451965 Registers_arm64 (const void *registers);
@@ -2010,7 +2030,8 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
20102030 " expected VFP registers to be at offset 272" );
20112031#endif
20122032 // getcontext signs the PC with the base address of the context.
2013- resignPC (reinterpret_cast <uint64_t >(registers));
2033+ resignPC (__libunwind_ptrauth_blend_discriminator (
2034+ reinterpret_cast <uint64_t >(registers), 0xface ));
20142035 memcpy (_vectorHalfRegisters,
20152036 static_cast <const uint8_t *>(registers) + sizeof (GPRs),
20162037 sizeof (_vectorHalfRegisters));
0 commit comments