ubsan: Tighten UBSAN_BOUNDS on GCC
authorKees Cook <keescook@chromium.org>
Wed, 5 Apr 2023 02:23:59 +0000 (19:23 -0700)
committerKees Cook <keescook@chromium.org>
Tue, 16 May 2023 20:57:14 +0000 (13:57 -0700)
The use of -fsanitize=bounds on GCC will ignore some trailing arrays,
leaving a gap in coverage. Switch to using -fsanitize=bounds-strict to
match Clang's stricter behavior.

Cc: Marco Elver <elver@google.com>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Nicolas Schier <nicolas@fjasle.eu>
Cc: Tom Rix <trix@redhat.com>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Miroslav Benes <mbenes@suse.cz>
Cc: linux-kbuild@vger.kernel.org
Cc: llvm@lists.linux.dev
Signed-off-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20230405022356.gonna.338-kees@kernel.org
lib/Kconfig.ubsan
scripts/Makefile.ubsan

index fd15230..65d8bbc 100644 (file)
@@ -27,16 +27,29 @@ config UBSAN_TRAP
          the system. For some system builders this is an acceptable
          trade-off.
 
-config CC_HAS_UBSAN_BOUNDS
-       def_bool $(cc-option,-fsanitize=bounds)
+config CC_HAS_UBSAN_BOUNDS_STRICT
+       def_bool $(cc-option,-fsanitize=bounds-strict)
+       help
+         The -fsanitize=bounds-strict option is only available on GCC,
+         but uses the more strict handling of arrays that includes knowledge
+         of flexible arrays, which is comparable to Clang's regular
+         -fsanitize=bounds.
 
 config CC_HAS_UBSAN_ARRAY_BOUNDS
        def_bool $(cc-option,-fsanitize=array-bounds)
+       help
+         Under Clang, the -fsanitize=bounds option is actually composed
+         of two more specific options, -fsanitize=array-bounds and
+         -fsanitize=local-bounds. However, -fsanitize=local-bounds can
+         only be used when trap mode is enabled. (See also the help for
+         CONFIG_LOCAL_BOUNDS.) Explicitly check for -fsanitize=array-bounds
+         so that we can build up the options needed for UBSAN_BOUNDS
+         with or without UBSAN_TRAP.
 
 config UBSAN_BOUNDS
        bool "Perform array index bounds checking"
        default UBSAN
-       depends on CC_HAS_UBSAN_ARRAY_BOUNDS || CC_HAS_UBSAN_BOUNDS
+       depends on CC_HAS_UBSAN_ARRAY_BOUNDS || CC_HAS_UBSAN_BOUNDS_STRICT
        help
          This option enables detection of directly indexed out of bounds
          array accesses, where the array size is known at compile time.
@@ -44,33 +57,26 @@ config UBSAN_BOUNDS
          to the {str,mem}*cpy() family of functions (that is addressed
          by CONFIG_FORTIFY_SOURCE).
 
-config UBSAN_ONLY_BOUNDS
-       def_bool CC_HAS_UBSAN_BOUNDS && !CC_HAS_UBSAN_ARRAY_BOUNDS
-       depends on UBSAN_BOUNDS
+config UBSAN_BOUNDS_STRICT
+       def_bool UBSAN_BOUNDS && CC_HAS_UBSAN_BOUNDS_STRICT
        help
-         This is a weird case: Clang's -fsanitize=bounds includes
-         -fsanitize=local-bounds, but it's trapping-only, so for
-         Clang, we must use -fsanitize=array-bounds when we want
-         traditional array bounds checking enabled. For GCC, we
-         want -fsanitize=bounds.
+         GCC's bounds sanitizer. This option is used to select the
+         correct options in Makefile.ubsan.
 
 config UBSAN_ARRAY_BOUNDS
-       def_bool CC_HAS_UBSAN_ARRAY_BOUNDS
-       depends on UBSAN_BOUNDS
+       def_bool UBSAN_BOUNDS && CC_HAS_UBSAN_ARRAY_BOUNDS
+       help
+         Clang's array bounds sanitizer. This option is used to select
+         the correct options in Makefile.ubsan.
 
 config UBSAN_LOCAL_BOUNDS
-       bool "Perform array local bounds checking"
-       depends on UBSAN_TRAP
-       depends on $(cc-option,-fsanitize=local-bounds)
-       help
-         This option enables -fsanitize=local-bounds which traps when an
-         exception/error is detected. Therefore, it may only be enabled
-         with CONFIG_UBSAN_TRAP.
-
-         Enabling this option detects errors due to accesses through a
-         pointer that is derived from an object of a statically-known size,
-         where an added offset (which may not be known statically) is
-         out-of-bounds.
+       def_bool UBSAN_ARRAY_BOUNDS && UBSAN_TRAP
+       help
+         This option enables Clang's -fsanitize=local-bounds which traps
+         when an access through a pointer that is derived from an object
+         of a statically-known size, where an added offset (which may not
+         be known statically) is out-of-bounds. Since this option is
+         trap-only, it depends on CONFIG_UBSAN_TRAP.
 
 config UBSAN_SHIFT
        bool "Perform checking for bit-shift overflows"
index 7099c60..4749865 100644 (file)
@@ -2,7 +2,7 @@
 
 # Enable available and selected UBSAN features.
 ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT)         += -fsanitize=alignment
-ubsan-cflags-$(CONFIG_UBSAN_ONLY_BOUNDS)       += -fsanitize=bounds
+ubsan-cflags-$(CONFIG_UBSAN_BOUNDS_STRICT)     += -fsanitize=bounds-strict
 ubsan-cflags-$(CONFIG_UBSAN_ARRAY_BOUNDS)      += -fsanitize=array-bounds
 ubsan-cflags-$(CONFIG_UBSAN_LOCAL_BOUNDS)      += -fsanitize=local-bounds
 ubsan-cflags-$(CONFIG_UBSAN_SHIFT)             += -fsanitize=shift