Skip to content

Disable memtag sanitization for global fnptrs going into .ctors #70186

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 1 commit into from
Nov 1, 2023

Conversation

hctim
Copy link
Collaborator

@hctim hctim commented Oct 25, 2023

Looks like there's code out there that, instead of using
'attribute((constructor(x)))' to add constructor functions, they
just declare a global function pointer and use
'attribute((section('.ctors')))' instead.

Problem is, with memtag-globals, we pad the global function pointer to
be 16 bytes large. This of course means we have an 8-byte real function
pointer, then 8 bytes of zero padding, and this trips up the loader when
it processes this section.

Fixes #69939

Looks like there's code out there that, instead of using
'__attribute__((constructor(x)))' to add constructor functions, they
just declare a global function pointer and use
'__attribute__((section('.ctors')))' instead.

Problem is, with memtag-globals, we pad the global function pointer to
be 16 bytes large. This of course means we have an 8-byte real function
pointer, then 8 bytes of zero padding, and this trips up the loader when
it processes this section.

Fixes llvm#69939
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:AArch64 labels Oct 25, 2023
@hctim hctim requested review from eugenis and vitalybuka October 25, 2023 09:39
@hctim
Copy link
Collaborator Author

hctim commented Oct 25, 2023

@P1119r1m

@llvmbot
Copy link
Member

llvmbot commented Oct 25, 2023

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-clang

Author: Mitch Phillips (hctim)

Changes

Looks like there's code out there that, instead of using
'attribute((constructor(x)))' to add constructor functions, they
just declare a global function pointer and use
'attribute((section('.ctors')))' instead.

Problem is, with memtag-globals, we pad the global function pointer to
be 16 bytes large. This of course means we have an 8-byte real function
pointer, then 8 bytes of zero padding, and this trips up the loader when
it processes this section.

Fixes #69939


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

2 Files Affected:

  • (modified) clang/test/CodeGen/memtag-globals-asm.cpp (+20)
  • (modified) llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp (+12)
diff --git a/clang/test/CodeGen/memtag-globals-asm.cpp b/clang/test/CodeGen/memtag-globals-asm.cpp
index 3f18671562def71..4b76b394e0c1dc3 100644
--- a/clang/test/CodeGen/memtag-globals-asm.cpp
+++ b/clang/test/CodeGen/memtag-globals-asm.cpp
@@ -259,3 +259,23 @@ int f(int x) {
   // CHECK-Q-DAG: ldr   {{.*}}, [[[REG_O2]]]
       function_int;
 }
+
+typedef void (*func_t)(void);
+#define CONSTRUCTOR(section_name) \
+  __attribute__((used)) __attribute__((section(section_name)))
+
+__attribute__((constructor(0))) void func_constructor() {}
+CONSTRUCTOR(".init") func_t func_init = func_constructor;
+CONSTRUCTOR(".fini") func_t func_fini = func_constructor;
+CONSTRUCTOR(".ctors") func_t func_ctors = func_constructor;
+CONSTRUCTOR(".dtors") func_t func_dtors = func_constructor;
+CONSTRUCTOR(".init_array") func_t func_init_array = func_constructor;
+CONSTRUCTOR(".fini_array") func_t func_fini_array = func_constructor;
+
+// CHECK-NOT: .memtag func_constructor
+// CHECK-NOT: .memtag func_init
+// CHECK-NOT: .memtag func_fini
+// CHECK-NOT: .memtag func_ctors
+// CHECK-NOT: .memtag func_dtors
+// CHECK-NOT: .memtag func_init_array
+// CHECK-NOT: .memtag func_fini_array
diff --git a/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp b/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp
index 2ed668712897ce7..88e44eb0bfbb99f 100644
--- a/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp
+++ b/llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp
@@ -43,6 +43,18 @@ static bool shouldTagGlobal(GlobalVariable &G) {
     return false;
   }
 
+  // Don't instrument function pointers that are going into various init arrays
+  // via `__attribute__((section(<foo>)))`:
+  // https://github.com/llvm/llvm-project/issues/69939
+  if (G.hasSection() &&
+      (G.getSection() == ".init" || G.getSection() == ".fini" ||
+       G.getSection() == ".init_array" || G.getSection() == ".fini_array" ||
+       G.getSection() == ".ctors" || G.getSection() == ".dtors")) {
+    Meta.Memtag = false;
+    G.setSanitizerMetadata(Meta);
+    return false;
+  }
+
   return true;
 }
 

@P1119r1m
Copy link

P1119r1m commented Oct 25, 2023

Dear Mitch,

thank you for your PR!
Let me check it on our end before submitting.

UPD.
This patch resolves the problem mentioned in #69939 .

Copy link

@P1119r1m P1119r1m left a comment

Choose a reason for hiding this comment

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

LGTM

@hctim
Copy link
Collaborator Author

hctim commented Oct 27, 2023

(friendly ping @eugenis / @vitalybuka)

@hctim hctim merged commit ba31ed4 into llvm:main Nov 1, 2023
@hctim hctim deleted the memtag/ctor branch November 1, 2023 10:43
hctim added a commit that referenced this pull request Jan 22, 2024
Previous work in this area (#70186) disabled MTE in constructor
sections. Looks like I missed one, ".preinit_array".

Also, in the meantime, I found an exciting feature in the linker where
globals placed into an explicit section, where the section name is a
valid C identifer, gets an implicit '__start_<sectionname>' and
'__stop_<sectionname>' symbol as well. This is convenient for iterating
over some globals, but of course iteration over differently-tagged
globals in MTE explodes.

Thus, disable MTE globals for anything that has a section.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Constructor size is twice as large on Clang17.0.2 with MTE enabled
4 participants