Skip to content

Commit 0d8ee11

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 5917e54 commit 0d8ee11

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
@@ -399,6 +399,7 @@ struct Config {
399399
bool zDynamicUndefined;
400400
bool zForceBti;
401401
bool zForceIbt;
402+
bool zGlibc228Compat;
402403
bool zGlobal;
403404
bool zHazardplt;
404405
bool zIfuncNoplt;

lld/ELF/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
16191619
ctx.arg.zZicfilp = getZZicfilp(ctx, args);
16201620
ctx.arg.zZicfiss = getZZicfiss(ctx, args);
16211621
ctx.arg.zGcs = getZGcs(ctx, args);
1622+
ctx.arg.zGlibc228Compat = hasZOption(args, "glibc-228-compat");
16221623
ctx.arg.zGlobal = hasZOption(args, "global");
16231624
ctx.arg.zGnustack = getZGnuStack(args);
16241625
ctx.arg.zHazardplt = hasZOption(args, "hazardplt");

lld/ELF/Writer.cpp

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

0 commit comments

Comments
 (0)