Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[X86] initial -mfunction-return=thunk-extern support
Adds support for: * `-mfunction-return=<value>` command line flag, and * `__attribute__((function_return("<value>")))` function attribute Where the supported <value>s are: * keep (disable) * thunk-extern (enable) thunk-extern enables clang to change ret instructions into jmps to an external symbol named __x86_return_thunk, implemented as a new MachineFunctionPass named "x86-return-thunks", keyed off the new IR attribute fn_ret_thunk_extern. The symbol __x86_return_thunk is expected to be provided by the runtime the compiled code is linked against and is not defined by the compiler. Enabling this option alone doesn't provide mitigations without corresponding definitions of __x86_return_thunk! This new MachineFunctionPass is very similar to "x86-lvi-ret". The <value>s "thunk" and "thunk-inline" are currently unsupported. It's not clear yet that they are necessary: whether the thunk pattern they would emit is beneficial or used anywhere. Should the <value>s "thunk" and "thunk-inline" become necessary, x86-return-thunks could probably be merged into x86-retpoline-thunks which has pre-existing machinery for emitting thunks (which could be used to implement the <value> "thunk"). Has been found to build+boot with corresponding Linux kernel patches. This helps the Linux kernel mitigate RETBLEED. * CVE-2022-23816 * CVE-2022-28693 * CVE-2022-29901 See also: * "RETBLEED: Arbitrary Speculative Code Execution with Return Instructions." * AMD SECURITY NOTICE AMD-SN-1037: AMD CPU Branch Type Confusion * TECHNICAL GUIDANCE FOR MITIGATING BRANCH TYPE CONFUSION REVISION 1.0 2022-07-12 * Return Stack Buffer Underflow / Return Stack Buffer Underflow / CVE-2022-29901, CVE-2022-28693 / INTEL-SA-00702 SystemZ may eventually want to support "thunk-extern" and "thunk"; both options are used by the Linux kernel's CONFIG_EXPOLINE. This functionality has been available in GCC since the 8.1 release, and was backported to the 7.3 release. Many thanks for folks that provided discrete review off list due to the embargoed nature of this hardware vulnerability. Many Bothans died to bring us this information. Link: https://www.youtube.com/watch?v=IF6HbCKQHK8 Link: #54404 Link: https://gcc.gnu.org/legacy-ml/gcc-patches/2018-01/msg01197.html Link: https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/return-stack-buffer-underflow.html Link: https://arstechnica.com/information-technology/2022/07/intel-and-amd-cpus-vulnerable-to-a-new-speculative-execution-attack/?comments=1 Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ce114c866860aa9eae3f50974efc68241186ba60 Link: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00702.html Link: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00707.html Reviewed By: aaron.ballman, craig.topper Differential Revision: https://reviews.llvm.org/D129572
- Loading branch information
1 parent
5791bcf
commit 2240d72
Showing
33 changed files
with
572 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \ | ||
// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-NOM | ||
// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \ | ||
// RUN: -mfunction-return=keep | FileCheck %s \ | ||
// RUN: --check-prefixes=CHECK,CHECK-KEEP | ||
// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \ | ||
// RUN: -mfunction-return=thunk-extern | FileCheck %s \ | ||
// RUN: --check-prefixes=CHECK,CHECK-EXTERN | ||
|
||
#if !__has_attribute(function_return) | ||
#error "missing attribute support for function_return" | ||
#endif | ||
|
||
// CHECK: @keep() [[KEEP:#[0-9]+]] | ||
__attribute__((function_return("keep"))) void keep(void) {} | ||
|
||
// CHECK: @keep2() [[KEEP:#[0-9]+]] | ||
[[gnu::function_return("keep")]] void keep2(void) {} | ||
|
||
// CHECK: @thunk_extern() [[EXTERN:#[0-9]+]] | ||
__attribute__((function_return("thunk-extern"))) void thunk_extern(void) {} | ||
|
||
// CHECK: @thunk_extern2() [[EXTERN:#[0-9]+]] | ||
[[gnu::function_return("thunk-extern")]] void thunk_extern2(void) {} | ||
|
||
// CHECK: @double_thunk_keep() [[KEEP]] | ||
// clang-format off | ||
__attribute__((function_return("thunk-extern"))) | ||
__attribute__((function_return("keep"))) | ||
void double_thunk_keep(void) {} | ||
|
||
// CHECK: @double_thunk_keep2() [[KEEP]] | ||
[[gnu::function_return("thunk-extern")]][[gnu::function_return("keep")]] | ||
void double_thunk_keep2(void) {} | ||
|
||
// CHECK: @double_keep_thunk() [[EXTERN]] | ||
__attribute__((function_return("keep"))) | ||
__attribute__((function_return("thunk-extern"))) | ||
void double_keep_thunk(void) {} | ||
|
||
// CHECK: @double_keep_thunk2() [[EXTERN]] | ||
[[gnu::function_return("thunk-keep")]][[gnu::function_return("thunk-extern")]] | ||
void double_keep_thunk2(void) {} | ||
|
||
// CHECK: @thunk_keep() [[KEEP]] | ||
__attribute__((function_return("thunk-extern"), function_return("keep"))) | ||
void thunk_keep(void) {} | ||
|
||
// CHECK: @thunk_keep2() [[KEEP]] | ||
[[gnu::function_return("thunk-extern"), gnu::function_return("keep")]] | ||
void thunk_keep2(void) {} | ||
|
||
// CHECK: @keep_thunk() [[EXTERN]] | ||
__attribute__((function_return("keep"), function_return("thunk-extern"))) | ||
void keep_thunk(void) {} | ||
|
||
// CHECK: @keep_thunk2() [[EXTERN]] | ||
[[gnu::function_return("keep"), gnu::function_return("thunk-extern")]] | ||
void keep_thunk2(void) {} | ||
// clang-format on | ||
|
||
void undef(void); | ||
// CHECK: @undef() [[KEEP]] | ||
__attribute__((function_return("keep"))) void undef(void) {} | ||
|
||
void undef2(void); | ||
// CHECK: @undef2() [[EXTERN]] | ||
__attribute__((function_return("thunk-extern"))) void undef2(void) {} | ||
|
||
__attribute__((function_return("thunk-extern"))) void change_def(void); | ||
// CHECK: @change_def() [[KEEP]] | ||
__attribute__((function_return("keep"))) void change_def(void) {} | ||
|
||
__attribute__((function_return("keep"))) void change_def2(void); | ||
// CHECK: @change_def2() [[EXTERN]] | ||
__attribute__((function_return("thunk-extern"))) void change_def2(void) {} | ||
|
||
__attribute__((function_return("thunk-extern"))) void change_def3(void); | ||
// CHECK: @change_def3() [[KEEP]] | ||
[[gnu::function_return("keep")]] void change_def3(void) {} | ||
|
||
[[gnu::function_return("keep")]] void change_def4(void); | ||
// CHECK: @change_def4() [[EXTERN]] | ||
__attribute__((function_return("thunk-extern"))) void change_def4(void) {} | ||
|
||
// When there is no -mfunction-return= flag set (NOM) or it's set to keep, | ||
// we don't emit anything into the IR for unattributed functions. | ||
|
||
// CHECK-NOM: @no_attrs() [[NOATTR:#[0-9]+]] | ||
// CHECK-KEEP: @no_attrs() [[NOATTR:#[0-9]+]] | ||
// CHECK-EXTERN: @no_attrs() [[EXTERN]] | ||
void no_attrs(void) {} | ||
|
||
// CHECK-NOM-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern | ||
// CHECK-KEEP-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern | ||
// CHECK: [[EXTERN]] = {{.*}}fn_ret_thunk_extern |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -emit-llvm -o - \ | ||
// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-NOM | ||
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -emit-llvm -o - \ | ||
// RUN: -mfunction-return=keep | FileCheck %s \ | ||
// RUN: --check-prefixes=CHECK,CHECK-KEEP | ||
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -emit-llvm -o - \ | ||
// RUN: -mfunction-return=thunk-extern | FileCheck %s \ | ||
// RUN: --check-prefixes=CHECK,CHECK-EXTERN | ||
|
||
int foo(void) { | ||
// CHECK: @"_ZZ3foovENK3$_0clEv"({{.*}}) [[NOATTR:#[0-9]+]] | ||
return []() { | ||
return 42; | ||
}(); | ||
} | ||
int bar(void) { | ||
// CHECK: @"_ZZ3barvENK3$_1clEv"({{.*}}) [[EXTERN:#[0-9]+]] | ||
return []() __attribute__((function_return("thunk-extern"))) { | ||
return 42; | ||
} | ||
(); | ||
} | ||
int baz(void) { | ||
// CHECK: @"_ZZ3bazvENK3$_2clEv"({{.*}}) [[KEEP:#[0-9]+]] | ||
return []() __attribute__((function_return("keep"))) { | ||
return 42; | ||
} | ||
(); | ||
} | ||
|
||
class Foo { | ||
public: | ||
// CHECK: @_ZN3Foo3fooEv({{.*}}) [[EXTERN]] | ||
__attribute__((function_return("thunk-extern"))) int foo() { return 42; } | ||
}; | ||
|
||
int quux() { | ||
Foo my_foo; | ||
return my_foo.foo(); | ||
} | ||
|
||
// CHECK: @extern_c() [[EXTERN]] | ||
extern "C" __attribute__((function_return("thunk-extern"))) void extern_c() {} | ||
extern "C" { | ||
// CHECK: @extern_c2() [[EXTERN]] | ||
__attribute__((function_return("thunk-extern"))) void extern_c2() {} | ||
} | ||
|
||
// CHECK-NOM-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern | ||
// CHECK-KEEP-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern | ||
// CHECK-KEEP-NOT: [[KEEP]] = {{.*}}fn_ret_thunk_extern | ||
// CHECK-EXTERN: [[EXTERN]] = {{.*}}fn_ret_thunk_extern |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// RUN: %clang -mfunction-return= -### %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-VALID %s | ||
// RUN: not %clang -mfunction-return -### %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-INVALID %s | ||
|
||
// RUN: %clang -mfunction-return=keep -### %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-KEEP %s | ||
// RUN: %clang -mfunction-return=thunk-extern -### %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-EXTERN %s | ||
|
||
// RUN: %clang -mfunction-return=keep -mfunction-return=thunk-extern -### %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-EXTERN %s | ||
// RUN: %clang -mfunction-return=thunk-extern -mfunction-return=keep -### %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-KEEP %s | ||
|
||
// CHECK-VALID: "-mfunction-return=" | ||
// CHECK-INVALID: error: unknown argument: '-mfunction-return' | ||
|
||
// CHECK-KEEP: "-mfunction-return=keep" | ||
// CHECK-KEEP-NOT: "-mfunction-return=thunk-extern" | ||
// CHECK-EXTERN: "-mfunction-return=thunk-extern" | ||
// CHECK-EXTERN-NOT: "-mfunction-return=keep" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// RUN: %clang_cc1 -mfunction-return=keep -triple x86_64-linux-gnu %s | ||
// RUN: %clang_cc1 -mfunction-return=thunk-extern -triple x86_64-linux-gnu %s | ||
|
||
// RUN: not %clang_cc1 -mfunction-return=thunk -triple x86_64-linux-gnu %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-THUNK %s | ||
// RUN: not %clang_cc1 -mfunction-return=thunk-inline -triple x86_64-linux-gnu %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-INLINE %s | ||
// RUN: not %clang_cc1 -mfunction-return=invalid -triple x86_64-linux-gnu %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-INVALID %s | ||
// RUN: not %clang_cc1 -mfunction-return=thunk-extern -triple s390x-linux-gnu %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-TARGET %s | ||
// RUN: not %clang_cc1 -mfunction-return=thunk-extern -mcmodel=large \ | ||
// RUN: -triple x86_64-linux-gnu %s 2>&1 \ | ||
// RUN: | FileCheck --check-prefix=CHECK-LARGE %s | ||
|
||
// CHECK-THUNK: error: invalid value 'thunk' in '-mfunction-return=thunk' | ||
// CHECK-INLINE: error: invalid value 'thunk-inline' in '-mfunction-return=thunk-inline' | ||
// CHECK-INVALID: error: invalid value 'invalid' in '-mfunction-return=invalid' | ||
// CHECK-TARGET: error: invalid argument '-mfunction-return=' not allowed with 's390x-unknown-linux-gnu' | ||
// CHECK-LARGE: error: invalid argument '-mfunction-return=thunk-extern' not allowed with '-mcmodel=large' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.