Skip to content

[PAC][ELF][AArch64] Encode signed GOT flag in PAuth core info #96159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 6, 2024

Conversation

kovdan01
Copy link
Contributor

@kovdan01 kovdan01 commented Jun 20, 2024

Treat 8th bit of version value for llvm_linux platform as signed GOT flag.

  • clang: define PointerAuthELFGOT LangOption and set 8th bit of aarch64-elf-pauthabi-version LLVM module flag correspondingly;

  • llvm-readobj: print PointerAuthELFGOT or !PointerAuthELFGOT in version description of llvm_linux platform depending on whether the flag is set.

Treat 7th bit of version value for llvm_linux platform as signed GOT flag.

- clang: define `PointerAuthELFGOT` LangOption and set 7th bit of
  `aarch64-elf-pauthabi-version` LLVM module flag correspondingly;

- llvm-readobj: print `PointerAuthELFGOT` or `!PointerAuthELFGOT` in version
  description of llvm_linux platform depending on whether the flag is set.
@kovdan01 kovdan01 self-assigned this Jun 20, 2024
@kovdan01 kovdan01 requested review from jh7370, asl and MaskRay June 20, 2024 11:21
@kovdan01 kovdan01 marked this pull request as ready for review June 20, 2024 11:22
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:AArch64 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. llvm:binary-utilities labels Jun 20, 2024
@kovdan01 kovdan01 requested a review from delcypher June 20, 2024 11:22
@llvmbot
Copy link
Member

llvmbot commented Jun 20, 2024

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-llvm-binary-utilities

Author: Daniil Kovalev (kovdan01)

Changes

Treat 7th bit of version value for llvm_linux platform as signed GOT flag.

  • clang: define PointerAuthELFGOT LangOption and set 7th bit of aarch64-elf-pauthabi-version LLVM module flag correspondingly;

  • llvm-readobj: print PointerAuthELFGOT or !PointerAuthELFGOT in version description of llvm_linux platform depending on whether the flag is set.


Full diff: https://github.com/llvm/llvm-project/pull/96159.diff

6 Files Affected:

  • (modified) clang/include/clang/Basic/LangOptions.def (+1)
  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+4-2)
  • (modified) llvm/include/llvm/BinaryFormat/ELF.h (+2-1)
  • (modified) llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll (+1-1)
  • (modified) llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s (+9-9)
  • (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+2-1)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 6dd6b5614f44c..bc99dad5cd55e 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -168,6 +168,7 @@ LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
 LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
 LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
 LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
+LANGOPT(PointerAuthELFGOT, 1, 0, "authenticate pointers from GOT")
 
 LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
 LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index dd4a665ebc78b..feac291e01b50 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1210,8 +1210,10 @@ void CodeGenModule::Release() {
           (LangOpts.PointerAuthVTPtrTypeDiscrimination
            << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR) |
           (LangOpts.PointerAuthInitFini
-           << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI);
-      static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI ==
+           << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI) |
+          (LangOpts.PointerAuthELFGOT
+           << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT);
+      static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT ==
                         AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST,
                     "Update when new enum items are defined");
       if (PAuthABIVersion != 0) {
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index dfba180149916..2aa37bbed6656 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1774,8 +1774,9 @@ enum : unsigned {
   AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRADDRDISCR = 4,
   AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR = 5,
   AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI = 6,
+  AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT = 7,
   AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST =
-      AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI,
+      AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT,
 };
 
 // x86 processor feature bits.
diff --git a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll
index 728cffeba02a2..fb69a12b2f906 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll
@@ -27,7 +27,7 @@
 ; OBJ: Displaying notes found in: .note.gnu.property
 ; OBJ-NEXT:   Owner                 Data size	Description
 ; OBJ-NEXT:   GNU                   0x00000018	NT_GNU_PROPERTY_TYPE_0 (property note)
-; OBJ-NEXT:   AArch64 PAuth ABI core info: platform 0x10000002 (llvm_linux), version 0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini)
+; OBJ-NEXT:   AArch64 PAuth ABI core info: platform 0x10000002 (llvm_linux), version 0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini, !PointerAuthELFGOT)
 
 ; ERR: either both or no 'aarch64-elf-pauthabi-platform' and 'aarch64-elf-pauthabi-version' module flags must be present
 
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s
index 512531748cd25..65e9b818729e7 100644
--- a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s
@@ -106,12 +106,12 @@ end:
 # RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0x10000002-85.s -o gnu-0x10000002-85.o
 # RUN: llvm-readelf --notes gnu-0x10000002-85.o | \
 # RUN:   FileCheck --check-prefix=ELF -DPLATFORM="0x10000002 (llvm_linux)" \
-# RUN:   -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini)" %s
+# RUN:   -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini, !PointerAuthELFGOT)" %s
 # RUN: llvm-readobj --notes gnu-0x10000002-85.o | \
 # RUN:   FileCheck --check-prefix=OBJ -DPLATFORM="0x10000002 (llvm_linux)" \
-# RUN:   -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini)" %s
+# RUN:   -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini, !PointerAuthELFGOT)" %s
 
-#--- gnu-0x10000002-128.s
+#--- gnu-0x10000002-256.s
 .section ".note.gnu.property", "a"
   .long 4           // Name length is always 4 ("GNU")
   .long end - begin // Data length
@@ -123,15 +123,15 @@ begin:
   .long 0xc0000001  // Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH
   .long 16          // Data size
   .quad 0x10000002  // PAuth ABI platform
-  .quad 128         // PAuth ABI version
+  .quad 256         // PAuth ABI version
   .p2align 3        // Align to 8 byte for 64 bit
 end:
 
-# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0x10000002-128.s -o gnu-0x10000002-128.o
-# RUN: llvm-readelf --notes gnu-0x10000002-128.o | \
-# RUN:   FileCheck --check-prefix=ELF -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x80 (unknown)" %s
-# RUN: llvm-readobj --notes gnu-0x10000002-128.o | \
-# RUN:   FileCheck --check-prefix=OBJ -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x80 (unknown)" %s
+# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0x10000002-256.s -o gnu-0x10000002-256.o
+# RUN: llvm-readelf --notes gnu-0x10000002-256.o | \
+# RUN:   FileCheck --check-prefix=ELF -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x100 (unknown)" %s
+# RUN: llvm-readobj --notes gnu-0x10000002-256.o | \
+# RUN:   FileCheck --check-prefix=OBJ -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x100 (unknown)" %s
 
 #--- gnu-short.s
 .section ".note.gnu.property", "a"
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index c696934a959b2..ba179c51b87c3 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -5216,8 +5216,9 @@ static bool printAArch64PAuthABICoreInfo(raw_ostream &OS, uint32_t DataSize,
     Flags[AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR] =
         "VTPtrTypeDiscrimination";
     Flags[AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI] = "InitFini";
+    Flags[AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT] = "ELFGOT";
 
-    static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI ==
+    static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT ==
                       AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST,
                   "Update when new enum items are defined");
 

@kovdan01 kovdan01 requested a review from smithp35 June 20, 2024 11:24
@kovdan01 kovdan01 added this to the LLVM 19.X Release milestone Jun 24, 2024
Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not at all familiar with this PAuth stuff, but don't you need a test case for where the new value is set (currently they all seem to be unset, if I'm interpreting things correctly)?

@kovdan01
Copy link
Contributor Author

kovdan01 commented Jun 27, 2024

I'm not at all familiar with this PAuth stuff, but don't you need a test case for where the new value is set (currently they all seem to be unset, if I'm interpreting things correctly)?

@jh7370 I'm not sure if I understood your question correctly - particularly, I'm not sure what does the phrase "the new value is set" mean. Could you please add a bit more details in your question?

If you are talking about llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s and llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll tests checking version value 0x55 which does not imply signed GOT enabled, we just can't test 2^8=256 combinations of flags, so we test values which look like 0b10101... But I can add a test for version value 0xAA which would set opposite flags compared to 0x55.

@jh7370
Copy link
Collaborator

jh7370 commented Jun 27, 2024

I'm not at all familiar with this PAuth stuff, but don't you need a test case for where the new value is set (currently they all seem to be unset, if I'm interpreting things correctly)?

@jh7370 I'm not sure if I understood your question correctly - particularly, I'm not sure what does the phrase "the new value is set" mean. Could you please add a bit more details in your question?

If you are talking about llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s and llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll tests checking version value 0x55 which does not imply signed GOT enabled, we just can't test 2^8=256 combinations of flags, so we test values which look like 0b10101... But I can add a test for version value 0xAA which would set opposite flags compared to 0x55.

I was referring to this line from the description:

llvm-readobj: print PointerAuthELFGOT or !PointerAuthELFGOT in version description of llvm_linux platform depending on whether the flag is set.

In my opinion, if you don't test the first of those two cases, you might as well not have implemented behaviour for it. I'd always test "all flags set" and "no flags set" cases (or some variant that effectively tests this, e.g. 0xff and ~0xff). Of course, if it's not practical, that's fine.

To be clear, I'm not suggesting testing every possible combination of flags, just each flag individually set/not set.

@kovdan01
Copy link
Contributor Author

I was referring to this line from the description:

llvm-readobj: print PointerAuthELFGOT or !PointerAuthELFGOT in version description of llvm_linux platform depending on whether the flag is set.

In my opinion, if you don't test the first of those two cases, you might as well not have implemented behaviour for it. I'd always test "all flags set" and "no flags set" cases (or some variant that effectively tests this, e.g. 0xff and ~0xff). Of course, if it's not practical, that's fine.

To be clear, I'm not suggesting testing every possible combination of flags, just each flag individually set/not set.

@jh7370 Thanks for explanation! It's a reasonable point, I'll add corresponding test cases, thanks.

@kovdan01 kovdan01 requested a review from jh7370 June 27, 2024 10:32
Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, llvm-readobj aspects look good to me (I don't feel like I can review the clang side).

@kovdan01
Copy link
Contributor Author

kovdan01 commented Jul 1, 2024

Would be glad to see feedback on the changes from those who are interested.

@kovdan01
Copy link
Contributor Author

kovdan01 commented Jul 1, 2024

@MaskRay Would be glad to see your feedback on the changes

Copy link
Contributor

@tmatheson-arm tmatheson-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just based on what I can see from implementation of the existing bits in the version field.

@kovdan01
Copy link
Contributor Author

kovdan01 commented Jul 5, 2024

Thanks @tmatheson-arm! I'll merge this as soon as #96478 gets merged - there, we introduce AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINIADDRDISC = 7, so signed GOT should be bit 8. We can't use bit 8 for signed GOT right now since the implementation relies on contiguous set of flags - so, I'll wait for #96478 and change signed GOT bit position to 8.

Copy link

github-actions bot commented Aug 6, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@kovdan01 kovdan01 merged commit 15d4a84 into llvm:main Aug 6, 2024
7 checks passed
kovdan01 added a commit to kovdan01/llvm-project that referenced this pull request Aug 6, 2024
Depends on llvm#96159

Add `-fptrauth-elf-got` clang driver flag and set `ptrauth_elf_got`
preprocessor feature and `PointerAuthELFGOT` LangOption correspondingly.
For non-ELF triples, the driver flag is ignored and a warning is emitted.
kovdan01 added a commit to kovdan01/llvm-project that referenced this pull request Aug 6, 2024
kovdan01 added a commit that referenced this pull request Aug 7, 2024
Depends on #96158 and #96159

Support the following relocations and assembly operators:

- `R_AARCH64_AUTH_ADR_GOT_PAGE` (`:got_auth:` for `adrp`)
- `R_AARCH64_AUTH_LD64_GOT_LO12_NC` (`:got_auth_lo12:` for `ldr`)
- `R_AARCH64_AUTH_GOT_ADD_LO12_NC` (`:got_auth_lo12:` for `add`)

`LOADgotAUTH` pseudo-instruction is introduced which is later expanded
to actual instruction sequence like the following.

```
adrp x16, :got_auth:sym
add x16, x16, :got_auth_lo12:sym
ldr x0, [x16]
autia x0, x16
```

If a resign is requested, like below, `LOADgotPAC` pseudo is used, and
GOT load is lowered similarly to `LOADgotAUTH`.

```
@var = global i32 0
define ptr @resign_globalvar() {
  ret ptr ptrauth (ptr @var, i32 3, i64 43)
}
```

Both SelectionDAG and GlobalISel are suppported. For FastISel, we fall
back to SelectionDAG.

Tests starting with 'ptrauth-' have corresponding variants w/o this
prefix.

See also specification
https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#appendix-signed-got
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category llvm:binary-utilities
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants