From: Justin Stitt <[email protected]> Replace CONFIG_UBSAN_INTEGER_WRAP with CONFIG_OVERFLOW_BEHAVIOR_TYPES, which a more distinct implementation of the integer wrapping logic, with the introduction of the Overflow Behavior Types in Clang 23+. While this uses sanitizers, it isn't really part of the "undefined behavior" sanitizer collection (there is nothing "undefined" going on, but the warn/trap infrastructure is still used for common instrumentation).
As OBTs will be annotated in code, we no longer need type annotation in the sanitizer SCL file. A build with CONFIG_OVERFLOW_BEHAVIOR_TYPES=y will result in no new instrumentation being added (as there are no users of the coming __ob_trap and __ob_wrap annotations yet). Signed-off-by: Justin Stitt <[email protected]> Co-developed-by: Kees Cook <[email protected]> Signed-off-by: Kees Cook <[email protected]> --- Cc: Nathan Chancellor <[email protected]> Cc: Nicolas Schier <[email protected]> Cc: <[email protected]> Cc: <[email protected]> --- lib/Kconfig.ubsan | 18 ------------ security/Kconfig.hardening | 50 +++++++++++++++++++++++++++++++- Makefile | 1 + scripts/basic/Makefile | 2 +- scripts/Makefile.lib | 7 +++-- scripts/Makefile.obt | 28 ++++++++++++++++++ scripts/Makefile.ubsan | 10 ------- scripts/Makefile.warn | 7 +++++ scripts/integer-wrap-ignore.scl | 3 +- include/linux/compiler-version.h | 2 +- include/linux/sched.h | 3 +- include/linux/ubsan.h | 12 +++++++- lib/ubsan.c | 17 ++++++----- MAINTAINERS | 9 ++++++ kernel/configs/hardening.config | 1 - 15 files changed, 125 insertions(+), 45 deletions(-) create mode 100644 scripts/Makefile.obt diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index 1ecaae7064d2..666286e0d294 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -116,24 +116,6 @@ config UBSAN_UNREACHABLE This option enables -fsanitize=unreachable which checks for control flow reaching an expected-to-be-unreachable position. -config UBSAN_INTEGER_WRAP - bool "Perform checking for integer arithmetic wrap-around" - # This is very experimental so drop the next line if you really want it - depends on BROKEN - depends on !COMPILE_TEST - depends on $(cc-option,-fsanitize-undefined-ignore-overflow-pattern=all) - depends on $(cc-option,-fsanitize=signed-integer-overflow) - depends on $(cc-option,-fsanitize=unsigned-integer-overflow) - depends on $(cc-option,-fsanitize=implicit-signed-integer-truncation) - depends on $(cc-option,-fsanitize=implicit-unsigned-integer-truncation) - depends on $(cc-option,-fsanitize-ignorelist=/dev/null) - help - This option enables all of the sanitizers involved in integer overflow - (wrap-around) mitigation: signed-integer-overflow, unsigned-integer-overflow, - implicit-signed-integer-truncation, and implicit-unsigned-integer-truncation. - This is currently limited only to the size_t type while testing and - compiler development continues. - config UBSAN_BOOL bool "Perform checking for non-boolean values used as boolean" default UBSAN diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening index 86f8768c63d4..0c9e03c8a5a7 100644 --- a/security/Kconfig.hardening +++ b/security/Kconfig.hardening @@ -211,7 +211,55 @@ config ZERO_CALL_USED_REGS endmenu -menu "Bounds checking" +menu "Bounds safety" + +config CC_HAS_OVERFLOW_BEHAVIOR_TYPES + # Clang 23+ + depends on CC_IS_CLANG + def_bool $(cc-option,-Xclang -fexperimental-overflow-behavior-types) + +config OVERFLOW_BEHAVIOR_TYPES + bool + help + Selected if either OVERFLOW_BEHAVIOR_TYPES_TRAP or + OVERFLOW_BEHAVIOR_TYPES_WARN is chosen. + +choice + prompt "Perform checking for integer arithmetic wrap-around" + default OVERFLOW_BEHAVIOR_TYPES_TRAP if CC_HAS_OVERFLOW_BEHAVIOR_TYPES + default OVERFLOW_BEHAVIOR_TYPES_WARN if COMPILE_TEST && CC_HAS_OVERFLOW_BEHAVIOR_TYPES + default OVERFLOW_BEHAVIOR_TYPES_NONE + help + This option enables Overflow Behavior Types and all of the + sanitizers involved in integer overflow (wrap-around) mitigation: + signed-integer-overflow, unsigned-integer-overflow, + implicit-signed-integer-truncation, implicit-unsigned-integer-truncation, + and implicit-integer-sign-change. Only types (and variables) + annotated with __ob_wrap or __ob_trap will be instrumented by the + compiler. + + config OVERFLOW_BEHAVIOR_TYPES_TRAP + bool "Trap when __ob_trap types overflow (mitigate)" + depends on CC_HAS_OVERFLOW_BEHAVIOR_TYPES + select OVERFLOW_BEHAVIOR_TYPES + help + Enables Overflow Behavior Types and traps when __ob_trap + annotated variables overflow or underflow. + + config OVERFLOW_BEHAVIOR_TYPES_WARN + bool "Warn when __ob_trap types overflow (informational)" + depends on CC_HAS_OVERFLOW_BEHAVIOR_TYPES + select OVERFLOW_BEHAVIOR_TYPES + help + Enables Overflow Behavior Types and warns when __ob_trap + annotated variables overflow or underflow. + + config OVERFLOW_BEHAVIOR_TYPES_NONE + bool "Disable any handling of __ob_trap types (disabled)" + help + No special handling of __ob_trap annotated types. + +endchoice config FORTIFY_SOURCE bool "Harden common str/mem functions against buffer overflows" diff --git a/Makefile b/Makefile index 2446085983f7..8e7336d22488 100644 --- a/Makefile +++ b/Makefile @@ -1123,6 +1123,7 @@ include-$(CONFIG_KASAN) += scripts/Makefile.kasan include-$(CONFIG_KCSAN) += scripts/Makefile.kcsan include-$(CONFIG_KMSAN) += scripts/Makefile.kmsan include-$(CONFIG_UBSAN) += scripts/Makefile.ubsan +include-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES) += scripts/Makefile.obt include-$(CONFIG_KCOV) += scripts/Makefile.kcov include-$(CONFIG_RANDSTRUCT) += scripts/Makefile.randstruct include-$(CONFIG_KSTACK_ERASE) += scripts/Makefile.kstack_erase diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile index fb8e2c38fbc7..098760fc403a 100644 --- a/scripts/basic/Makefile +++ b/scripts/basic/Makefile @@ -18,4 +18,4 @@ always-$(CONFIG_RANDSTRUCT) += randstruct.seed # integer-wrap: if the .scl file changes, we need to do a full rebuild. $(obj)/../../include/generated/integer-wrap.h: $(srctree)/scripts/integer-wrap-ignore.scl FORCE $(call if_changed,touch) -always-$(CONFIG_UBSAN_INTEGER_WRAP) += ../../include/generated/integer-wrap.h +always-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES) += ../../include/generated/integer-wrap.h diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 0718e39cedda..d0e5cf2b0e3f 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -76,9 +76,12 @@ ifeq ($(CONFIG_UBSAN),y) _c_flags += $(if $(patsubst n%,, \ $(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SANITIZE)$(is-kernel-object)), \ $(CFLAGS_UBSAN)) +endif + +ifeq ($(CONFIG_OVERFLOW_BEHAVIOR_TYPES),y) _c_flags += $(if $(patsubst n%,, \ - $(UBSAN_INTEGER_WRAP_$(target-stem).o)$(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_INTEGER_WRAP)$(UBSAN_SANITIZE)$(is-kernel-object)), \ - $(CFLAGS_UBSAN_INTEGER_WRAP)) + $(OVERFLOW_BEHAVIOR_TYPES_$(target-stem).o)$(OVERFLOW_BEHAVIOR_TYPES)$(is-kernel-object)), \ + $(CFLAGS_OVERFLOW_BEHAVIOR_TYPES)) endif ifeq ($(CONFIG_KCOV),y) diff --git a/scripts/Makefile.obt b/scripts/Makefile.obt new file mode 100644 index 000000000000..f87f87e148f9 --- /dev/null +++ b/scripts/Makefile.obt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Instead of specifying `all`, let's pick our patterns piecemeal so we aren't +# blindsided by compiler upgrades. +OVERFLOW_BEHAVIOR_TYPES_IGNORE_PATTERNS := negated-unsigned-const,$\ + unsigned-post-decr-while,$\ + add-signed-overflow-test,$\ + add-unsigned-overflow-test + +OVERFLOW_BEHAVIOR_TYPES_SANITIZERS := signed-integer-overflow,$\ + unsigned-integer-overflow,$\ + implicit-signed-integer-truncation,$\ + implicit-unsigned-integer-truncation,$\ + implicit-integer-sign-change + +overflow-behavior-types-cflags-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES) += \ + -DOVERFLOW_BEHAVIOR_TYPES \ + -Xclang -fexperimental-overflow-behavior-types \ + -fsanitize=$(OVERFLOW_BEHAVIOR_TYPES_SANITIZERS) \ + -fsanitize-undefined-ignore-overflow-pattern=$(OVERFLOW_BEHAVIOR_TYPES_IGNORE_PATTERNS) \ + -fsanitize-ignorelist=$(srctree)/scripts/integer-wrap-ignore.scl \ + -Wno-incompatible-pointer-types-discards-overflow-behavior +overflow-behavior-types-cflags-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES_WARN) += \ + -fno-sanitize-trap=$(OVERFLOW_BEHAVIOR_TYPES_SANITIZERS) +overflow-behavior-types-cflags-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP) += \ + -fsanitize-trap=$(OVERFLOW_BEHAVIOR_TYPES_SANITIZERS) + +export CFLAGS_OVERFLOW_BEHAVIOR_TYPES := $(overflow-behavior-types-cflags-y) diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 734a102e6b56..fb49302078e5 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -16,13 +16,3 @@ ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(CFLAGS_UBSAN_TRAP) export CFLAGS_UBSAN := $(ubsan-cflags-y) - -ubsan-integer-wrap-cflags-$(CONFIG_UBSAN_INTEGER_WRAP) += \ - -DINTEGER_WRAP \ - -fsanitize-undefined-ignore-overflow-pattern=all \ - -fsanitize=signed-integer-overflow \ - -fsanitize=unsigned-integer-overflow \ - -fsanitize=implicit-signed-integer-truncation \ - -fsanitize=implicit-unsigned-integer-truncation \ - -fsanitize-ignorelist=$(srctree)/scripts/integer-wrap-ignore.scl -export CFLAGS_UBSAN_INTEGER_WRAP := $(ubsan-integer-wrap-cflags-y) diff --git a/scripts/Makefile.warn b/scripts/Makefile.warn index 5567da6c7dfe..eae0ecb88da4 100644 --- a/scripts/Makefile.warn +++ b/scripts/Makefile.warn @@ -49,6 +49,13 @@ KBUILD_CFLAGS += $(call cc-option, -Wno-format-truncation-non-kprintf) # because -Wuninitialized will still flag when an uninitialized const variable # is used. KBUILD_CFLAGS += $(call cc-option, -Wno-default-const-init-unsafe) + +# Clang with Overflow Behavior Types support but building a kernel without +# CONFIG_OVERFLOW_BEHAVIOR_TYPES needs to explicitly ignore the attribute. +ifndef CONFIG_OVERFLOW_BEHAVIOR_TYPES +KBUILD_CFLAGS += $(call cc-option, -Wno-overflow-behavior-attribute-ignored) +endif + else # gcc inanely warns about local variables called 'main' diff --git a/scripts/integer-wrap-ignore.scl b/scripts/integer-wrap-ignore.scl index 431c3053a4a2..8168d376ffff 100644 --- a/scripts/integer-wrap-ignore.scl +++ b/scripts/integer-wrap-ignore.scl @@ -1,3 +1,2 @@ -[{unsigned-integer-overflow,signed-integer-overflow,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation}] +[{unsigned-integer-overflow,signed-integer-overflow,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation,implicit-integer-sign-change}] type:* -type:size_t=sanitize diff --git a/include/linux/compiler-version.h b/include/linux/compiler-version.h index ac1665a98a15..20033781ff15 100644 --- a/include/linux/compiler-version.h +++ b/include/linux/compiler-version.h @@ -39,6 +39,6 @@ * may have changed, which may impact the expected behaviors that should * not differ between compilation units. */ -#ifdef INTEGER_WRAP +#ifdef OVERFLOW_BEHAVIOR_TYPES #include <generated/integer-wrap.h> #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index a7b4a980eb2f..d3e2ae0e2fe4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -48,6 +48,7 @@ #include <linux/uidgid_types.h> #include <linux/tracepoint-defs.h> #include <linux/unwind_deferred_types.h> +#include <linux/ubsan.h> #include <asm/kmap_size.h> #include <linux/time64.h> #ifndef COMPILE_OFFSETS @@ -1271,7 +1272,7 @@ struct task_struct { struct held_lock held_locks[MAX_LOCK_DEPTH]; #endif -#if defined(CONFIG_UBSAN) && !defined(CONFIG_UBSAN_TRAP) +#ifdef NEED_SANITIZER_WARN_HANDLER unsigned int in_ubsan; #endif diff --git a/include/linux/ubsan.h b/include/linux/ubsan.h index 3ab8d38aedb8..7fedff0cdf8e 100644 --- a/include/linux/ubsan.h +++ b/include/linux/ubsan.h @@ -2,7 +2,17 @@ #ifndef _LINUX_UBSAN_H #define _LINUX_UBSAN_H -#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2) +#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2) || \ + defined(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP) +# define NEED_SANITIZER_TRAP_HANDLER +#endif + +#if (defined(CONFIG_UBSAN) && !defined(CONFIG_UBSAN_TRAP)) || \ + defined(CONFIG_OVERFLOW_BEHAVIOR_TYPES_WARN) +# define NEED_SANITIZER_WARN_HANDLER +#endif + +#ifdef NEED_SANITIZER_TRAP_HANDLER const char *report_ubsan_failure(u32 check_type); #else static inline const char *report_ubsan_failure(u32 check_type) diff --git a/lib/ubsan.c b/lib/ubsan.c index 456e3dd8f4ea..19edb5cedb5a 100644 --- a/lib/ubsan.c +++ b/lib/ubsan.c @@ -19,7 +19,7 @@ #include "ubsan.h" -#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2) +#ifdef NEED_SANITIZER_TRAP_HANDLER /* * Only include matches for UBSAN checks that are actually compiled in. * The mappings of struct SanitizerKind (the -fsanitize=xxx args) to @@ -44,7 +44,7 @@ const char *report_ubsan_failure(u32 check_type) case ubsan_shift_out_of_bounds: return "UBSAN: shift out of bounds"; #endif -#if defined(CONFIG_UBSAN_DIV_ZERO) || defined(CONFIG_UBSAN_INTEGER_WRAP) +#if defined(CONFIG_UBSAN_DIV_ZERO) || defined(CONFIG_OVERFLOW_BEHAVIOR_TYPES) /* * SanitizerKind::IntegerDivideByZero and * SanitizerKind::SignedIntegerOverflow emit @@ -79,7 +79,7 @@ const char *report_ubsan_failure(u32 check_type) case ubsan_type_mismatch: return "UBSAN: type mismatch"; #endif -#ifdef CONFIG_UBSAN_INTEGER_WRAP +#ifdef CONFIG_OVERFLOW_BEHAVIOR_TYPES /* * SanitizerKind::SignedIntegerOverflow emits * SanitizerHandler::AddOverflow, SanitizerHandler::SubOverflow, @@ -91,15 +91,18 @@ const char *report_ubsan_failure(u32 check_type) return "UBSAN: integer subtraction overflow"; case ubsan_mul_overflow: return "UBSAN: integer multiplication overflow"; + case ubsan_implicit_conversion: + return "UBSAN: integer truncation"; + case ubsan_negate_overflow: + return "UBSAN: negation overflow"; #endif default: return "UBSAN: unrecognized failure code"; } } +#endif /* NEED_SANITIZER_TRAP_HANDLER */ -#endif - -#ifndef CONFIG_UBSAN_TRAP +#ifdef NEED_SANITIZER_WARN_HANDLER static const char * const type_check_kinds[] = { "load of", "store to", @@ -558,4 +561,4 @@ void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, } EXPORT_SYMBOL(__ubsan_handle_alignment_assumption); -#endif /* !CONFIG_UBSAN_TRAP */ +#endif /* NEED_SANITIZER_WARN_HANDLER */ diff --git a/MAINTAINERS b/MAINTAINERS index 61bf550fd37c..a9f067164203 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19919,6 +19919,15 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov2659.txt F: drivers/media/i2c/ov2659.c F: include/media/i2c/ov2659.h +OVERFLOW BEHAVIOR TYPES +M: Kees Cook <[email protected]> +M: Justin Stitt <[email protected]> +L: [email protected] +S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening +F: scripts/integer-wrap-ignore.scl +F: scripts/Makefile.obt + OVERLAY FILESYSTEM M: Miklos Szeredi <[email protected]> M: Amir Goldstein <[email protected]> diff --git a/kernel/configs/hardening.config b/kernel/configs/hardening.config index 7c3924614e01..aabe28005a3d 100644 --- a/kernel/configs/hardening.config +++ b/kernel/configs/hardening.config @@ -46,7 +46,6 @@ CONFIG_UBSAN_BOUNDS=y # CONFIG_UBSAN_SHIFT is not set # CONFIG_UBSAN_DIV_ZERO is not set # CONFIG_UBSAN_UNREACHABLE is not set -# CONFIG_UBSAN_INTEGER_WRAP is not set # CONFIG_UBSAN_BOOL is not set # CONFIG_UBSAN_ENUM is not set # CONFIG_UBSAN_ALIGNMENT is not set -- 2.34.1

