Skip to content

Commit 29c4e5e

Browse files
committed
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: - 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 b4c74c0 commit 29c4e5e

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
@@ -366,6 +366,7 @@ struct Config {
366366
bool zCopyreloc;
367367
bool zForceBti;
368368
bool zForceIbt;
369+
bool zGlibc228Compat;
369370
bool zGlobal;
370371
bool zHazardplt;
371372
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
@@ -2277,6 +2277,19 @@ static uint64_t computeFlags(Ctx &ctx, uint64_t flags) {
22772277
return PF_R | PF_W | PF_X;
22782278
if (ctx.arg.executeOnly && (flags & PF_X))
22792279
return flags & ~PF_R;
2280+
2281+
// The -z glibc-228-compat flag is used for binaries utilizing IFUNCs which
2282+
// need to be compatible with glibc versions containing a bug that was fixed
2283+
// in commit b5c45e83753b27dc538dff2d55d4410c385cf3a4 which was released in
2284+
// version 2.29. The bug causes glibc to mprotect the .text section as RW
2285+
// while calling ifunc resolvers in binaries linked with -z notext, leading to
2286+
// a SIGSEGV at startup time. By setting the W flag on the executable section
2287+
// we work around the bug by avoiding the code path that does the mprotect. It
2288+
// is recommended that binaries linked with this flag contain startup code
2289+
// (e.g. in .init_array) that remaps the executable section as non-writable.
2290+
if (ctx.arg.zGlibc228Compat && !ctx.arg.zText && (flags & PF_X))
2291+
return flags | PF_W;
2292+
22802293
return flags;
22812294
}
22822295

0 commit comments

Comments
 (0)