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.
 
          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)
 
 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
 
 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.
        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).
 
          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
        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
 
 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
 
 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"
 
 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
 
 # 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
 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