Skip to contentSkip to conversation

compiler_types: Provide __no_kstack_erase to disable coverage only on Clang

PATCH Superseded Kees Cook 3 participants 4 messages Jul 29, 2025 x86

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Kees Cook

author
#0 lore raw

PATCH 1/1 compiler_types: Provide __no_kstack_erase to disable coverage only on Clang

In order to support Clang's stack depth tracking (for Linux's kstack_erase feature), the coverage sanitizer needed to be disabled for __init (and __head) section code. Doing this universally (i.e. for GCC too), created a number of unexpected problems, ranging from changes to inlining logic to failures to DCE code on earlier GCC versions.

Since this change is only needed for Clang, specialize it so that GCC doesn't see the change as it isn't needed there (the GCC implementation of kstack_erase uses a GCC plugin that removes stack depth tracking instrumentation from __init sections during a late pass in the IR).

Successful build and boot tested with GCC 12 and Clang 22.

---
Cc: Linus Torvalds <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Hou Wenlong <[email protected]>
Cc: Kirill A. Shutemov <[email protected]>
Cc: Miguel Ojeda <[email protected]>
Cc: Nathan Chancellor <[email protected]>
Cc: Przemek Kitszel <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Masahiro Yamada <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Wei Yang <[email protected]>
Cc: Sami Tolvanen <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Christophe Leroy <[email protected]>

---
 arch/x86/include/asm/init.h    | 2 +-
 include/linux/compiler_types.h | 7 +++++++
 include/linux/init.h           | 2 +-
 3 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/init.h +1 -1
index 6bfdaeddbae8..5a68e9db6518 100644
@@ -5,7 +5,7 @@
 #if defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 170000
 #define __head	__section(".head.text") __no_sanitize_undefined __no_stack_protector
 #else
-#define __head	__section(".head.text") __no_sanitize_undefined __no_sanitize_coverage
+#define __head	__section(".head.text") __no_sanitize_undefined __no_kstack_erase
 #endif
 
 struct x86_mapping_info {
include/linux/compiler_types.h +7 -0
index 2b77d12e07b2..89e2c01fc8b1 100644
@@ -378,6 +378,13 @@ struct ftrace_likely_data {
 # define __signed_wrap
 #endif
 
+/* GCC does not like splitting sanitizer coverage across section inlines */
+#ifdef CC_IS_CLANG
+#define __no_kstack_erase	__no_sanitize_coverage
+#else
+#define __no_kstack_erase
+#endif
+
 /* Section for code which can't be instrumented at all */
 #define __noinstr_section(section)					\
 	noinline notrace __attribute((__section__(section)))		\
include/linux/init.h +1 -1
index c65a050d52a7..a60d32d227ee 100644
@@ -51,7 +51,7 @@
    discard it in modules) */
 #define __init		__section(".init.text") __cold __latent_entropy	\
 						__noinitretpoline	\
-						__no_sanitize_coverage
+						__no_kstack_erase
 #define __initdata	__section(".init.data")
 #define __initconst	__section(".init.rodata")
 #define __exitdata	__section(".exit.data")
Signature · 1 line
2.34.1
#1 lore raw
Quoted 66 lines · Kees Cook

In order to support Clang's stack depth tracking (for Linux's kstack_erase feature), the coverage sanitizer needed to be disabled for __init (and __head) section code. Doing this universally (i.e. for GCC too), created a number of unexpected problems, ranging from changes to inlining logic to failures to DCE code on earlier GCC versions.

Since this change is only needed for Clang, specialize it so that GCC doesn't see the change as it isn't needed there (the GCC implementation of kstack_erase uses a GCC plugin that removes stack depth tracking instrumentation from __init sections during a late pass in the IR).

Successful build and boot tested with GCC 12 and Clang 22.

---
Cc: Linus Torvalds <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Hou Wenlong <[email protected]>
Cc: Kirill A. Shutemov <[email protected]>
Cc: Miguel Ojeda <[email protected]>
Cc: Nathan Chancellor <[email protected]>
Cc: Przemek Kitszel <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Masahiro Yamada <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Wei Yang <[email protected]>
Cc: Sami Tolvanen <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Christophe Leroy <[email protected]>

---
 arch/x86/include/asm/init.h    | 2 +-
 include/linux/compiler_types.h | 7 +++++++
 include/linux/init.h           | 2 +-
 3 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/init.h +1 -1
index 6bfdaeddbae8..5a68e9db6518 100644
@@ -5,7 +5,7 @@
 #if defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 170000
 #define __head __section(".head.text") __no_sanitize_undefined __no_stack_protector
 #else
-#define __head __section(".head.text") __no_sanitize_undefined __no_sanitize_coverage
+#define __head __section(".head.text") __no_sanitize_undefined __no_kstack_erase
 #endif
 
 struct x86_mapping_info {
include/linux/compiler_types.h +0 -0
index 2b77d12e07b2..89e2c01fc8b1 100644

include/linux/compiler_types.h struct ftrace_likely_data { · line 386

Quoted 9 lines
include/linux/compiler_types.h +6 -0
@@ -378,6 +378,13 @@ struct ftrace_likely_data {
 # define __signed_wrap
 #endif
 
+/* GCC does not like splitting sanitizer coverage across section inlines */
+#ifdef CC_IS_CLANG
+#define __no_kstack_erase      __no_sanitize_coverage
+#else
+#define __no_kstack_erase
+#endif

I think this belongs into compiler-clang.h, we've typically refrained from ifdef CC_IS_CLANG/GCC in the generic headers.
See __nocfi for an example, where compiler_types.h provides a default empty definition, and compiler-clang.h provides a non-empty definition.

#2 lore raw
Quoted 6 lines · Marco Elver

I think this belongs into compiler-clang.h, we've typically refrained from ifdef CC_IS_CLANG/GCC in the generic headers.
See __nocfi for an example, where compiler_types.h provides a default empty definition, and compiler-clang.h provides a non-empty definition.

Yeah, I think that would be a lot cleaner and matches the other things like this.

Linus

author
#3 lore raw
In reply to Marco Elver
Quoted 70 lines · Marco Elver
Quoted 69 lines · Kees Cook

In order to support Clang's stack depth tracking (for Linux's kstack_erase feature), the coverage sanitizer needed to be disabled for __init (and __head) section code. Doing this universally (i.e. for GCC too), created a number of unexpected problems, ranging from changes to inlining logic to failures to DCE code on earlier GCC versions.

Since this change is only needed for Clang, specialize it so that GCC doesn't see the change as it isn't needed there (the GCC implementation of kstack_erase uses a GCC plugin that removes stack depth tracking instrumentation from __init sections during a late pass in the IR).

Successful build and boot tested with GCC 12 and Clang 22.

---
Cc: Linus Torvalds <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Hou Wenlong <[email protected]>
Cc: Kirill A. Shutemov <[email protected]>
Cc: Miguel Ojeda <[email protected]>
Cc: Nathan Chancellor <[email protected]>
Cc: Przemek Kitszel <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Masahiro Yamada <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Wei Yang <[email protected]>
Cc: Sami Tolvanen <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Christophe Leroy <[email protected]>

---
 arch/x86/include/asm/init.h    | 2 +-
 include/linux/compiler_types.h | 7 +++++++
 include/linux/init.h           | 2 +-
 3 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/init.h +1 -1
index 6bfdaeddbae8..5a68e9db6518 100644
@@ -5,7 +5,7 @@
 #if defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 170000
 #define __head __section(".head.text") __no_sanitize_undefined __no_stack_protector
 #else
-#define __head __section(".head.text") __no_sanitize_undefined __no_sanitize_coverage
+#define __head __section(".head.text") __no_sanitize_undefined __no_kstack_erase
 #endif
 
 struct x86_mapping_info {
include/linux/compiler_types.h +0 -0
index 2b77d12e07b2..89e2c01fc8b1 100644
@@ -378,6 +378,13 @@ struct ftrace_likely_data {
 # define __signed_wrap
 #endif
 
Quoted 12 lines

include/linux/compiler_types.h struct ftrace_likely_data { · line 386

Quoted 6 lines
include/linux/compiler_types.h +6 -0
+/* GCC does not like splitting sanitizer coverage across section inlines */
+#ifdef CC_IS_CLANG
+#define __no_kstack_erase      __no_sanitize_coverage
+#else
+#define __no_kstack_erase
+#endif

I think this belongs into compiler-clang.h, we've typically refrained from ifdef CC_IS_CLANG/GCC in the generic headers.
See __nocfi for an example, where compiler_types.h provides a default empty definition, and compiler-clang.h provides a non-empty definition.

Oh, good point. I will rearrange this to use the #ifndef style handling!

Signature · 1 line
Kees Cook