Skip to content

Commit 9bbf4a7

Browse files
committed
[probably not for upstream] ELF: Add a -z glibc-228-compat flag for working around an old glibc bug.
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: - Maybe drop this if it isn't needed? - Add tests. - Possibly decide on another mechanism for enabling this besides the -z flag (e.g. examine symbol version data on libc.so.6). Pull Request: llvm#133532
1 parent 36a7963 commit 9bbf4a7

File tree

3 files changed

+15
-0
lines changed

3 files changed

+15
-0
lines changed

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ struct Config {
367367
bool zCopyreloc;
368368
bool zForceBti;
369369
bool zForceIbt;
370+
bool zGlibc228Compat;
370371
bool zGlobal;
371372
bool zHazardplt;
372373
bool zIfuncNoplt;

lld/ELF/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
15591559
ctx.arg.zForceBti = hasZOption(args, "force-bti");
15601560
ctx.arg.zForceIbt = hasZOption(args, "force-ibt");
15611561
ctx.arg.zGcs = getZGcs(ctx, args);
1562+
ctx.arg.zGlibc228Compat = hasZOption(args, "glibc-228-compat");
15621563
ctx.arg.zGlobal = hasZOption(args, "global");
15631564
ctx.arg.zGnustack = getZGnuStack(args);
15641565
ctx.arg.zHazardplt = hasZOption(args, "hazardplt");

lld/ELF/Writer.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,6 +2292,19 @@ static uint64_t computeFlags(Ctx &ctx, uint64_t flags) {
22922292
return PF_R | PF_W | PF_X;
22932293
if (ctx.arg.executeOnly && (flags & PF_X))
22942294
return flags & ~PF_R;
2295+
2296+
// The -z glibc-228-compat flag is used for binaries utilizing IFUNCs which
2297+
// need to be compatible with glibc versions containing a bug that was fixed
2298+
// in commit b5c45e83753b27dc538dff2d55d4410c385cf3a4 which was released in
2299+
// version 2.29. The bug causes glibc to mprotect the .text section as RW
2300+
// while calling ifunc resolvers in binaries linked with -z notext, leading to
2301+
// a SIGSEGV at startup time. By setting the W flag on the executable section
2302+
// we work around the bug by avoiding the code path that does the mprotect. It
2303+
// is recommended that binaries linked with this flag contain startup code
2304+
// (e.g. in .init_array) that remaps the executable section as non-writable.
2305+
if (ctx.arg.zGlibc228Compat && !ctx.arg.zText && (flags & PF_X))
2306+
return flags | PF_W;
2307+
22952308
return flags;
22962309
}
22972310

0 commit comments

Comments
 (0)