public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <kees@kernel.org>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Kees Cook <kees@kernel.org>, Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Shuah Khan <shuah@kernel.org>,
	linux-kselftest@vger.kernel.org,
	Justin Stitt <justinstitt@google.com>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Marco Elver <elver@google.com>, Jonathan Corbet <corbet@lwn.net>,
	Nathan Chancellor <nathan@kernel.org>,
	Nicolas Schier <nsc@kernel.org>, Miguel Ojeda <ojeda@kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	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	[thread overview]
Message-ID: <20260331163725.2765789-4-kees@kernel.org> (raw)
In-Reply-To: <20260331163716.work.696-kees@kernel.org>

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=y, as well as the corner cases associated
with promotion, casting, etc.

For example, executing this test with CONFIG_OVERFLOW_BEHAVIOR_TYPES_WARN=y
(instead of CONFIG_OVERFLOW_BEHAVIOR_TYPES_TRAP=y), will show:

    $ echo OBT_ASSIGN_TRUNCATE_TO | cat >/sys/kernel/debug/provoke-crash/DIRECT
    $ 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 'u8t' (aka '__ob_trap u8'), truncated to 255

Signed-off-by: Kees Cook <kees@kernel.org>
---
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Shuah Khan <shuah@kernel.org>
Cc: <linux-kselftest@vger.kernel.org>
---
 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
 }
 
+static void lkdtm_OBT_ASSIGN_TRUNCATE_TO(void)
+{
+	volatile int big = INT_MAX;
+	volatile int wide_low_value = 5;
+	u8 __ob_trap narrow_low_value = 0;
+	s32 __ob_trap same = 0;
+	u8 __ob_trap small = 0;
+
+	pr_info("Performing same-width assignment to OBT\n");
+	same = big;
+
+	pr_info("Performing small-value assignment to OBT\n");
+	narrow_low_value = wide_low_value;
+
+	pr_info("Expecting trap on truncated assignment to OBT\n");
+	small = 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 = INT_MAX;
+	volatile s32 __ob_trap wide_low_value = 5;
+	u8 narrow_low_value = 0;
+	s32 same = 0;
+	u8 small = 0;
+
+	pr_info("Performing same-width assignment from OBT\n");
+	same = big;
+
+	pr_info("Performing small-value assignment from OBT\n");
+	narrow_low_value = wide_low_value;
+
+	pr_info("Expecting trap on truncated assignment from OBT\n");
+	small = 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 = INT_MAX;
+	u32 trunc = 0;
+	u32 small = 0;
+
+	pr_info("Performing wrapping too-small cast\n");
+	trunc = (u16 __ob_wrap)big;
+
+	pr_info("Expecting trap on too-small cast\n");
+	small = (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 = UINT_MAX;
+	s32 neg = 0;
+	s32 small = 0;
+
+	pr_info("Performing explicit sign-changing cast\n");
+	neg = (s32 __ob_wrap)big;
+
+	pr_info("Expecting trap on unexpected sign-changing cast\n");
+	small = (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 = 100;
+	volatile u8 __ob_trap b8 = 3;
+	unsigned int promoted;
+	/* 32-bit or larger, however, get checked. */
+	volatile u32 __ob_trap a = UINT_MAX - 1;
+	volatile u32 __ob_trap b = 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 = a8 * b8;
+
+	pr_info("Performing non-overflowing unsigned multiplication\n");
+	happy = b * b;
+
+	pr_info("Expecting trap on overflowing unsigned multiplication\n");
+	outcome = 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 = 100;
+	volatile s8 __ob_trap b8 = 3;
+	int promoted;
+	/* 32-bit or larger, however, get checked. */
+	volatile s32 __ob_trap a = INT_MAX - 1;
+	volatile s32 __ob_trap b = 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 = a8 * b8;
+
+	pr_info("Performing non-overflowing signed multiplication\n");
+	happy = b * b;
+
+	pr_info("Expecting trap on overflowing signed multiplication\n");
+	outcome = a * b;
+
+	pr_err("FAIL: survived signed multiplication overflow: %d * %d -> %lld (ok: %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 = 250;
+	volatile u8 __ob_trap b8 = 30;
+	unsigned int promoted;
+	/* 32-bit or larger, however, get checked. */
+	volatile u32 __ob_trap a = UINT_MAX - 1;
+	volatile u32 __ob_trap b = 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 = 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 = b + b;
+
+	pr_info("Expecting trap on overflowing unsigned addition\n");
+	outcome = 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 = 120;
+	volatile s8 __ob_trap b8 = 30;
+	int promoted;
+	/* 32-bit or larger, however, get checked. */
+	volatile s32 __ob_trap a = INT_MAX - 1;
+	volatile s32 __ob_trap b = 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 = 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 = b + b;
+
+	pr_info("Expecting trap on overflowing signed addition\n");
+	outcome = 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 = 256;
+	size_t outcome;
+
+	pr_info("Expecting trap on overflowing unsigned negation\n");
+	outcome = 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 = 300;
+	volatile int flag = 0;
+	int i;
+	u8 __ob_wrap wrapper = 0; /* Explicitly wrapping. */
+	u8 __ob_trap counter = 0;
+
+	pr_info("Performing u8 __ob_wrap post-increment past 255\n");
+	for (i = 0; i < target; i++)
+		wrapper++;
+	if (wrapper != 44)
+		pr_err("FAIL: wrapped incorrecty: %u\n", wrapper);
+
+	pr_info("Performing idiomatic post-decrement zero test\n");
+	counter = target / 2;
+	while (counter--)
+		if (flag)
+			break;
+	if (counter != 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 = 0;
+	for (i = 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[] = {
 	CRASHTYPE(PANIC),
 	CRASHTYPE(PANIC_STOP_IRQOFF),
@@ -850,6 +1093,16 @@ static struct crashtype crashtypes[] = {
 	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),
 };
 
 struct crashtype_category bugs_crashtypes = {
diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/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
-- 
2.34.1


  parent reply	other threads:[~2026-03-31 16:37 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-31 16:37 [PATCH 0/5] Introduce Overflow Behavior Types Kees Cook
2026-03-31 16:37 ` [PATCH 1/5] refcount: Remove unused __signed_wrap function annotations Kees Cook
2026-03-31 16:37 ` [PATCH 2/5] hardening: Introduce Overflow Behavior Types support Kees Cook
2026-03-31 16:37 ` [PATCH 3/5] compiler_attributes: Add overflow_behavior macros __ob_trap and __ob_wrap Kees Cook
2026-03-31 17:01   ` Miguel Ojeda
2026-03-31 17:09     ` Miguel Ojeda
2026-03-31 17:09     ` Justin Stitt
2026-03-31 17:14       ` Miguel Ojeda
2026-03-31 17:17         ` Justin Stitt
2026-03-31 19:52       ` Kees Cook
2026-04-01  9:08         ` Peter Zijlstra
2026-04-01 20:21           ` Kees Cook
2026-04-01 20:30             ` Peter Zijlstra
2026-04-01 20:55               ` Kees Cook
2026-04-01 23:42               ` Justin Stitt
2026-04-02  9:13             ` David Laight
2026-03-31 17:16   ` Linus Torvalds
2026-03-31 17:18     ` Linus Torvalds
2026-04-01  7:19   ` Vincent Mailhol
2026-04-01  9:20     ` Peter Zijlstra
2026-04-01 19:43       ` Kees Cook
2026-04-01 19:42     ` Kees Cook
2026-03-31 16:37 ` Kees Cook [this message]
2026-03-31 17:16   ` [PATCH 4/5] lkdtm/bugs: Add basic Overflow Behavior Types test Justin Stitt
2026-03-31 16:37 ` [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types Kees Cook
2026-03-31 17:10   ` Linus Torvalds
2026-03-31 17:47     ` Miguel Ojeda
2026-03-31 18:02       ` Linus Torvalds
2026-03-31 18:25         ` Linus Torvalds
2026-03-31 18:59           ` Kees Cook
2026-03-31 20:01             ` Linus Torvalds
2026-03-31 18:32         ` Kees Cook
2026-03-31 18:36           ` Linus Torvalds
2026-03-31 18:16       ` Kees Cook
2026-03-31 20:03     ` Kees Cook
2026-03-31 20:11       ` Linus Torvalds
2026-03-31 20:18         ` Linus Torvalds
2026-03-31 20:31         ` Kees Cook
2026-03-31 20:58           ` Linus Torvalds
2026-03-31 21:50             ` Justin Stitt
2026-03-31 23:49               ` Kees Cook
2026-03-31 23:50               ` Linus Torvalds
2026-04-01  8:31           ` Peter Zijlstra
2026-04-01 20:52             ` Kees Cook
2026-04-02  5:38               ` Peter Zijlstra
2026-04-01  8:57           ` Peter Zijlstra
2026-04-01 20:23             ` Kees Cook
2026-04-01  9:38           ` Peter Zijlstra
2026-04-01 21:41             ` Kees Cook

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260331163725.2765789-4-kees@kernel.org \
    --to=kees@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=corbet@lwn.net \
    --cc=elver@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=justinstitt@google.com \
    --cc=kasan-dev@googlegroups.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=nathan@kernel.org \
    --cc=nsc@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=peterz@infradead.org \
    --cc=shuah@kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox