Skip to content

Commit

Permalink
Rename --remove-landing-pad -z rewrite-endbr
Browse files Browse the repository at this point in the history
  • Loading branch information
rui314 committed Aug 2, 2024
1 parent dd8d971 commit 22f85c1
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 43 deletions.
53 changes: 27 additions & 26 deletions docs/mold.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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`:
Expand Down
4 changes: 2 additions & 2 deletions elf/arch-x86-64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -835,8 +835,8 @@ void InputSection<E>::scan_relocations(Context<E> &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<E> &ctx) {
Timer t(ctx, "remove_landing_pads");
void rewrite_endbr(Context<E> &ctx) {
Timer t(ctx, "rewrite_endbr");

constexpr u8 endbr64[] = {0xf3, 0x0f, 0x1e, 0xfa};
constexpr u8 nop[] = {0x0f, 0x1f, 0x40, 0x00};
Expand Down
16 changes: 8 additions & 8 deletions elf/cmdline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -978,12 +978,6 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &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<E>)
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")) {
Expand Down Expand Up @@ -1077,6 +1071,12 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &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<E>)
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")) {
Expand Down
4 changes: 2 additions & 2 deletions elf/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -649,8 +649,8 @@ int elf_main(int argc, char **argv) {
copy_chunks(ctx);

if constexpr (is_x86_64<E>)
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.
Expand Down
4 changes: 2 additions & 2 deletions elf/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -1522,7 +1522,7 @@ template <typename E> void show_stats(Context<E> &);
// arch-x86-64.cc
//

void remove_landing_pads(Context<X86_64> &ctx);
void rewrite_endbr(Context<X86_64> &ctx);

//
// arch-arm32.cc
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ grep -A1 '<foo>:' $t/log1 | grep -q endbr64
grep -A1 '<bar>:' $t/log1 | grep -q endbr64
grep -A1 '<main>:' $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 '<foo>:' $t/log2 | grep -q nop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ grep -A1 '<foo>:' $t/log1 | grep -q endbr64
grep -A1 '<bar>:' $t/log1 | grep -q endbr64
grep -A1 '<main>:' $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 '<foo>:' $t/log2 | grep -q nop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'

0 comments on commit 22f85c1

Please sign in to comment.