From nobody Wed Apr 1 09:05:44 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 77249423A80; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; cv=none; b=pFgCBRxGj4zcpNgNdpeLPJL0UmgUbx3bLhyg29U2nJZjWfYNLsg1Yf5g2Geh3c9RZVrkBgb0xQnp7dWnpmCWMZ19APGmZEzfpif/yW0OwvGp/BVPmFinW60VUE/xhXBKhIxGmhd58mqMdc4xhUaxfWtQAi+XcUv4sQW0ClHSf6o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; c=relaxed/simple; bh=dRUACUfYM3hpUKt4oHZzZpLCHG7xwGYcgN8GkPASyZU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bJk8f3MQYkxoOV5OM7obEFxluB1mjvNs2TN1QZae8uqW31e91ZV+Qo6otZpqoYruJUneNOMi598h8Kt6bnQtKtegDG6jUd3fIeGKLDLH2/v6XXADaGuo3tLKvsbBAIUW6L3WyOJq4uHKT5QHdS37Sb3gDSa8qa6tpMSIHbj51iU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Mx9+0th8; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Mx9+0th8" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 34C23C19424; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774975046; bh=dRUACUfYM3hpUKt4oHZzZpLCHG7xwGYcgN8GkPASyZU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Mx9+0th8pvcSxWRvrrGWA1SxYzlIrfH/HDcZF3Sfp4ilvNE70PI8fbV60dps73LV+ ql9/kGvtatJYWvGiTq03UQSnhF6rPVLKOezvLBT3BqkAzS48eqZxIvJ+jelzsjAwqI HKK/EtEZNMOWtzo2Uh7xw3ewdW6WtOF9f2mdtVayiBui2ykpfK/xOybWsgvQAn/jUy eFIIF7fswGILddpC2a0Tg3klWU7b6oAQUAEkxQ5gbKAg1ob6O6NjzDNwOxYyjNb8EC r34iZKrLorKyjejfdidY4GK/skyXXVzCIGktFY9p7sBXIAvsmXUVKpZXNzMLEomdDW LQRKlfpq38Tfw== From: Kees Cook To: Peter Zijlstra Cc: Kees Cook , Will Deacon , Boqun Feng , Mark Rutland , Gary Guo , Nathan Chancellor , Marco Elver , Miguel Ojeda , Przemek Kitszel , Justin Stitt , Linus Torvalds , Jonathan Corbet , Nicolas Schier , Arnd Bergmann , Greg Kroah-Hartman , Andrew Morton , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, linux-hardening@vger.kernel.org, linux-doc@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev Subject: [PATCH 1/5] refcount: Remove unused __signed_wrap function annotations Date: Tue, 31 Mar 2026 09:37:19 -0700 Message-Id: <20260331163725.2765789-1-kees@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260331163716.work.696-kees@kernel.org> References: <20260331163716.work.696-kees@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3451; i=kees@kernel.org; h=from:subject; bh=dRUACUfYM3hpUKt4oHZzZpLCHG7xwGYcgN8GkPASyZU=; b=owGbwMvMwCVmps19z/KJym7G02pJDJmnfzjK7LzR55a3/gbn9ZMvGFiuWGzI0L91uq5bYbeS1 doc6dAJHaUsDGJcDLJiiixBdu5xLh5v28Pd5yrCzGFlAhnCwMUpABPpKGVkWN5yPK/dyLb64jZ7 Wb3rJw8LhXBf31h2mFeiSj1j4grZdEaGiXtDoi15rZQu3+QMezF3PpN/T/7xYPbvD9ilrEoPe+z hBAA= X-Developer-Key: i=kees@kernel.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" With CONFIG_UBSAN_INTEGER_WRAP being replaced by Overflow Behavior Types, remove the __signed_wrap function annotation as it is already unused, and any future work here will use OBT annotations instead. Signed-off-by: Kees Cook --- Cc: Will Deacon Cc: Peter Zijlstra Cc: Boqun Feng Cc: Mark Rutland Cc: Gary Guo Cc: Nathan Chancellor Cc: Marco Elver Cc: Miguel Ojeda Cc: Przemek Kitszel --- include/linux/compiler_types.h | 9 +-------- include/linux/refcount.h | 10 +++++----- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 890076d0974b..e8fd77593b68 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -432,18 +432,11 @@ struct ftrace_likely_data { #define at_least #endif =20 -/* Do not trap wrapping arithmetic within an annotated function. */ -#ifdef CONFIG_UBSAN_INTEGER_WRAP -# define __signed_wrap __attribute__((no_sanitize("signed-integer-overflow= "))) -#else -# define __signed_wrap -#endif - /* Section for code which can't be instrumented at all */ #define __noinstr_section(section) \ noinline notrace __attribute((__section__(section))) \ __no_kcsan __no_sanitize_address __no_profile __no_sanitize_coverage \ - __no_sanitize_memory __signed_wrap + __no_sanitize_memory =20 #define noinstr __noinstr_section(".noinstr.text") =20 diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 3da377ffb0c2..ba7657ced281 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -170,7 +170,7 @@ static inline unsigned int refcount_read(const refcount= _t *r) return atomic_read(&r->refs); } =20 -static inline __must_check __signed_wrap +static inline __must_check bool __refcount_add_not_zero(int i, refcount_t *r, int *oldp) { int old =3D refcount_read(r); @@ -212,7 +212,7 @@ static inline __must_check bool refcount_add_not_zero(i= nt i, refcount_t *r) return __refcount_add_not_zero(i, r, NULL); } =20 -static inline __must_check __signed_wrap +static inline __must_check bool __refcount_add_not_zero_limited_acquire(int i, refcount_t *r, int *ol= dp, int limit) { @@ -244,7 +244,7 @@ __refcount_inc_not_zero_limited_acquire(refcount_t *r, = int *oldp, int limit) return __refcount_add_not_zero_limited_acquire(1, r, oldp, limit); } =20 -static inline __must_check __signed_wrap +static inline __must_check bool __refcount_add_not_zero_acquire(int i, refcount_t *r, int *oldp) { return __refcount_add_not_zero_limited_acquire(i, r, oldp, INT_MAX); @@ -277,7 +277,7 @@ static inline __must_check bool refcount_add_not_zero_a= cquire(int i, refcount_t return __refcount_add_not_zero_acquire(i, r, NULL); } =20 -static inline __signed_wrap +static inline void __refcount_add(int i, refcount_t *r, int *oldp) { int old =3D atomic_fetch_add_relaxed(i, &r->refs); @@ -383,7 +383,7 @@ static inline void refcount_inc(refcount_t *r) __refcount_inc(r, NULL); } =20 -static inline __must_check __signed_wrap +static inline __must_check bool __refcount_sub_and_test(int i, refcount_t *r, int *oldp) { int old =3D atomic_fetch_sub_release(i, &r->refs); --=20 2.34.1 From nobody Wed Apr 1 09:05:44 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 82D8B425CEA; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; cv=none; b=ssbn32sGVB9fHUPiLOpHp/z04s4CCgqO2Bpkf86aaFjQ510cSA/dPFCduhUc/kpI8wvTDkd9O/Hq+Nw8I9OBKyFGCb/CQXy2JhLMGmSzE/RcxfTnNVjedIG6DMAQ1297csx0WDKHWYNDjkyHIMuF2xwCYg+aXBAi3sYuk7AMTjA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; c=relaxed/simple; bh=plwLZu034DP7ALedYET9m5sogF/wKfI7FZsY4DUGFzY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=hFC66APTRWu1wNVlrwES4bo/SMT+nJCU6IRPKZh53c7VInW25/EMTKyPWxFtw1ywVCCqYrwoa4NWXkVTVdZLXNe0HfHi9mcSfW3gHft8bEz5/98pDcZuG8uY/2LIkVyBNDyyc+Ai/+RP6GNNavb+yZWHe+uA0T1segd7+jpWSuY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MdkrlQsA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MdkrlQsA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 40DD9C2BCB3; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774975046; bh=plwLZu034DP7ALedYET9m5sogF/wKfI7FZsY4DUGFzY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MdkrlQsA0p/MiNam9XDR7gsxCIMEbTweDp37U1/JLB1BeMqdTH3X9LBvZUX0W9mTk qddN7VdYdP4hyaVjE3EqvuOrGzj8qWKePJcNAPA4evoCgoTMNH0CwDMhdOd0LEeToz NC0susD7dwZTqoSyMwOuEJhQQ/Mpghb1Cjfxum/EoyVIimg0Hf24hdXo2XKQcnQZix MhrLkbqpOjRld78dorgBHb061F1i+YIhJ3ziFRsPHj1Vu7jmRpLhSlljnUOk4pRrBv OvKzJzXY0lEs9NFSCxdEAhpzYGD+lCwo1E1ag6ePR9Hblk4DpUFIeZqNG7TJeLdSH7 D8Fd6XSxtRE3w== From: Kees Cook To: Peter Zijlstra Cc: Kees Cook , Justin Stitt , Nathan Chancellor , Nicolas Schier , linux-kbuild@vger.kernel.org, kasan-dev@googlegroups.com, Linus Torvalds , Marco Elver , Jonathan Corbet , Arnd Bergmann , Greg Kroah-Hartman , Miguel Ojeda , Andrew Morton , linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, linux-doc@vger.kernel.org, llvm@lists.linux.dev Subject: [PATCH 2/5] hardening: Introduce Overflow Behavior Types support Date: Tue, 31 Mar 2026 09:37:20 -0700 Message-Id: <20260331163725.2765789-2-kees@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260331163716.work.696-kees@kernel.org> References: <20260331163716.work.696-kees@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=16204; i=kees@kernel.org; h=from:subject; bh=QyrELgDzPrDq6Kmgo5WNzb34FKfbRuVEzigDIZ2rX8w=; b=owGbwMvMwCVmps19z/KJym7G02pJDJmnfzhe56xflrDBh1uX/25Oyybh7qwLQsvsMjdert4y5 V5SyMU7HaUsDGJcDLJiiixBdu5xLh5v28Pd5yrCzGFlAhnCwMUpABN5s5SRobduyvYKCQe92/vP bQ0NMvi8pFlzMq+5p8rqmV379XUaJzD8lRF/IjvZh2HyFGutmuX8By4uEVM1L5/nIbG7gEHXgD+ VFQA= X-Developer-Key: i=kees@kernel.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Justin Stitt 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=3Dy 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 Co-developed-by: Kees Cook Signed-off-by: Kees Cook --- Cc: Nathan Chancellor Cc: Nicolas Schier Cc: Cc: --- 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=3Dunreachable which checks for control flow reaching an expected-to-be-unreachable position. =20 -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=3Dall) - depends on $(cc-option,-fsanitize=3Dsigned-integer-overflow) - depends on $(cc-option,-fsanitize=3Dunsigned-integer-overflow) - depends on $(cc-option,-fsanitize=3Dimplicit-signed-integer-truncation) - depends on $(cc-option,-fsanitize=3Dimplicit-unsigned-integer-truncation) - depends on $(cc-option,-fsanitize-ignorelist=3D/dev/null) - help - This option enables all of the sanitizers involved in integer overflow - (wrap-around) mitigation: signed-integer-overflow, unsigned-integer-ove= rflow, - implicit-signed-integer-truncation, and implicit-unsigned-integer-trunc= ation. - 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 =20 endmenu =20 -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_B= EHAVIOR_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-truncatio= n, + 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 =20 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) +=3D scripts/Makefile.kasan include-$(CONFIG_KCSAN) +=3D scripts/Makefile.kcsan include-$(CONFIG_KMSAN) +=3D scripts/Makefile.kmsan include-$(CONFIG_UBSAN) +=3D scripts/Makefile.ubsan +include-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES) +=3D scripts/Makefile.obt include-$(CONFIG_KCOV) +=3D scripts/Makefile.kcov include-$(CONFIG_RANDSTRUCT) +=3D scripts/Makefile.randstruct include-$(CONFIG_KSTACK_ERASE) +=3D 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) +=3D 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) +=3D ../../include/generated/integer-w= rap.h +always-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES) +=3D ../../include/generated/inte= ger-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 +=3D $(if $(patsubst n%,, \ $(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SANITIZE)$(is-kernel-object)),= \ $(CFLAGS_UBSAN)) +endif + +ifeq ($(CONFIG_OVERFLOW_BEHAVIOR_TYPES),y) _c_flags +=3D $(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)$(i= s-kernel-object)), \ + $(CFLAGS_OVERFLOW_BEHAVIOR_TYPES)) endif =20 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 are= n't +# blindsided by compiler upgrades. +OVERFLOW_BEHAVIOR_TYPES_IGNORE_PATTERNS :=3D negated-unsigned-const,$\ + unsigned-post-decr-while,$\ + add-signed-overflow-test,$\ + add-unsigned-overflow-test + +OVERFLOW_BEHAVIOR_TYPES_SANITIZERS :=3D 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) +=3D \ + -DOVERFLOW_BEHAVIOR_TYPES \ + -Xclang -fexperimental-overflow-behavior-types \ + -fsanitize=3D$(OVERFLOW_BEHAVIOR_TYPES_SANITIZERS) \ + -fsanitize-undefined-ignore-overflow-pattern=3D$(OVERFLOW_BEHAVIOR_TYPES_= IGNORE_PATTERNS) \ + -fsanitize-ignorelist=3D$(srctree)/scripts/integer-wrap-ignore.scl \ + -Wno-incompatible-pointer-types-discards-overflow-behavior +overflow-behavior-types-cflags-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES_WARN) +=3D= \ + -fno-sanitize-trap=3D$(OVERFLOW_BEHAVIOR_TYPES_SANITIZERS) +overflow-behavior-types-cflags-$(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP) +=3D= \ + -fsanitize-trap=3D$(OVERFLOW_BEHAVIOR_TYPES_SANITIZERS) + +export CFLAGS_OVERFLOW_BEHAVIOR_TYPES :=3D $(overflow-behavior-types-cflag= s-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) +=3D -fsanitize=3Denum ubsan-cflags-$(CONFIG_UBSAN_TRAP) +=3D $(CFLAGS_UBSAN_TRAP) =20 export CFLAGS_UBSAN :=3D $(ubsan-cflags-y) - -ubsan-integer-wrap-cflags-$(CONFIG_UBSAN_INTEGER_WRAP) +=3D \ - -DINTEGER_WRAP \ - -fsanitize-undefined-ignore-overflow-pattern=3Dall \ - -fsanitize=3Dsigned-integer-overflow \ - -fsanitize=3Dunsigned-integer-overflow \ - -fsanitize=3Dimplicit-signed-integer-truncation \ - -fsanitize=3Dimplicit-unsigned-integer-truncation \ - -fsanitize-ignorelist=3D$(srctree)/scripts/integer-wrap-ignore.scl -export CFLAGS_UBSAN_INTEGER_WRAP :=3D $(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 +=3D $(call cc-option, -Wno-format-truncat= ion-non-kprintf) # because -Wuninitialized will still flag when an uninitialized const vari= able # is used. KBUILD_CFLAGS +=3D $(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 +=3D $(call cc-option, -Wno-overflow-behavior-attribute-igno= red) +endif + else =20 # 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-intege= r-truncation,implicit-unsigned-integer-truncation}] +[{unsigned-integer-overflow,signed-integer-overflow,implicit-signed-intege= r-truncation,implicit-unsigned-integer-truncation,implicit-integer-sign-cha= nge}] type:* -type:size_t=3Dsanitize diff --git a/include/linux/compiler-version.h b/include/linux/compiler-vers= ion.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 #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 #include #include +#include #include #include #ifndef COMPILE_OFFSETS @@ -1271,7 +1272,7 @@ struct task_struct { struct held_lock held_locks[MAX_LOCK_DEPTH]; #endif =20 -#if defined(CONFIG_UBSAN) && !defined(CONFIG_UBSAN_TRAP) +#ifdef NEED_SANITIZER_WARN_HANDLER unsigned int in_ubsan; #endif =20 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 =20 -#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 @@ =20 #include "ubsan.h" =20 -#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=3Dxxx 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_TYP= ES) /* * 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 */ =20 -#endif - -#ifndef CONFIG_UBSAN_TRAP +#ifdef NEED_SANITIZER_WARN_HANDLER static const char * const type_check_kinds[] =3D { "load of", "store to", @@ -558,4 +561,4 @@ void __ubsan_handle_alignment_assumption(void *_data, u= nsigned long ptr, } EXPORT_SYMBOL(__ubsan_handle_alignment_assumption); =20 -#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/ovt= i,ov2659.txt F: drivers/media/i2c/ov2659.c F: include/media/i2c/ov2659.h =20 +OVERFLOW BEHAVIOR TYPES +M: Kees Cook +M: Justin Stitt +L: linux-hardening@vger.kernel.org +S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-ne= xt/hardening +F: scripts/integer-wrap-ignore.scl +F: scripts/Makefile.obt + OVERLAY FILESYSTEM M: Miklos Szeredi M: Amir Goldstein diff --git a/kernel/configs/hardening.config b/kernel/configs/hardening.con= fig index 7c3924614e01..aabe28005a3d 100644 --- a/kernel/configs/hardening.config +++ b/kernel/configs/hardening.config @@ -46,7 +46,6 @@ CONFIG_UBSAN_BOUNDS=3Dy # 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 --=20 2.34.1 From nobody Wed Apr 1 09:05:44 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 772E7425CC4; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; cv=none; b=awZDuUsfKXGna8fIbJzEFPxbERcEgVZL8Lao3ksKtD3C5mMGlywwBwAaU2IVl1cgx2qQrIupVLi6xwBpH5bIqlqV9FquuzBGsyPXYdpnJ9Bm5NCDAd5nif/9/YI09M3Fuqhzaoro++SxZW/i2ww3vMKLou2PtJSq0R4MtkVJ72I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; c=relaxed/simple; bh=2ENkdacgL6qQ4CkwHQy9QBlqPlwlV1b5+fQmJvyLSq8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Mh8DHc1mmnUz/EQrurPfMiZcfpd9IOx3G3WIu8sV8SPfHq4mN+3vr53GGi/nvd71pp6XFLz6xB5+xJv5nZTf61pYKoYP4ijhIDhUiosD7KiqWppi+qDRQ6UnIC+CAs3Vlq0g4I5rL/PnNtH/kjEXz3mRwQmcbw1NROWmsb34rGs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TtvtmcGm; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TtvtmcGm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3CD50C2BCB5; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774975046; bh=2ENkdacgL6qQ4CkwHQy9QBlqPlwlV1b5+fQmJvyLSq8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TtvtmcGmS5l+peWR1ZnLkhj8TegDKN1jsEuFF+CClQTvBZvGCuwXXZslN5C71bQn1 Du/rBINbcqgLtqhBHYK+V/21I37qsopO0hCNVzjoz5qbeCMCE7cEoLik26Jo8ZqVVo YCIi0sK79jAU6xxBAueTu87BCGr950twhnbt9EjHf358252nUDDj79LRUZ0px28Hdw UYaoI0bF0FjnWckPLRPxvGhVcAtOG3IvLUW1AhvpZ/BbuQwIe2hHIIpU9NML+mmfKl EOv132QLa48ATqxc2x03asFg7ZQJzt0xAGpsPKxdsKdv7R6CSR+DorcbazmYkM5Opw 5Xv0fypQomxtw== From: Kees Cook To: Peter Zijlstra Cc: Kees Cook , Justin Stitt , Marco Elver , Andrey Konovalov , Andrey Ryabinin , Jonathan Corbet , Shuah Khan , Miguel Ojeda , Nathan Chancellor , kasan-dev@googlegroups.com, linux-doc@vger.kernel.org, llvm@lists.linux.dev, Linus Torvalds , Nicolas Schier , Arnd Bergmann , Greg Kroah-Hartman , Andrew Morton , linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, linux-kbuild@vger.kernel.org Subject: [PATCH 3/5] compiler_attributes: Add overflow_behavior macros __ob_trap and __ob_wrap Date: Tue, 31 Mar 2026 09:37:21 -0700 Message-Id: <20260331163725.2765789-3-kees@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260331163716.work.696-kees@kernel.org> References: <20260331163716.work.696-kees@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=18211; i=kees@kernel.org; h=from:subject; bh=/GZFvx+P9MNbVo6VGogk5CmI3c2mHRhKCUb448404GE=; b=owGbwMvMwCVmps19z/KJym7G02pJDJmnfzh6Zr6OD6y5E/7nWWV5dXHIvXQxhzlTsuSLrZUdV aYxnHnVUcrCIMbFICumyBJk5x7n4vG2Pdx9riLMHFYmkCEMXJwCMJHIG4wMJ9/KL0qKMexL33e/ vq6oxqF/jq5k7eJlUuxysuKC5qlbGBnalbpFO50kvxzek8/o4BMceJv/K+e9LV3H7227vaLDI4E RAA== X-Developer-Key: i=kees@kernel.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Justin Stitt When CONFIG_OVERFLOW_BEHAVIOR_TYPES=3Dy, Clang 23+'s Overflow Behavior Type[1] annotations are available (i.e. __ob_trap, __ob_wrap). When not enabled, these need to be empty macros. Document the new annotation and add links from sanitizer docs pointing to the arithmetic-overflow docs. Link: https://clang.llvm.org/docs/OverflowBehaviorTypes.html [1] Signed-off-by: Justin Stitt Co-developed-by: Kees Cook Signed-off-by: Kees Cook --- Cc: Marco Elver Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Jonathan Corbet Cc: Shuah Khan Cc: Miguel Ojeda Cc: Nathan Chancellor Cc: Cc: Cc: --- Documentation/dev-tools/ubsan.rst | 13 + Documentation/process/arithmetic-overflow.rst | 323 ++++++++++++++++++ Documentation/process/deprecated.rst | 39 +++ Documentation/process/index.rst | 1 + include/linux/compiler_attributes.h | 12 + MAINTAINERS | 1 + 6 files changed, 389 insertions(+) create mode 100644 Documentation/process/arithmetic-overflow.rst diff --git a/Documentation/dev-tools/ubsan.rst b/Documentation/dev-tools/ub= san.rst index e3591f8e9d5b..9e0c0f048eef 100644 --- a/Documentation/dev-tools/ubsan.rst +++ b/Documentation/dev-tools/ubsan.rst @@ -71,6 +71,19 @@ unaligned accesses (CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCE= SS=3Dy). One could still enable it in config, just note that it will produce a lot of UBSAN reports. =20 +Additional sanitizer options include:: + + CONFIG_OVERFLOW_BEHAVIOR_TYPES=3Dy + +This enables checking for integer arithmetic wrap-around (overflow/underfl= ow). +It instruments signed and unsigned integer overflow, as well as implicit +truncation operations. This option is currently limited to specific types +via the ``__ob_trap`` and ``__ob_wrap`` annotations. + +For detailed information about arithmetic overflow handling, overflow beha= vior +annotations, and best practices, see: +Documentation/process/arithmetic-overflow.rst + References ---------- =20 diff --git a/Documentation/process/arithmetic-overflow.rst b/Documentation/= process/arithmetic-overflow.rst new file mode 100644 index 000000000000..2f19990f189b --- /dev/null +++ b/Documentation/process/arithmetic-overflow.rst @@ -0,0 +1,323 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _arithmetic_overflow: + +Arithmetic Overflow Resolutions for Linux +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Background +---------- + +When a calculation's result exceeds the involved storage ranges, several +strategies can be followed to handle such an overflow (or underflow), +including: + + - Undefined (i.e. pretend it's impossible and the result depends on hard= ware) + - Wrap around (this is what 2s-complement representation does by default) + - Trap (create an exception so the problem can be handled in another way) + - Saturate (explicitly hold the maximum or minimum representable value) + +In the C standard, three basic types can be involved in arithmetic, and ea= ch +has a default strategy for solving the overflow problem: + + - Signed overflow is undefined + - Unsigned overflow explicitly wraps around + - Pointer overflow is undefined + +The Linux kernel uses ``-fno-strict-overflow`` which implies ``-fwrapv`` +and ``-fwrapv-pointer`` which treats signed integer overflow and pointer +overflow respectively as being consistent with two's complement. This flag +allows for consistency within the codebase about the expectations of +overflowing arithmetic as well as prevents eager compiler optimizations. +Note that :ref:`open-coded intentional arithmetic wrap-around is deprecate= d `. + +From here on, arithmetic overflow concerning signed, unsigned, or +pointer types will be referred to as "wrap-around" since it is the +default strategy for the kernel. There is no such thing as "undefined +behavior" for arithmetic in Linux: it always wraps. + +Overflow Behavior Types +----------------------- + +The newly available ``__ob_trap`` and ``__ob_wrap`` annotations provide +fine-grained control over overflow behavior. These can be applied to +integer types to unambiguously specify how arithmetic operations are +expected to behave upon overflow. Currently, only Clang supports these +annotations. The annotation defines two possible overflow behaviors: + +* ``wrap``: Ensures arithmetic operations wrap on overflow, providing + well-defined two's complement semantics according to the bitwidth of the + underlying type, regardless of any associated ``-fwrapv`` options or + sanitizers (integer overflow and truncation checks are suppressed) +* ``trap``: Enables overflow and truncation checking for the type, even wh= en + associated ``-fwrapv`` options are enabled. Without the sanitizer enabled + the compiler emits a trap instruction, otherwise the integer overflow + and truncation warnings are emitted but execution continues. + +Note that the sanitizer infrastructure is used for instrumentation shows +up in logs as the "Undefined Behavior" sanitizer (UBSan), which may be +confusing. Instead this should be thought of as the "Unexpected Behavior" +sanitizer. Its infrastructure is used to report on unexpected wrapping +behaviors: none of integer operations are "undefined" any more, as per +the use of ``-fno-strict-overflow``, but instead UBSan will kick in when +a type is explicitly marked as non-wrapping (i.e. trapping). + + +Enablement +~~~~~~~~~~ + +When supported by the compiler, kernels can build with either +``CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP=3Dy`` for trapping mode (i.e. +mitigation enabled), or ``CONFIG_OVERFLOW_BEHAVIOR_TYPES_WARN=3Dy`` which +enables warn-only mode, which logs the overflows but will continue as +if the type was not marked with ``__ob_trap``. + +Compiler Options +^^^^^^^^^^^^^^^^ + +Usage of the ``overflow_behavior`` attribute is gated behind the +``-fexperimental-overflow-behavior-types`` compiler flag which +is a ``-cc1`` flag, meaning the kernel passes it as ``-Xclang +-fexperimental-overflow-behavior-types``. + +Sanitizer Case Lists +^^^^^^^^^^^^^^^^^^^^ + +Linux uses a Sanitizer Case List file to selectively enable certain +sanitizers for specific types. Specifically, the overflow and truncation +sanitizers have had their standard instrumentation disabled for all +types. To "allowlist" specific types for instrumentation the kernel +makes use of the in-source ``__ob_trap`` annotations to gain reporting +by the sanitizers. + +Currently, type-based entries within a sanitizer case list are only +supported by Clang. For more information on the syntax for SCL files +refer to the Clang docs: +https://clang.llvm.org/docs/SanitizerSpecialCaseList.html + +Syntax +~~~~~~ + +Creating Overflow Behavior Types is possible via two syntactic forms; + +**Attribute syntax:** + +.. code-block:: c + + typedef unsigned int __attribute__((overflow_behavior(trap))) safe_uint; + typedef unsigned int __attribute__((overflow_behavior(wrap))) wrapping_u= int; + +**Keyword syntax:** + +.. code-block:: c + + typedef unsigned int __ob_trap safe_uint; + typedef unsigned int __ob_wrap wrapping_uint; + +Both forms are semantically identical. The keyword syntax is shorter and c= an +appear in the same positions as ``const`` or ``volatile``. The attribute s= yntax +is more self-documenting, so Linux uses this form. + +When ``-fexperimental-overflow-behavior-types`` is not enabled, both the +keywords (``__ob_wrap``, ``__ob_trap``) and the attribute are ignored with= a +warning. + +The feature can be queried with either +``__has_extension(overflow_behavior_types)`` or +``__has_attribute(overflow_behavior)``. + +Basic Usage +^^^^^^^^^^^ + +.. code-block:: c + + typedef unsigned int __ob_wrap counter_t; + typedef unsigned long __ob_trap safe_size_type; + + counter_t increment_counter(counter_t count) { + return count + 1; + } + + safe_size_type calculate_buffer_size(safe_size_type base, + safe_size_type extra) { + return base + extra; + } + +In the first function, arithmetic on ``counter_t`` is well-defined +wrapping. Its overflow will never be reported and unlike an plain +``unsigned int`` its purpose is unambiguous: it is expected to wrap +around. In the second function, arithmetic on ``safe_size_type`` is +checked -- overflow will result in a trap or sanitizer report depending +on the build configuration. + +Variables can be annotated directly: + +.. code-block:: c + + void foo(int num) { + int __ob_trap a =3D num; + a +=3D 42; + + unsigned char __ob_wrap b =3D 255; + b +=3D 10; + } + + +Interaction with Compiler Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Overflow behavior annotations override many global compiler flags and +sanitizer configurations: + +* ``wrap`` types suppress UBSan's integer overflow checks + (``signed-integer-overflow``, ``unsigned-integer-overflow``) and implicit + truncation checks (``implicit-signed-integer-truncation``, + ``implicit-unsigned-integer-truncation``). They also suppress ``-ftrapv`` + for the annotated type. +* ``trap`` types enable overflow checking even when ``-fwrapv`` + is globally enabled. When no sanitizer runtime is available, the compiler + emits a trap instruction directly. +* Both forms override Sanitizer Special Case List (SSCL) entries. + +Common overflow idioms are excluded from instrumentation via +``-fsanitize-undefined-ignore-overflow-pattern=3D``. These overflow idioms= have +their instrumentation withheld even under the presence of overflow behavior +annotations. For more details see: +https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#disabling-inst= rumentation-for-common-overflow-patterns + +Truncation Semantics +^^^^^^^^^^^^^^^^^^^^ + +Truncation and overflow are related -- both are often desirable in some +contexts and undesirable in others. Overflow behavior types control trunca= tion +instrumentation at the type level as well: + +* If a ``trap`` type is involved as source or destination of a truncation,= the + compiler inserts truncation checks. These will either trap or report via + sanitizer depending on the build configuration. +* If a ``wrap`` type is involved as source or destination, truncation chec= ks + are suppressed regardless of compiler flags. +* If both ``trap`` and ``wrap`` are involved in the same truncation, ``wra= p`` + takes precedence (truncation checks are suppressed) since the explicit + wrapping intent covers truncation as well. + +.. code-block:: c + + void checked(char a, int __ob_trap b) { + a =3D b; + } + + void wrapping(char a, int __ob_wrap b) { + a =3D b; + } + + +Promotion Rules +^^^^^^^^^^^^^^^ + +Overflow behavior types follow standard C integer promotion rules while +preserving the overflow behavior annotation through expressions: + +* When an overflow behavior type is mixed with a standard integer type, the + result carries the overflow behavior annotation. Standard C conversion r= ules + determine the resulting width and signedness. +* When two overflow behavior types of the same kind (both ``wrap`` or both + ``trap``) are mixed, the result follows standard C arithmetic conversion + rules with that behavior applied. +* When ``wrap`` and ``trap`` are mixed, ``trap`` dominates. The result fol= lows + standard C conversions with ``trap`` behavior. + +.. code-block:: c + + typedef int __ob_wrap wrap_int; + typedef int __ob_trap trap_int; + + wrap_int a =3D 1; + trap_int b =3D 2; + /* a + b results in __ob_trap int (trap dominates) */ + + +Type Compatibility +^^^^^^^^^^^^^^^^^^ + +Overflow behavior types are distinct from their underlying types for type +checking purposes. Assigning between types with different overflow behavio= rs +(``wrap`` vs ``trap``) is an error: + +.. code-block:: c + + int __ob_wrap w; + int __ob_trap t; + w =3D t; /* error: incompatible overflow behavior types */ + +Assigning from an overflow behavior type to a plain integer type discards = the +overflow behavior. The compiler can warn about this with +``-Wimplicit-overflow-behavior-conversion`` (implied by ``-Wconversion``). + +Intentionally discarding the overflow behavior should use an explicit +cast: + +.. code-block:: c + + unsigned long __ob_trap checked_size; + unsigned long regular_size; + + regular_size =3D checked_size; /* warning: discards overflow behavior */ + regular_size =3D (unsigned long)checked_size; /* OK, explicit cast */ + +If truncation should be allowed for a cast away from ``trap``, an +explicit ``wrap`` cast is needed to suppress run-time instrumentation: + +.. code-block:: c + + unsigned long __ob_trap checked_size; + unsigned char small_size; + + small_size =3D checked_size; /* may trap at run-time on truncation */ + small_size =3D (unsigned long __ob_wrap)checked_size; /* OK, explicit ca= st */ + + +Pointer Semantics +^^^^^^^^^^^^^^^^^ + +Pointers to overflow behavior types are treated as distinct from pointers = to +their underlying types. Converting between them produces a warning control= led +by ``-Wincompatible-pointer-types-discards-overflow-behavior``: + +.. code-block:: c + + unsigned long *px; + unsigned long __ob_trap *py; + + px =3D py; /* warning: discards overflow behavior */ + py =3D px; /* warning: discards overflow behavior */ + + +Best Practices +^^^^^^^^^^^^^^ + +1. **Use ``__ob_trap`` for sizes and counts** where overflow indicates bug= s: + + .. code-block:: c + + typedef unsigned long long __ob_trap no_wrap_u64; + no_wrap_u64 buffer_len =3D kmalloc_size + header_size; + +2. **Use ``__ob_wrap`` for arithmetic that intentionally overflows**: + + .. code-block:: c + + typedef u32 __ob_wrap hash_t; + hash_t hash =3D (hash * 31) + byte; + +3. **Don't mix different overflow behavior types**: + + .. code-block:: c + + int __ob_wrap a; + int __ob_trap b; + + a =3D b; /* error: incompatible overflow behavior types */ + + a =3D (int __ob_wrap)b; /* OK, explicit cast */ + a =3D (int)b; /* OK, cast to underlying type */ diff --git a/Documentation/process/deprecated.rst b/Documentation/process/d= eprecated.rst index fed56864d036..1c20f7ff0798 100644 --- a/Documentation/process/deprecated.rst +++ b/Documentation/process/deprecated.rst @@ -109,6 +109,45 @@ For more details, also see array3_size() and flex_arra= y_size(), as well as the related check_mul_overflow(), check_add_overflow(), check_sub_overflow(), and check_shl_overflow() family of functions. =20 +.. _open_coded_wrap_around: + +open-coded intentional arithmetic wrap-around +--------------------------------------------- +Depending on arithmetic wrap-around without annotations means the +kernel cannot distinguish between intentional wrap-around and accidental +wrap-around (when using things like the overflow sanitizers). + +For example, where an addition is intended to wrap around:: + + magic =3D counter + rotation; + +please use the wrapping_add() helper:: + + magic =3D wrapping_add(int, counter, rotation); + +To help minimize needless code churn, the kernel uses overflow idiom exclu= sions +(currently only supported by Clang). Some commonly used overflow-dependent= code +patterns will not be instrumented by overflow sanitizers. The currently +supported patterns are:: + + /* wrap-around test */ + if (var + offset < var) ... + + /* standalone unsigned decrement used in while loop */ + while(size--) + + /* negated unsigned constants */ + -1UL; + -5U; + +In rare cases where helpers aren't available (e.g. in early boot code, etc= ) but +overflow instrumentation still needs to be avoided, utilize wrap-around te= sts +to check wrap-around outcomes before performing calculations:: + + if (var + offset < var) { + /* wrap-around has occurred */ + } + simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull() ---------------------------------------------------------------------- The simple_strtol(), simple_strtoll(), diff --git a/Documentation/process/index.rst b/Documentation/process/index.= rst index dbd6ea16aca7..620257eca00e 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -111,3 +111,4 @@ developers: =20 kernel-docs deprecated + arithmetic-overflow diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_a= ttributes.h index c16d4199bf92..65f57ff378bb 100644 --- a/include/linux/compiler_attributes.h +++ b/include/linux/compiler_attributes.h @@ -396,6 +396,18 @@ # define __disable_sanitizer_instrumentation #endif =20 +/* + * Optional: only supported by Clang with -Xclang -experimental-foverflow-= behavior-types + * passed via CONFIG_OVERFLOW_BEHAVIOR_TYPES. When not available, define e= mpty macros for + * the trap/wrap annotations. + * + * clang: https://clang.llvm.org/docs/OverflowBehaviorTypes.html + */ +#if !__has_attribute(overflow_behavior) || !defined(OVERFLOW_BEHAVIOR_TYPE= S) +# define __ob_trap +# define __ob_wrap +#endif + /* * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.ht= ml#index-weak-function-attribute * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.ht= ml#index-weak-variable-attribute diff --git a/MAINTAINERS b/MAINTAINERS index a9f067164203..342a550c25b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19925,6 +19925,7 @@ M: Justin Stitt L: linux-hardening@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-ne= xt/hardening +F: Documentation/process/arithmetic-overflow.rst F: scripts/integer-wrap-ignore.scl F: scripts/Makefile.obt =20 --=20 2.34.1 From nobody Wed Apr 1 09:05:44 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 949BD425CEE; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; cv=none; b=By/hSEYB6VYz02j3v+XYzNuNHEvFlpFo+gWWZcEsHuglM89FLIJvCtpuAITxZPF2Ji0g0UdJZLvVlbhbSzMOFI+C5x+s33nzgKwN23WQ3+4RSZEK6sTVDKA97ELlLWZxYBiJwITNqgEsIXyfOuTwPXhYPMQP/J7jTToQEFajBFA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; c=relaxed/simple; bh=8ICpeLoyfF2BIMXBU7MfdBMil+QYa1a2pfcUa1hQh+c=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iKJ/wn3xL92dei7hodEkDRv91KsFkWBD8f/gtbu9bfsfqzqQXaJG8cg7dKv9EKbF4RYSVzSttqgJ414+tDR6N1TZyw2ELMJlLvjL40TGnDAh0bqQHC1RVFaU2WyOyzVXY42Lb/qxrXmtjnlA0vb7vSkNstT0evS0PGXtYm6jmcM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=o9I9T/0E; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="o9I9T/0E" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 512F7C2BCB1; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774975046; bh=8ICpeLoyfF2BIMXBU7MfdBMil+QYa1a2pfcUa1hQh+c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o9I9T/0EVFqYtlh0EtKMYzkcoKp4fU7mtqknM9yHsHq3gJeOBQD8xYQSkTns6xxrw GnPGvq1iti2AykrCx+ot7rXEpAPYD8Nl7zotOBjl9vNccYu+K/7r2tvK2H96bPrZ3e UDyvEs0bQM4wVBFxhH59HfJQD4YlZ2MjPI0s0YXs2YmCqXTNOqAYXKLlo6HleWhVqq aVJDM21YM3ihEA1mpjT1E5BVBCpyL07mSAjSHga2XJcivhelzHrF0mCLznCWzoqySZ LaWVnE8s1LfQ2QkGYqpAqRZoInX/lrB7/JzxWlcxVzBuPULzCV7xhPa8JkH8FiGJbO rQm4TnL0HXwPw== From: Kees Cook To: Peter Zijlstra Cc: Kees Cook , Arnd Bergmann , Greg Kroah-Hartman , Shuah Khan , linux-kselftest@vger.kernel.org, Justin Stitt , Linus Torvalds , Marco Elver , Jonathan Corbet , Nathan Chancellor , Nicolas Schier , Miguel Ojeda , Andrew Morton , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, linux-hardening@vger.kernel.org, linux-doc@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev Subject: [PATCH 4/5] lkdtm/bugs: Add basic Overflow Behavior Types test Date: Tue, 31 Mar 2026 09:37:22 -0700 Message-Id: <20260331163725.2765789-4-kees@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260331163716.work.696-kees@kernel.org> References: <20260331163716.work.696-kees@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10793; i=kees@kernel.org; h=from:subject; bh=8ICpeLoyfF2BIMXBU7MfdBMil+QYa1a2pfcUa1hQh+c=; b=owGbwMvMwCVmps19z/KJym7G02pJDJmnfzjVvF91Tmzp1mmz667KPNVp49U5pK3buvK+84c8J oPtD7ufdpSyMIhxMciKKbIE2bnHuXi8bQ93n6sIM4eVCWQIAxenAEzk7h1Ghkk/tZKWfDz+/6S3 9LUvv05kNkz7xqfz0eMTz9xbPwyLQ30Y/mcUf256m5izYz3rm8ApHLrvcr2fa055Elztsf4FV2R WCRcA X-Developer-Key: i=kees@kernel.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Exercise the end-to-end build and trap infrastructure in the kernel for __ob_trap, __ob_wrap, and associated sanitizer ignore patterns (i.e. idiom exclusions). Add a test for each of the basic overflow conditions under CONFIG_OVERFLOW_BEHAVIOR_TYPES=3Dy, as well as the corner cases associated with promotion, casting, etc. For example, executing this test with CONFIG_OVERFLOW_BEHAVIOR_TYPES_WARN= =3Dy (instead of CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP=3Dy), will show: $ echo OBT_ASSIGN_TRUNCATE_TO | cat >/sys/kernel/debug/provoke-crash/DI= RECT $ dmesg ... lkdtm: Performing direct entry OBT_ASSIGN_TRUNCATE_TO UBSAN: implicit-conversion in ../drivers/misc/lkdtm/bugs.c:825:10 cannot represent 'int' value 2147483647 during reference binding to 'u8= t' (aka '__ob_trap u8'), truncated to 255 Signed-off-by: Kees Cook --- Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: Shuah Khan Cc: --- drivers/misc/lkdtm/bugs.c | 253 ++++++++++++++++++++++++ tools/testing/selftests/lkdtm/tests.txt | 10 + 2 files changed, 263 insertions(+) diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index e0098f314570..f00c9099957e 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -817,6 +817,249 @@ static noinline void lkdtm_CORRUPT_PAC(void) #endif } =20 +static void lkdtm_OBT_ASSIGN_TRUNCATE_TO(void) +{ + volatile int big =3D INT_MAX; + volatile int wide_low_value =3D 5; + u8 __ob_trap narrow_low_value =3D 0; + s32 __ob_trap same =3D 0; + u8 __ob_trap small =3D 0; + + pr_info("Performing same-width assignment to OBT\n"); + same =3D big; + + pr_info("Performing small-value assignment to OBT\n"); + narrow_low_value =3D wide_low_value; + + pr_info("Expecting trap on truncated assignment to OBT\n"); + small =3D big; + + pr_err("FAIL: survived overflowing truncated assignment to OBT: %d -> %u = (ok: %d -> %u)\n", + same, small, wide_low_value, narrow_low_value); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_ASSIGN_TRUNCATE_FROM(void) +{ + volatile s32 __ob_trap big =3D INT_MAX; + volatile s32 __ob_trap wide_low_value =3D 5; + u8 narrow_low_value =3D 0; + s32 same =3D 0; + u8 small =3D 0; + + pr_info("Performing same-width assignment from OBT\n"); + same =3D big; + + pr_info("Performing small-value assignment from OBT\n"); + narrow_low_value =3D wide_low_value; + + pr_info("Expecting trap on truncated assignment from OBT\n"); + small =3D big; + + pr_err("FAIL: survived overflowing truncated assignment from OBT: %d -> %= u (ok: %d -> %u)\n", + same, small, wide_low_value, narrow_low_value); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_CAST_TRUNCATE(void) +{ + volatile u32 __ob_trap big =3D INT_MAX; + u32 trunc =3D 0; + u32 small =3D 0; + + pr_info("Performing wrapping too-small cast\n"); + trunc =3D (u16 __ob_wrap)big; + + pr_info("Expecting trap on too-small cast\n"); + small =3D (s16)big; + + pr_err("FAIL: survived truncated casting: %u -> %u (ok: %u -> %u)\n", + big, small, big, trunc); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_CAST_SIGNED(void) +{ + volatile u32 __ob_trap big =3D UINT_MAX; + s32 neg =3D 0; + s32 small =3D 0; + + pr_info("Performing explicit sign-changing cast\n"); + neg =3D (s32 __ob_wrap)big; + + pr_info("Expecting trap on unexpected sign-changing cast\n"); + small =3D (s32)big; + + pr_err("FAIL: survived lossy sign conversion: %u -> %d (forced: %u -> %d)= \n", + big, small, big, neg); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_MUL(void) +{ + /* Promotion means no overflow checking can happen. */ + volatile u8 __ob_trap a8 =3D 100; + volatile u8 __ob_trap b8 =3D 3; + unsigned int promoted; + /* 32-bit or larger, however, get checked. */ + volatile u32 __ob_trap a =3D UINT_MAX - 1; + volatile u32 __ob_trap b =3D 2; + unsigned long long happy; + unsigned long long outcome; + + /* Promotion means a * b happens as "int __ob_trap", so no trap. */ + pr_info("Performing promoted overflowing unsigned multiplication\n"); + promoted =3D a8 * b8; + + pr_info("Performing non-overflowing unsigned multiplication\n"); + happy =3D b * b; + + pr_info("Expecting trap on overflowing unsigned multiplication\n"); + outcome =3D a * b; + + pr_err("FAIL: survived unsigned multiplication overflow: %u * %u -> %llu = (ok: %u * %u -> %llu, %u)\n", + a, b, outcome, b, b, happy, promoted); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_MUL_SIGNED(void) +{ + /* Promotion means no overflow checking can happen. */ + volatile s8 __ob_trap a8 =3D 100; + volatile s8 __ob_trap b8 =3D 3; + int promoted; + /* 32-bit or larger, however, get checked. */ + volatile s32 __ob_trap a =3D INT_MAX - 1; + volatile s32 __ob_trap b =3D 2; + signed long long happy; + signed long long outcome; + + /* Promotion means a8 * b8 happens as "int __ob_trap", so no trap. */ + pr_info("Performing promoted overflowing signed multiplication\n"); + promoted =3D a8 * b8; + + pr_info("Performing non-overflowing signed multiplication\n"); + happy =3D b * b; + + pr_info("Expecting trap on overflowing signed multiplication\n"); + outcome =3D a * b; + + pr_err("FAIL: survived signed multiplication overflow: %d * %d -> %lld (o= k: %d * %d -> %lld, %d)\n", + a, b, outcome, b, b, happy, promoted); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_ADD(void) +{ + /* Promotion means no overflow checking can happen. */ + volatile u8 __ob_trap a8 =3D 250; + volatile u8 __ob_trap b8 =3D 30; + unsigned int promoted; + /* 32-bit or larger, however, get checked. */ + volatile u32 __ob_trap a =3D UINT_MAX - 1; + volatile u32 __ob_trap b =3D 2; + unsigned long long happy; + unsigned long long outcome; + + /* Promotion means a8 + b8 happens as "int __ob_trap", so no trap. */ + pr_info("Performing promoted overflowing unsigned addition\n"); + promoted =3D a8 + b8; + + pr_info("Performing idiomatic unsigned overflow addition test\n"); + if (a + b < a) { + /* Report status so test isn't elided by compiler. */ + pr_info("ok: overflow contained by conditional\n"); + } + + pr_info("Performing non-overflowing unsigned addition\n"); + happy =3D b + b; + + pr_info("Expecting trap on overflowing unsigned addition\n"); + outcome =3D a + b; + + pr_err("FAIL: survived unsigned addition overflow: %u + %u -> %llu (ok: %= u + %u -> %llu)\n", + a, b, outcome, b, b, happy); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_ADD_SIGNED(void) +{ + /* Promotion means no overflow checking can happen. */ + volatile s8 __ob_trap a8 =3D 120; + volatile s8 __ob_trap b8 =3D 30; + int promoted; + /* 32-bit or larger, however, get checked. */ + volatile s32 __ob_trap a =3D INT_MAX - 1; + volatile s32 __ob_trap b =3D 2; + signed long long happy; + signed long long outcome; + + /* Promotion means a8 + b8 happens as "int __ob_trap", so no trap. */ + pr_info("Performing promoted overflowing signed addition\n"); + promoted =3D a8 + b8; + + pr_info("Performing idiomatic signed overflow addition test\n"); + if (a + b < a) { + /* Report status so test isn't elided by compiler. */ + pr_info("ok: overflow contained by conditional\n"); + } + + pr_info("Performing non-overflowing signed addition\n"); + happy =3D b + b; + + pr_info("Expecting trap on overflowing signed addition\n"); + outcome =3D a + b; + + pr_err("FAIL: survived signed addition overflow: %u + %u -> %llu (ok: %u = + %u -> %llu)\n", + a, b, outcome, b, b, happy); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_NEGATED_UNSIGNED(void) +{ + volatile unsigned long __ob_trap value =3D 256; + size_t outcome; + + pr_info("Expecting trap on overflowing unsigned negation\n"); + outcome =3D value & -value; + + pr_err("FAIL: survived negated unsigned value: %lu -> %zu\n", + value, outcome); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + +static void lkdtm_OBT_POSTFIX_OPERATORS(void) +{ + volatile int target =3D 300; + volatile int flag =3D 0; + int i; + u8 __ob_wrap wrapper =3D 0; /* Explicitly wrapping. */ + u8 __ob_trap counter =3D 0; + + pr_info("Performing u8 __ob_wrap post-increment past 255\n"); + for (i =3D 0; i < target; i++) + wrapper++; + if (wrapper !=3D 44) + pr_err("FAIL: wrapped incorrecty: %u\n", wrapper); + + pr_info("Performing idiomatic post-decrement zero test\n"); + counter =3D target / 2; + while (counter--) + if (flag) + break; + if (counter !=3D 255) + pr_err("FAIL: u8 __ob_trap post-decrement zero-test did not wrap: %u\n", + counter); + + pr_info("Expecting trap on u8 __ob_trap post-increment past 255\n"); + counter =3D 0; + for (i =3D 0; i < target; i++) + counter++; + + pr_err("FAIL: survived overflowed post-increment: %u\n", counter); + pr_expected_config(CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP); +} + static struct crashtype crashtypes[] =3D { CRASHTYPE(PANIC), CRASHTYPE(PANIC_STOP_IRQOFF), @@ -850,6 +1093,16 @@ static struct crashtype crashtypes[] =3D { CRASHTYPE(UNSET_SMEP), CRASHTYPE(DOUBLE_FAULT), CRASHTYPE(CORRUPT_PAC), + CRASHTYPE(OBT_ASSIGN_TRUNCATE_TO), + CRASHTYPE(OBT_ASSIGN_TRUNCATE_FROM), + CRASHTYPE(OBT_CAST_TRUNCATE), + CRASHTYPE(OBT_CAST_SIGNED), + CRASHTYPE(OBT_MUL), + CRASHTYPE(OBT_MUL_SIGNED), + CRASHTYPE(OBT_ADD), + CRASHTYPE(OBT_ADD_SIGNED), + CRASHTYPE(OBT_NEGATED_UNSIGNED), + CRASHTYPE(OBT_POSTFIX_OPERATORS), }; =20 struct crashtype_category bugs_crashtypes =3D { diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selfte= sts/lkdtm/tests.txt index e62b85b591be..231299ba3959 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -87,3 +87,13 @@ FORTIFY_STR_MEMBER detected buffer overflow FORTIFY_MEM_OBJECT detected buffer overflow FORTIFY_MEM_MEMBER detected field-spanning write PPC_SLB_MULTIHIT Recovered +OBT_ASSIGN_TRUNCATE_TO traps: UBSAN: integer truncation +OBT_ASSIGN_TRUNCATE_FROM traps: UBSAN: integer truncation +OBT_CAST_TRUNCATE traps: UBSAN: integer truncation +OBT_CAST_SIGNED traps: UBSAN: integer truncation +OBT_MUL traps: UBSAN: integer multiplication overflow +OBT_MUL_SIGNED traps: UBSAN: integer multiplication overflow +OBT_ADD traps: UBSAN: integer addition overflow +OBT_ADD_SIGNED traps: UBSAN: integer addition overflow +OBT_NEGATED_UNSIGNED traps: UBSAN: negation overflow +OBT_POSTFIX_OPERATORS traps: UBSAN: integer truncation --=20 2.34.1 From nobody Wed Apr 1 09:05:44 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A5652426686; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; cv=none; b=PnbO255MRcW+aRP4ryirODdgsKypg/t2BycE/ZK6yRzO9tBcwQ0e3CqejguL//uEyT1nWX0jX3nwLwYXakZnRkObzYtR/qUfV0jFkLjIGeaO560HPDayFiuj4f5f916UtogMXt5tmEbZvbO4+xM3sSLWsoMiQywkZSy3KCSxTjM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774975046; c=relaxed/simple; bh=a4JG7usT6Z6N0Znenn9HJ2Ff5uUsHYvIsmUVVM1ha74=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=q3uNRHeQL6hciqVKt9AJQIHfRZgZ21+yHWFzpqTkcftt7qWRahBHkNTkvSmhz5eq6/QTDfTpSCG7A6A4yiRk2xwLeL5L9zK2JHKR5wbUgy2k4UOYqFhKBKWGkVyCu7DZm7XZMNXxvMq+PPGJowk4xn7o5tWYOywPpijfv84g9Eg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uqAi4pN1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uqAi4pN1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 721D1C4AF10; Tue, 31 Mar 2026 16:37:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774975046; bh=a4JG7usT6Z6N0Znenn9HJ2Ff5uUsHYvIsmUVVM1ha74=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uqAi4pN1Z8ucCsiUu+1eUEmYdhAcjaNzGIJbAW+vfqMgV8q3KsXOGzY9mWLYYBh4X ZQmhGSdJI0TaVO58Lqu8FphqRR/iCQuxsIEoFxRTMV10UPeK1QpZHaoQc6t4W1XQkq BFU35lt9z23/4W+IlSN/mxlZGuzkQtOetnlmjbx7J4KDGU1y1i09LU3wc+GH515fgH Ln57eaoQYAeAdygThC3LXzzmc3niIpq/H6kXByGfjh4w6u/KVwFJYl4klVEYZPDgNk SK8qHE5w7mFovWtXo0waaUNjsVuo8A08pE+SHHf1H908opsLv2laztVDYGj754m/W8 SQZuSHzyfBFTA== From: Kees Cook To: Peter Zijlstra Cc: Kees Cook , Justin Stitt , Linus Torvalds , Miguel Ojeda , Nathan Chancellor , Andrew Morton , Andy Shevchenko , Arnd Bergmann , Mark Rutland , "Matthew Wilcox (Oracle)" , Suren Baghdasaryan , Thomas Gleixner , Finn Thain , Geert Uytterhoeven , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , llvm@lists.linux.dev, Marco Elver , Jonathan Corbet , Nicolas Schier , Greg Kroah-Hartman , linux-kernel@vger.kernel.org, kasan-dev@googlegroups.com, linux-hardening@vger.kernel.org, linux-doc@vger.kernel.org, linux-kbuild@vger.kernel.org Subject: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types Date: Tue, 31 Mar 2026 09:37:23 -0700 Message-Id: <20260331163725.2765789-5-kees@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260331163716.work.696-kees@kernel.org> References: <20260331163716.work.696-kees@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Developer-Signature: v=1; a=openpgp-sha256; l=3375; i=kees@kernel.org; h=from:subject; bh=a4JG7usT6Z6N0Znenn9HJ2Ff5uUsHYvIsmUVVM1ha74=; b=owGbwMvMwCVmps19z/KJym7G02pJDJmnfzgZ57sa8O8X3MkZ/Vz6c6bB4oNsS4PMX3XHaUXdd 3ZlaXrbUcrCIMbFICumyBJk5x7n4vG2Pdx9riLMHFYmkCEMXJwCMBG3aEaGzeJcdxR3hV4+v/KV nrJlaC3f6y/mnHum/TX2kJ0qnP/oCcMfnoIja5QXO+2M6nzmfkX759RuaybtVE0Zge6GW/u+tpi xAAA= X-Developer-Key: i=kees@kernel.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 Content-Transfer-Encoding: quoted-printable While Linux's use of -fno-strict-overflow means that all arithmetic operations have a defined behavior (2's-complement wrapping), there isn't a way to unambiguously specify if a given variable was designed or intended to wrap around by the author. Introduce explicit trapping and wrapping types for all bit widths including architecture word length (i.e. "long"), signed and unsigned, for use going forward for unambiguous arithmetic, now available via Clang 23+'s Overflow Behavior Types[1] (CONFIG_OVERFLOW_BEHAVIOR_TYPES=3Dy). Bike shedding time! How should these be named? We already have the short bit width types, named as: {u,s}{8,16,32,64}. We need to construct new type names that also indicate their overflow behavior: "trapping" or "wrapping". And we need to capture the "architectural word" length type too (i.e. what "unsigned long" or "size_t" captures). Whole word addition: - Pro: Unambiguous - Con: Long. E.g. suffixed "u16_trap", or prefixed "wrap_u16" Single letter addition, "t" for "trap" and "w" for "wrap": - At the end: but "u8t" looks like the "t" is "type", like "uint8_t". - At the front: but "wu8" looks like the "w" is "wide", like "wchar_t". Current straw-man proposal is single letter suffix because it vaguely felt like the least bad of all choices, and they should be short or everyone will just continue to type "int". :) Link: https://clang.llvm.org/docs/OverflowBehaviorTypes.html [1] Signed-off-by: Kees Cook --- Cc: Justin Stitt Cc: Peter Zijlstra Cc: Linus Torvalds Cc: Miguel Ojeda Cc: Nathan Chancellor Cc: Andrew Morton Cc: Andy Shevchenko Cc: Arnd Bergmann Cc: Mark Rutland Cc: "Matthew Wilcox (Oracle)" Cc: Suren Baghdasaryan Cc: Thomas Gleixner Cc: Finn Thain Cc: Geert Uytterhoeven Cc: "Thomas Wei=C3=9Fschuh" Cc: --- include/linux/types.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/types.h b/include/linux/types.h index 7e71d260763c..786eb2c9775f 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -94,6 +94,30 @@ typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned long long ullong; =20 +/* Trapping types. */ +typedef u8 __ob_trap u8t; +typedef u16 __ob_trap u16t; +typedef u32 __ob_trap u32t; +typedef u64 __ob_trap u64t; +typedef unsigned long __ob_trap ulongt; +typedef s8 __ob_trap s8t; +typedef s16 __ob_trap s16t; +typedef s32 __ob_trap s32t; +typedef s64 __ob_trap s64t; +typedef signed long __ob_trap slongt; + +/* Wrapping types. */ +typedef u8 __ob_wrap u8w; +typedef u16 __ob_wrap u16w; +typedef u32 __ob_wrap u32w; +typedef u64 __ob_wrap u64w; +typedef unsigned long __ob_wrap ulongw; +typedef s8 __ob_wrap s8w; +typedef s16 __ob_wrap s16w; +typedef s32 __ob_wrap s32w; +typedef s64 __ob_wrap s64w; +typedef signed long __ob_wrap slongw; + #ifndef __BIT_TYPES_DEFINED__ #define __BIT_TYPES_DEFINED__ =20 --=20 2.34.1