[llvm-branch-commits] ELF: Add a -z glibc-228-compat flag for working around an old glibc bug. (PR #133532)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Mar 28 15:34:09 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf
Author: Peter Collingbourne (pcc)
<details>
<summary>Changes</summary>
The -z glibc-228-compat flag is intended to be used for
binaries utilizing IFUNCs which need to be compatible with
glibc versions containing a bug that was fixed in commit
b5c45e83753b27dc538dff2d55d4410c385cf3a4 which was released in
version 2.29. The bug causes glibc to mprotect the .text section as
RW while calling ifunc resolvers in binaries linked with -z notext,
leading to a SIGSEGV at startup time. By setting the W flag on the
executable section we work around the bug by avoiding the code path
that does the mprotect. It is recommended that binaries linked with
this flag contain startup code (e.g. in .init_array) that remaps the
executable section as non-writable.
TODO:
- Add tests.
- Possibly decide on another mechanism for enabling this besides the -z flag
(e.g. examine symbol version data on libc.so.6).
---
Full diff: https://github.com/llvm/llvm-project/pull/133532.diff
3 Files Affected:
- (modified) lld/ELF/Config.h (+1)
- (modified) lld/ELF/Driver.cpp (+1)
- (modified) lld/ELF/Writer.cpp (+13)
``````````diff
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 03b3cd4771f49..e611e5059dc19 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -366,6 +366,7 @@ struct Config {
bool zCopyreloc;
bool zForceBti;
bool zForceIbt;
+ bool zGlibc228Compat;
bool zGlobal;
bool zHazardplt;
bool zIfuncNoplt;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 4555a85a4d216..5a173565e478f 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1559,6 +1559,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
ctx.arg.zForceBti = hasZOption(args, "force-bti");
ctx.arg.zForceIbt = hasZOption(args, "force-ibt");
ctx.arg.zGcs = getZGcs(ctx, args);
+ ctx.arg.zGlibc228Compat = hasZOption(args, "glibc-228-compat");
ctx.arg.zGlobal = hasZOption(args, "global");
ctx.arg.zGnustack = getZGnuStack(args);
ctx.arg.zHazardplt = hasZOption(args, "hazardplt");
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 2cea6a44b391a..c266aff3a5153 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2277,6 +2277,19 @@ static uint64_t computeFlags(Ctx &ctx, uint64_t flags) {
return PF_R | PF_W | PF_X;
if (ctx.arg.executeOnly && (flags & PF_X))
return flags & ~PF_R;
+
+ // The -z glibc-228-compat flag is used for binaries utilizing IFUNCs which
+ // need to be compatible with glibc versions containing a bug that was fixed
+ // in commit b5c45e83753b27dc538dff2d55d4410c385cf3a4 which was released in
+ // version 2.29. The bug causes glibc to mprotect the .text section as RW
+ // while calling ifunc resolvers in binaries linked with -z notext, leading to
+ // a SIGSEGV at startup time. By setting the W flag on the executable section
+ // we work around the bug by avoiding the code path that does the mprotect. It
+ // is recommended that binaries linked with this flag contain startup code
+ // (e.g. in .init_array) that remaps the executable section as non-writable.
+ if (ctx.arg.zGlibc228Compat && !ctx.arg.zText && (flags & PF_X))
+ return flags | PF_W;
+
return flags;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/133532
More information about the llvm-branch-commits
mailing list