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
next prev parent reply other threads:[~2026-03-31 16:37 UTC|newest]
Thread overview: 50+ 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-10 17:48 ` Justin Stitt
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.