Add an experimental `-z rewrite-endbr` option
endbr64 is a relatively new x86 instruction to mark a location to which an
indirect jump instruction can transfer control. If the control-flow
integrity is turned on (i.e., endbr64 is effective), an indirect jump can
only target an endbr64 or raise a runtime exception. This mechanism makes
some types of control hijacking attacks, such as ROP or JOP, very hard
because an attacker can no longer jump to an arbitrary location.
If `-fcf-protection` is given, GCC emits an endbr64 at the beginning of
each global function conservatively because the address of that function
might be used by other translation units.
In reality, most function addresses aren't taken, so the conservative
assumption ends up emitting lots of unnecessary endbr64 instructions.
This not only bloats the code but also weakens security because an
attacker would have more locations to attack.
The new linker option, `-z rewrite-endbr`, is designed to mitigate this
situation. The linker is in a position to conduct whole-program analysis
on the input files and determine functions whose addresses have never been
taken. If `-z rewrite-endbr` is given, mold performs that analysis and
rewrites the leading endbr64 with a nop if the function's address wasn't
taken.
For evaluation, I built the mold executable itself both with and without
this option. Before using the `-z rewrite-endbr` option, the mold
executable contained 25,994 endbr64 instructions. With the option, the
number becomes 18,035, a 30% reduction.
The new option is exprerimental; we may remove it in a future versions of
the mold linker.
2023-10-02 11:30:21 +03:00
|
|
|
#!/bin/bash
|
|
|
|
. $(dirname $0)/common.inc
|
|
|
|
|
2023-10-02 14:03:24 +03:00
|
|
|
test_cflags -fcf-protection || skip
|
Add an experimental `-z rewrite-endbr` option
endbr64 is a relatively new x86 instruction to mark a location to which an
indirect jump instruction can transfer control. If the control-flow
integrity is turned on (i.e., endbr64 is effective), an indirect jump can
only target an endbr64 or raise a runtime exception. This mechanism makes
some types of control hijacking attacks, such as ROP or JOP, very hard
because an attacker can no longer jump to an arbitrary location.
If `-fcf-protection` is given, GCC emits an endbr64 at the beginning of
each global function conservatively because the address of that function
might be used by other translation units.
In reality, most function addresses aren't taken, so the conservative
assumption ends up emitting lots of unnecessary endbr64 instructions.
This not only bloats the code but also weakens security because an
attacker would have more locations to attack.
The new linker option, `-z rewrite-endbr`, is designed to mitigate this
situation. The linker is in a position to conduct whole-program analysis
on the input files and determine functions whose addresses have never been
taken. If `-z rewrite-endbr` is given, mold performs that analysis and
rewrites the leading endbr64 with a nop if the function's address wasn't
taken.
For evaluation, I built the mold executable itself both with and without
this option. Before using the `-z rewrite-endbr` option, the mold
executable contained 25,994 endbr64 instructions. With the option, the
number becomes 18,035, a 30% reduction.
The new option is exprerimental; we may remove it in a future versions of
the mold linker.
2023-10-02 11:30:21 +03:00
|
|
|
|
2023-10-19 05:44:05 +03:00
|
|
|
cat <<EOF | $CC -o $t/a.o -c -xc - -ffunction-sections -O -fcf-protection
|
Add an experimental `-z rewrite-endbr` option
endbr64 is a relatively new x86 instruction to mark a location to which an
indirect jump instruction can transfer control. If the control-flow
integrity is turned on (i.e., endbr64 is effective), an indirect jump can
only target an endbr64 or raise a runtime exception. This mechanism makes
some types of control hijacking attacks, such as ROP or JOP, very hard
because an attacker can no longer jump to an arbitrary location.
If `-fcf-protection` is given, GCC emits an endbr64 at the beginning of
each global function conservatively because the address of that function
might be used by other translation units.
In reality, most function addresses aren't taken, so the conservative
assumption ends up emitting lots of unnecessary endbr64 instructions.
This not only bloats the code but also weakens security because an
attacker would have more locations to attack.
The new linker option, `-z rewrite-endbr`, is designed to mitigate this
situation. The linker is in a position to conduct whole-program analysis
on the input files and determine functions whose addresses have never been
taken. If `-z rewrite-endbr` is given, mold performs that analysis and
rewrites the leading endbr64 with a nop if the function's address wasn't
taken.
For evaluation, I built the mold executable itself both with and without
this option. Before using the `-z rewrite-endbr` option, the mold
executable contained 25,994 endbr64 instructions. With the option, the
number becomes 18,035, a 30% reduction.
The new option is exprerimental; we may remove it in a future versions of
the mold linker.
2023-10-02 11:30:21 +03:00
|
|
|
int foo() { return 3; }
|
|
|
|
int bar() { return foo(); }
|
|
|
|
EOF
|
|
|
|
|
2023-10-19 05:44:05 +03:00
|
|
|
cat <<EOF | $CC -o $t/b.o -c -xc - -ffunction-sections -O -fcf-protection
|
Add an experimental `-z rewrite-endbr` option
endbr64 is a relatively new x86 instruction to mark a location to which an
indirect jump instruction can transfer control. If the control-flow
integrity is turned on (i.e., endbr64 is effective), an indirect jump can
only target an endbr64 or raise a runtime exception. This mechanism makes
some types of control hijacking attacks, such as ROP or JOP, very hard
because an attacker can no longer jump to an arbitrary location.
If `-fcf-protection` is given, GCC emits an endbr64 at the beginning of
each global function conservatively because the address of that function
might be used by other translation units.
In reality, most function addresses aren't taken, so the conservative
assumption ends up emitting lots of unnecessary endbr64 instructions.
This not only bloats the code but also weakens security because an
attacker would have more locations to attack.
The new linker option, `-z rewrite-endbr`, is designed to mitigate this
situation. The linker is in a position to conduct whole-program analysis
on the input files and determine functions whose addresses have never been
taken. If `-z rewrite-endbr` is given, mold performs that analysis and
rewrites the leading endbr64 with a nop if the function's address wasn't
taken.
For evaluation, I built the mold executable itself both with and without
this option. Before using the `-z rewrite-endbr` option, the mold
executable contained 25,994 endbr64 instructions. With the option, the
number becomes 18,035, a 30% reduction.
The new option is exprerimental; we may remove it in a future versions of
the mold linker.
2023-10-02 11:30:21 +03:00
|
|
|
int main() {}
|
|
|
|
EOF
|
|
|
|
|
|
|
|
$CC -B. -o $t/exe1 $t/a.o $t/b.o
|
|
|
|
$OBJDUMP -dr $t/exe1 > $t/log1
|
|
|
|
|
|
|
|
grep -A1 '<foo>:' $t/log1 | grep -q endbr64
|
|
|
|
grep -A1 '<bar>:' $t/log1 | grep -q endbr64
|
|
|
|
grep -A1 '<main>:' $t/log1 | grep -q endbr64
|
|
|
|
|
2024-08-02 08:20:25 +03:00
|
|
|
$CC -B. -o $t/exe2 $t/a.o $t/b.o -Wl,-z,rewrite-endbr
|
Add an experimental `-z rewrite-endbr` option
endbr64 is a relatively new x86 instruction to mark a location to which an
indirect jump instruction can transfer control. If the control-flow
integrity is turned on (i.e., endbr64 is effective), an indirect jump can
only target an endbr64 or raise a runtime exception. This mechanism makes
some types of control hijacking attacks, such as ROP or JOP, very hard
because an attacker can no longer jump to an arbitrary location.
If `-fcf-protection` is given, GCC emits an endbr64 at the beginning of
each global function conservatively because the address of that function
might be used by other translation units.
In reality, most function addresses aren't taken, so the conservative
assumption ends up emitting lots of unnecessary endbr64 instructions.
This not only bloats the code but also weakens security because an
attacker would have more locations to attack.
The new linker option, `-z rewrite-endbr`, is designed to mitigate this
situation. The linker is in a position to conduct whole-program analysis
on the input files and determine functions whose addresses have never been
taken. If `-z rewrite-endbr` is given, mold performs that analysis and
rewrites the leading endbr64 with a nop if the function's address wasn't
taken.
For evaluation, I built the mold executable itself both with and without
this option. Before using the `-z rewrite-endbr` option, the mold
executable contained 25,994 endbr64 instructions. With the option, the
number becomes 18,035, a 30% reduction.
The new option is exprerimental; we may remove it in a future versions of
the mold linker.
2023-10-02 11:30:21 +03:00
|
|
|
$OBJDUMP -dr $t/exe2 > $t/log2
|
|
|
|
|
|
|
|
grep -A1 '<foo>:' $t/log2 | grep -q nop
|
|
|
|
grep -A1 '<bar>:' $t/log2 | grep -q nop
|
|
|
|
grep -A1 '<main>:' $t/log2 | grep -q endbr64
|