From 22f85c1b6f0c92ae5e944b4ab322787160e4eb42 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 2 Aug 2024 14:20:25 +0900 Subject: [PATCH] Rename `--remove-landing-pad` `-z rewrite-endbr` --- docs/mold.md | 53 ++++++++++--------- elf/arch-x86-64.cc | 4 +- elf/cmdline.cc | 16 +++--- elf/main.cc | 4 +- elf/mold.h | 4 +- ...ding-pads.sh => x86_64_z-rewrite-endbr.sh} | 2 +- ...ng-pads2.sh => x86_64_z-rewrite-endbr2.sh} | 2 +- ...ng-pads3.sh => x86_64_z-rewrite-endbr3.sh} | 2 +- 8 files changed, 44 insertions(+), 43 deletions(-) rename test/elf/{x86_64_remove-landing-pads.sh => x86_64_z-rewrite-endbr.sh} (91%) rename test/elf/{x86_64_remove-landing-pads2.sh => x86_64_z-rewrite-endbr2.sh} (91%) rename test/elf/{x86_64_remove-landing-pads3.sh => x86_64_z-rewrite-endbr3.sh} (89%) diff --git a/docs/mold.md b/docs/mold.md index a1a2dd7455..d1b5e991e7 100644 --- a/docs/mold.md +++ b/docs/mold.md @@ -180,32 +180,6 @@ but as `-o magic`. This option changes the behavior so that `mold` merges input sections by name by the default section merging rules. -* `--remove-landing-pads`, `--no-remove-landing-pads`: - As a security measure, a few CPU instruction sets have recently gained - support of landing pad instructions. If the feature is enabled, an - _indirect_ branch must "land" on a landing pad instruction, or a CPU-level - fault is raised. In other words, it restricts the locations to which - indirect branch instructions can jump to. The feature makes ROP or JOP - attacks harder to conduct. - - To use the feature, a function whose pointer is taken needs to begin with a - landing pad because a function call via a function pointer is compiled to an - indirect branch. On the other hand, if a function is called only directly - (i.e. referred to only by _direct_ branch instructions), it doesn't have to - begin with it. - - By default, the compiler always emits a landing pad at the beginning of each - global function because it doesn't know whether or not the function's - pointer is taken in another translation unit. As a result, the resulting - binary has more attack surface than necessary. - - If `--remove-landing-pads` is given, mold conducts a whole program analysis - to identify functions whose addresses are actually taken and rewrites - landing pads with no-ops for non-address-taken functions, reducing the - attack surface. - - This feature is currently available only on x86-64. - * `--repro`: Archive input files, as well as a text file containing command line options, in a tar file so that you can run `mold` with the exact same inputs again. @@ -294,6 +268,33 @@ but as `-o magic`. * `--quick-exit`, `--no-quick-exit`: Use or do not use `quick_exit` to exit. +* `-z rewrite-endbr`, `-z norewrite-endbr`: + As a security measure, some CPU instruction sets have recently gained a + feature to protect control flow integrity by disallowing indirect branches + by default. If the feature is enabled, the instruction that is executed + immediately after an indirect branch must be an branch target marker + instruction, or a CPU-level fault will raise. The marker instruction is also + known as "landing pad" instruction, to which indirect branches can land. + This feature makes ROP attacks harder to conduct. + + To use the feature, a function whose pointer is taken needs to begin with a + landing pad because a function call via a function pointer is compiled to an + indirect branch. On the other hand, if a function is called only directly + (i.e. referred to only by _direct_ branch instructions), it doesn't have to + begin with it. + + By default, the compiler always emits a landing pad at the beginning of each + global function because it doesn't know whether or not the function's + pointer is taken in another translation unit. As a result, the resulting + binary has more attack surface than necessary. + + If `--rewrite-endbr` is given, mold conducts a whole program analysis + to identify functions whose addresses are actually taken and rewrites + landing pads with no-ops for non-address-taken functions, reducing the + attack surface. + + This feature is currently available only on x86-64. + ## GNU-COMPATIBLE OPTIONS * `--help`: diff --git a/elf/arch-x86-64.cc b/elf/arch-x86-64.cc index f6c3a9fef7..8177039d74 100644 --- a/elf/arch-x86-64.cc +++ b/elf/arch-x86-64.cc @@ -835,8 +835,8 @@ void InputSection::scan_relocations(Context &ctx) { // This function rewrites a landing pad with a nop if the function's address // was not actually taken. We can do what the compiler cannot because we // know about all translation units. -void remove_landing_pads(Context &ctx) { - Timer t(ctx, "remove_landing_pads"); +void rewrite_endbr(Context &ctx) { + Timer t(ctx, "rewrite_endbr"); constexpr u8 endbr64[] = {0xf3, 0x0f, 0x1e, 0xfa}; constexpr u8 nop[] = {0x0f, 0x1f, 0x40, 0x00}; diff --git a/elf/cmdline.cc b/elf/cmdline.cc index a0d57ae715..b0dabffc4d 100644 --- a/elf/cmdline.cc +++ b/elf/cmdline.cc @@ -139,8 +139,6 @@ inline const char helpmsg[] = R"( --no-quick-exit --relax Optimize instructions (default) --no-relax - --remove-landing-pads Rewrite landing pad instructions with NOPs - --no-remove-landing-pads --repro Embed input files in .repro section --require-defined SYMBOL Require SYMBOL be defined in the final output --retain-symbols-file FILE Keep only symbols listed in FILE @@ -219,6 +217,8 @@ inline const char helpmsg[] = R"( -z stack-size=VALUE Set the size of the stack segment -z relro Make some sections read-only after relocation (default) -z norelro + -z rewrite-endbr Rewrite indirect branch target instructions with NOPs + -z norewrite-endbr -z rodynamic Make the .dynamic section read-only -z text Report error if DT_TEXTREL is set -z notext @@ -978,12 +978,6 @@ std::vector parse_nonpositional_args(Context &ctx) { ctx.arg.section_start[".text"] = parse_hex(ctx, "Ttext", arg); } else if (read_flag("repro")) { ctx.arg.repro = true; - } else if (read_flag("remove-landing-pads")) { - if constexpr (!is_x86_64) - Fatal(ctx) << "--remove-landing-pads is supported only on x86-64"; - ctx.arg.remove_landing_pads = true; - } else if (read_flag("no-remove-landing-pads")) { - ctx.arg.remove_landing_pads = false; } else if (read_z_flag("now")) { ctx.arg.z_now = true; } else if (read_z_flag("lazy")) { @@ -1077,6 +1071,12 @@ std::vector parse_nonpositional_args(Context &ctx) { ctx.arg.z_x86_64_isa_level |= GNU_PROPERTY_X86_ISA_1_V3; } else if (read_z_flag("x86-64-v4")) { ctx.arg.z_x86_64_isa_level |= GNU_PROPERTY_X86_ISA_1_V4; + } else if (read_z_flag("rewrite-endbr")) { + if constexpr (!is_x86_64) + Fatal(ctx) << "-z rewrite-endbr is supported only on x86-64"; + ctx.arg.z_rewrite_endbr = true; + } else if (read_z_flag("norewrite-endbr")) { + ctx.arg.z_rewrite_endbr = false; } else if (read_flag("nmagic")) { ctx.arg.nmagic = true; } else if (read_flag("no-nmagic")) { diff --git a/elf/main.cc b/elf/main.cc index 004b9c48ea..800be687b1 100644 --- a/elf/main.cc +++ b/elf/main.cc @@ -649,8 +649,8 @@ int elf_main(int argc, char **argv) { copy_chunks(ctx); if constexpr (is_x86_64) - if (ctx.arg.remove_landing_pads) - remove_landing_pads(ctx); + if (ctx.arg.z_rewrite_endbr) + rewrite_endbr(ctx); // Dynamic linker works better with sorted .rela.dyn section, // so we sort them. diff --git a/elf/mold.h b/elf/mold.h index 3c5b5fba7e..bcf9a4c537 100644 --- a/elf/mold.h +++ b/elf/mold.h @@ -1522,7 +1522,7 @@ template void show_stats(Context &); // arch-x86-64.cc // -void remove_landing_pads(Context &ctx); +void rewrite_endbr(Context &ctx); // // arch-arm32.cc @@ -1831,7 +1831,6 @@ struct Context { bool relax = true; bool relocatable = false; bool relocatable_merge_sections = false; - bool remove_landing_pads = false; bool repro = false; bool rosegment = true; bool shared = false; @@ -1861,6 +1860,7 @@ struct Context { bool z_now = false; bool z_origin = false; bool z_relro = true; + bool z_rewrite_endbr = false; bool z_rodynamic = false; bool z_sectionheader = true; bool z_shstk = false; diff --git a/test/elf/x86_64_remove-landing-pads.sh b/test/elf/x86_64_z-rewrite-endbr.sh similarity index 91% rename from test/elf/x86_64_remove-landing-pads.sh rename to test/elf/x86_64_z-rewrite-endbr.sh index 5af4785b3b..0a04ffdcb9 100755 --- a/test/elf/x86_64_remove-landing-pads.sh +++ b/test/elf/x86_64_z-rewrite-endbr.sh @@ -19,7 +19,7 @@ grep -A1 ':' $t/log1 | grep -q endbr64 grep -A1 ':' $t/log1 | grep -q endbr64 grep -A1 '
:' $t/log1 | grep -q endbr64 -$CC -B. -o $t/exe2 $t/a.o $t/b.o -Wl,--remove-landing-pads +$CC -B. -o $t/exe2 $t/a.o $t/b.o -Wl,-z,rewrite-endbr $OBJDUMP -dr $t/exe2 > $t/log2 grep -A1 ':' $t/log2 | grep -q nop diff --git a/test/elf/x86_64_remove-landing-pads2.sh b/test/elf/x86_64_z-rewrite-endbr2.sh similarity index 91% rename from test/elf/x86_64_remove-landing-pads2.sh rename to test/elf/x86_64_z-rewrite-endbr2.sh index d0c2e38ac3..52d1445b72 100755 --- a/test/elf/x86_64_remove-landing-pads2.sh +++ b/test/elf/x86_64_z-rewrite-endbr2.sh @@ -19,7 +19,7 @@ grep -A1 ':' $t/log1 | grep -q endbr64 grep -A1 ':' $t/log1 | grep -q endbr64 grep -A1 '
:' $t/log1 | grep -q endbr64 -$CC -B. -o $t/exe2 $t/a.o $t/b.o -Wl,--remove-landing-pads +$CC -B. -o $t/exe2 $t/a.o $t/b.o -Wl,-z,rewrite-endbr $OBJDUMP -dr $t/exe2 > $t/log2 grep -A1 ':' $t/log2 | grep -q nop diff --git a/test/elf/x86_64_remove-landing-pads3.sh b/test/elf/x86_64_z-rewrite-endbr3.sh similarity index 89% rename from test/elf/x86_64_remove-landing-pads3.sh rename to test/elf/x86_64_z-rewrite-endbr3.sh index d82604b660..f835854294 100755 --- a/test/elf/x86_64_remove-landing-pads3.sh +++ b/test/elf/x86_64_z-rewrite-endbr3.sh @@ -15,5 +15,5 @@ int main() { } EOF -$CC -B. -o $t/exe $t/a.o -Wl,--remove-landing-pads +$CC -B. -o $t/exe $t/a.o -Wl,-z,rewrite-endbr sde -cet 1 -- $t/exe | grep -q 'Hello world'