Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

UBSAN: run-time undefined behavior sanity checker

UBSAN uses compile-time instrumentation to catch undefined behavior
(UB). Compiler inserts code that perform certain kinds of checks before
operations that could cause UB. If check fails (i.e. UB detected)
__ubsan_handle_* function called to print error message.

So the most of the work is done by compiler. This patch just implements
ubsan handlers printing errors.

GCC has this capability since 4.9.x [1] (see -fsanitize=undefined
option and its suboptions).
However GCC 5.x has more checkers implemented [2].
Article [3] has a bit more details about UBSAN in the GCC.

[1] - https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html
[2] - https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
[3] - http://developerblog.redhat.com/2014/10/16/gcc-undefined-behavior-sanitizer-ubsan/

Issues which UBSAN has found thus far are:

Found bugs:

* out-of-bounds access - 97840cb67ff5 ("netfilter: nfnetlink: fix
insufficient validation in nfnetlink_bind")

undefined shifts:

* d48458d4a768 ("jbd2: use a better hash function for the revoke
table")

* 10632008b9e1 ("clockevents: Prevent shift out of bounds")

* 'x << -1' shift in ext4 -
http://lkml.kernel.org/r/<5444EF21.8020501@samsung.com>

* undefined rol32(0) -
http://lkml.kernel.org/r/<1449198241-20654-1-git-send-email-sasha.levin@oracle.com>

* undefined dirty_ratelimit calculation -
http://lkml.kernel.org/r/<566594E2.3050306@odin.com>

* undefined roundown_pow_of_two(0) -
http://lkml.kernel.org/r/<1449156616-11474-1-git-send-email-sasha.levin@oracle.com>

* [WONTFIX] undefined shift in __bpf_prog_run -
http://lkml.kernel.org/r/<CACT4Y+ZxoR3UjLgcNdUm4fECLMx2VdtfrENMtRRCdgHB2n0bJA@mail.gmail.com>

WONTFIX here because it should be fixed in bpf program, not in kernel.

signed overflows:

* 32a8df4e0b33f ("sched: Fix odd values in effective_load()
calculations")

* mul overflow in ntp -
http://lkml.kernel.org/r/<1449175608-1146-1-git-send-email-sasha.levin@oracle.com>

* incorrect conversion into rtc_time in rtc_time64_to_tm() -
http://lkml.kernel.org/r/<1449187944-11730-1-git-send-email-sasha.levin@oracle.com>

* unvalidated timespec in io_getevents() -
http://lkml.kernel.org/r/<CACT4Y+bBxVYLQ6LtOKrKtnLthqLHcw-BMp3aqP3mjdAvr9FULQ@mail.gmail.com>

* [NOTABUG] signed overflow in ktime_add_safe() -
http://lkml.kernel.org/r/<CACT4Y+aJ4muRnWxsUe1CMnA6P8nooO33kwG-c8YZg=0Xc8rJqw@mail.gmail.com>

[akpm@linux-foundation.org: fix unused local warning]
[akpm@linux-foundation.org: fix __int128 build woes]
Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Michal Marek <mmarek@suse.cz>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Yury Gribov <y.gribov@samsung.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Kostya Serebryany <kcc@google.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andrey Ryabinin and committed by
Linus Torvalds
c6d30853 68920c97

+693 -1
+84
Documentation/ubsan.txt
··· 1 + Undefined Behavior Sanitizer - UBSAN 2 + 3 + Overview 4 + -------- 5 + 6 + UBSAN is a runtime undefined behaviour checker. 7 + 8 + UBSAN uses compile-time instrumentation to catch undefined behavior (UB). 9 + Compiler inserts code that perform certain kinds of checks before operations 10 + that may cause UB. If check fails (i.e. UB detected) __ubsan_handle_* 11 + function called to print error message. 12 + 13 + GCC has that feature since 4.9.x [1] (see -fsanitize=undefined option and 14 + its suboptions). GCC 5.x has more checkers implemented [2]. 15 + 16 + Report example 17 + --------------- 18 + 19 + ================================================================================ 20 + UBSAN: Undefined behaviour in ../include/linux/bitops.h:110:33 21 + shift exponent 32 is to large for 32-bit type 'unsigned int' 22 + CPU: 0 PID: 0 Comm: swapper Not tainted 4.4.0-rc1+ #26 23 + 0000000000000000 ffffffff82403cc8 ffffffff815e6cd6 0000000000000001 24 + ffffffff82403cf8 ffffffff82403ce0 ffffffff8163a5ed 0000000000000020 25 + ffffffff82403d78 ffffffff8163ac2b ffffffff815f0001 0000000000000002 26 + Call Trace: 27 + [<ffffffff815e6cd6>] dump_stack+0x45/0x5f 28 + [<ffffffff8163a5ed>] ubsan_epilogue+0xd/0x40 29 + [<ffffffff8163ac2b>] __ubsan_handle_shift_out_of_bounds+0xeb/0x130 30 + [<ffffffff815f0001>] ? radix_tree_gang_lookup_slot+0x51/0x150 31 + [<ffffffff8173c586>] _mix_pool_bytes+0x1e6/0x480 32 + [<ffffffff83105653>] ? dmi_walk_early+0x48/0x5c 33 + [<ffffffff8173c881>] add_device_randomness+0x61/0x130 34 + [<ffffffff83105b35>] ? dmi_save_one_device+0xaa/0xaa 35 + [<ffffffff83105653>] dmi_walk_early+0x48/0x5c 36 + [<ffffffff831066ae>] dmi_scan_machine+0x278/0x4b4 37 + [<ffffffff8111d58a>] ? vprintk_default+0x1a/0x20 38 + [<ffffffff830ad120>] ? early_idt_handler_array+0x120/0x120 39 + [<ffffffff830b2240>] setup_arch+0x405/0xc2c 40 + [<ffffffff830ad120>] ? early_idt_handler_array+0x120/0x120 41 + [<ffffffff830ae053>] start_kernel+0x83/0x49a 42 + [<ffffffff830ad120>] ? early_idt_handler_array+0x120/0x120 43 + [<ffffffff830ad386>] x86_64_start_reservations+0x2a/0x2c 44 + [<ffffffff830ad4f3>] x86_64_start_kernel+0x16b/0x17a 45 + ================================================================================ 46 + 47 + Usage 48 + ----- 49 + 50 + To enable UBSAN configure kernel with: 51 + 52 + CONFIG_UBSAN=y 53 + 54 + and to check the entire kernel: 55 + 56 + CONFIG_UBSAN_SANITIZE_ALL=y 57 + 58 + To enable instrumentation for specific files or directories, add a line 59 + similar to the following to the respective kernel Makefile: 60 + 61 + For a single file (e.g. main.o): 62 + UBSAN_SANITIZE_main.o := y 63 + 64 + For all files in one directory: 65 + UBSAN_SANITIZE := y 66 + 67 + To exclude files from being instrumented even if 68 + CONFIG_UBSAN_SANITIZE_ALL=y, use: 69 + 70 + UBSAN_SANITIZE_main.o := n 71 + and: 72 + UBSAN_SANITIZE := n 73 + 74 + Detection of unaligned accesses controlled through the separate option - 75 + CONFIG_UBSAN_ALIGNMENT. It's off by default on architectures that support 76 + unaligned accesses (CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y). One could 77 + still enable it in config, just note that it will produce a lot of UBSAN 78 + reports. 79 + 80 + References 81 + ---------- 82 + 83 + [1] - https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html 84 + [2] - https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
+2 -1
Makefile
··· 411 411 export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS 412 412 413 413 export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS 414 - export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN 414 + export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN CFLAGS_UBSAN 415 415 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE 416 416 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE 417 417 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL ··· 784 784 785 785 include scripts/Makefile.kasan 786 786 include scripts/Makefile.extrawarn 787 + include scripts/Makefile.ubsan 787 788 788 789 # Add any arch overrides and user supplied CPPFLAGS, AFLAGS and CFLAGS as the 789 790 # last assignments
+1
arch/x86/Kconfig
··· 31 31 select ARCH_HAS_PMEM_API if X86_64 32 32 select ARCH_HAS_MMIO_FLUSH 33 33 select ARCH_HAS_SG_CHAIN 34 + select ARCH_HAS_UBSAN_SANITIZE_ALL 34 35 select ARCH_HAVE_NMI_SAFE_CMPXCHG 35 36 select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI 36 37 select ARCH_MIGHT_HAVE_PC_PARPORT
+1
arch/x86/boot/Makefile
··· 60 60 KBUILD_CFLAGS := $(USERINCLUDE) $(REALMODE_CFLAGS) -D_SETUP 61 61 KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ 62 62 GCOV_PROFILE := n 63 + UBSAN_SANITIZE := n 63 64 64 65 $(obj)/bzImage: asflags-y := $(SVGA_MODE) 65 66
+1
arch/x86/boot/compressed/Makefile
··· 33 33 34 34 KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ 35 35 GCOV_PROFILE := n 36 + UBSAN_SANITIZE :=n 36 37 37 38 LDFLAGS := -m elf_$(UTS_MACHINE) 38 39 LDFLAGS_vmlinux := -T
+1
arch/x86/entry/vdso/Makefile
··· 4 4 5 5 KBUILD_CFLAGS += $(DISABLE_LTO) 6 6 KASAN_SANITIZE := n 7 + UBSAN_SANITIZE := n 7 8 8 9 VDSO64-$(CONFIG_X86_64) := y 9 10 VDSOX32-$(CONFIG_X86_X32_ABI) := y
+1
arch/x86/realmode/rm/Makefile
··· 70 70 -I$(srctree)/arch/x86/boot 71 71 KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ 72 72 GCOV_PROFILE := n 73 + UBSAN_SANITIZE := n
+1
drivers/firmware/efi/libstub/Makefile
··· 22 22 23 23 GCOV_PROFILE := n 24 24 KASAN_SANITIZE := n 25 + UBSAN_SANITIZE := n 25 26 26 27 lib-y := efi-stub-helper.o 27 28
+3
include/linux/sched.h
··· 1643 1643 struct held_lock held_locks[MAX_LOCK_DEPTH]; 1644 1644 gfp_t lockdep_reclaim_gfp; 1645 1645 #endif 1646 + #ifdef CONFIG_UBSAN 1647 + unsigned int in_ubsan; 1648 + #endif 1646 1649 1647 1650 /* journalling filesystem info */ 1648 1651 void *journal_info;
+2
lib/Kconfig.debug
··· 1893 1893 1894 1894 source "lib/Kconfig.kgdb" 1895 1895 1896 + source "lib/Kconfig.ubsan" 1897 + 1896 1898 config ARCH_HAS_DEVMEM_IS_ALLOWED 1897 1899 bool 1898 1900
+29
lib/Kconfig.ubsan
··· 1 + config ARCH_HAS_UBSAN_SANITIZE_ALL 2 + bool 3 + 4 + config UBSAN 5 + bool "Undefined behaviour sanity checker" 6 + help 7 + This option enables undefined behaviour sanity checker 8 + Compile-time instrumentation is used to detect various undefined 9 + behaviours in runtime. Various types of checks may be enabled 10 + via boot parameter ubsan_handle (see: Documentation/ubsan.txt). 11 + 12 + config UBSAN_SANITIZE_ALL 13 + bool "Enable instrumentation for the entire kernel" 14 + depends on UBSAN 15 + depends on ARCH_HAS_UBSAN_SANITIZE_ALL 16 + default y 17 + help 18 + This option activates instrumentation for the entire kernel. 19 + If you don't enable this option, you have to explicitly specify 20 + UBSAN_SANITIZE := y for the files/directories you want to check for UB. 21 + 22 + config UBSAN_ALIGNMENT 23 + bool "Enable checking of pointers alignment" 24 + depends on UBSAN 25 + default y if !HAVE_EFFICIENT_UNALIGNED_ACCESS 26 + help 27 + This option enables detection of unaligned memory accesses. 28 + Enabling this option on architectures that support unalligned 29 + accesses may produce a lot of false positives.
+3
lib/Makefile
··· 209 209 clean-files += oid_registry_data.c 210 210 211 211 obj-$(CONFIG_UCS2_STRING) += ucs2_string.o 212 + obj-$(CONFIG_UBSAN) += ubsan.o 213 + 214 + UBSAN_SANITIZE_ubsan.o := n
+456
lib/ubsan.c
··· 1 + /* 2 + * UBSAN error reporting functions 3 + * 4 + * Copyright (c) 2014 Samsung Electronics Co., Ltd. 5 + * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 11 + */ 12 + 13 + #include <linux/bitops.h> 14 + #include <linux/bug.h> 15 + #include <linux/ctype.h> 16 + #include <linux/init.h> 17 + #include <linux/kernel.h> 18 + #include <linux/types.h> 19 + #include <linux/sched.h> 20 + 21 + #include "ubsan.h" 22 + 23 + const char *type_check_kinds[] = { 24 + "load of", 25 + "store to", 26 + "reference binding to", 27 + "member access within", 28 + "member call on", 29 + "constructor call on", 30 + "downcast of", 31 + "downcast of" 32 + }; 33 + 34 + #define REPORTED_BIT 31 35 + 36 + #if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN) 37 + #define COLUMN_MASK (~(1U << REPORTED_BIT)) 38 + #define LINE_MASK (~0U) 39 + #else 40 + #define COLUMN_MASK (~0U) 41 + #define LINE_MASK (~(1U << REPORTED_BIT)) 42 + #endif 43 + 44 + #define VALUE_LENGTH 40 45 + 46 + static bool was_reported(struct source_location *location) 47 + { 48 + return test_and_set_bit(REPORTED_BIT, &location->reported); 49 + } 50 + 51 + static void print_source_location(const char *prefix, 52 + struct source_location *loc) 53 + { 54 + pr_err("%s %s:%d:%d\n", prefix, loc->file_name, 55 + loc->line & LINE_MASK, loc->column & COLUMN_MASK); 56 + } 57 + 58 + static bool suppress_report(struct source_location *loc) 59 + { 60 + return current->in_ubsan || was_reported(loc); 61 + } 62 + 63 + static bool type_is_int(struct type_descriptor *type) 64 + { 65 + return type->type_kind == type_kind_int; 66 + } 67 + 68 + static bool type_is_signed(struct type_descriptor *type) 69 + { 70 + WARN_ON(!type_is_int(type)); 71 + return type->type_info & 1; 72 + } 73 + 74 + static unsigned type_bit_width(struct type_descriptor *type) 75 + { 76 + return 1 << (type->type_info >> 1); 77 + } 78 + 79 + static bool is_inline_int(struct type_descriptor *type) 80 + { 81 + unsigned inline_bits = sizeof(unsigned long)*8; 82 + unsigned bits = type_bit_width(type); 83 + 84 + WARN_ON(!type_is_int(type)); 85 + 86 + return bits <= inline_bits; 87 + } 88 + 89 + static s_max get_signed_val(struct type_descriptor *type, unsigned long val) 90 + { 91 + if (is_inline_int(type)) { 92 + unsigned extra_bits = sizeof(s_max)*8 - type_bit_width(type); 93 + return ((s_max)val) << extra_bits >> extra_bits; 94 + } 95 + 96 + if (type_bit_width(type) == 64) 97 + return *(s64 *)val; 98 + 99 + return *(s_max *)val; 100 + } 101 + 102 + static bool val_is_negative(struct type_descriptor *type, unsigned long val) 103 + { 104 + return type_is_signed(type) && get_signed_val(type, val) < 0; 105 + } 106 + 107 + static u_max get_unsigned_val(struct type_descriptor *type, unsigned long val) 108 + { 109 + if (is_inline_int(type)) 110 + return val; 111 + 112 + if (type_bit_width(type) == 64) 113 + return *(u64 *)val; 114 + 115 + return *(u_max *)val; 116 + } 117 + 118 + static void val_to_string(char *str, size_t size, struct type_descriptor *type, 119 + unsigned long value) 120 + { 121 + if (type_is_int(type)) { 122 + if (type_bit_width(type) == 128) { 123 + #if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__) 124 + u_max val = get_unsigned_val(type, value); 125 + 126 + scnprintf(str, size, "0x%08x%08x%08x%08x", 127 + (u32)(val >> 96), 128 + (u32)(val >> 64), 129 + (u32)(val >> 32), 130 + (u32)(val)); 131 + #else 132 + WARN_ON(1); 133 + #endif 134 + } else if (type_is_signed(type)) { 135 + scnprintf(str, size, "%lld", 136 + (s64)get_signed_val(type, value)); 137 + } else { 138 + scnprintf(str, size, "%llu", 139 + (u64)get_unsigned_val(type, value)); 140 + } 141 + } 142 + } 143 + 144 + static bool location_is_valid(struct source_location *loc) 145 + { 146 + return loc->file_name != NULL; 147 + } 148 + 149 + static DEFINE_SPINLOCK(report_lock); 150 + 151 + static void ubsan_prologue(struct source_location *location, 152 + unsigned long *flags) 153 + { 154 + current->in_ubsan++; 155 + spin_lock_irqsave(&report_lock, *flags); 156 + 157 + pr_err("========================================" 158 + "========================================\n"); 159 + print_source_location("UBSAN: Undefined behaviour in", location); 160 + } 161 + 162 + static void ubsan_epilogue(unsigned long *flags) 163 + { 164 + dump_stack(); 165 + pr_err("========================================" 166 + "========================================\n"); 167 + spin_unlock_irqrestore(&report_lock, *flags); 168 + current->in_ubsan--; 169 + } 170 + 171 + static void handle_overflow(struct overflow_data *data, unsigned long lhs, 172 + unsigned long rhs, char op) 173 + { 174 + 175 + struct type_descriptor *type = data->type; 176 + unsigned long flags; 177 + char lhs_val_str[VALUE_LENGTH]; 178 + char rhs_val_str[VALUE_LENGTH]; 179 + 180 + if (suppress_report(&data->location)) 181 + return; 182 + 183 + ubsan_prologue(&data->location, &flags); 184 + 185 + val_to_string(lhs_val_str, sizeof(lhs_val_str), type, lhs); 186 + val_to_string(rhs_val_str, sizeof(rhs_val_str), type, rhs); 187 + pr_err("%s integer overflow:\n", 188 + type_is_signed(type) ? "signed" : "unsigned"); 189 + pr_err("%s %c %s cannot be represented in type %s\n", 190 + lhs_val_str, 191 + op, 192 + rhs_val_str, 193 + type->type_name); 194 + 195 + ubsan_epilogue(&flags); 196 + } 197 + 198 + void __ubsan_handle_add_overflow(struct overflow_data *data, 199 + unsigned long lhs, 200 + unsigned long rhs) 201 + { 202 + 203 + handle_overflow(data, lhs, rhs, '+'); 204 + } 205 + EXPORT_SYMBOL(__ubsan_handle_add_overflow); 206 + 207 + void __ubsan_handle_sub_overflow(struct overflow_data *data, 208 + unsigned long lhs, 209 + unsigned long rhs) 210 + { 211 + handle_overflow(data, lhs, rhs, '-'); 212 + } 213 + EXPORT_SYMBOL(__ubsan_handle_sub_overflow); 214 + 215 + void __ubsan_handle_mul_overflow(struct overflow_data *data, 216 + unsigned long lhs, 217 + unsigned long rhs) 218 + { 219 + handle_overflow(data, lhs, rhs, '*'); 220 + } 221 + EXPORT_SYMBOL(__ubsan_handle_mul_overflow); 222 + 223 + void __ubsan_handle_negate_overflow(struct overflow_data *data, 224 + unsigned long old_val) 225 + { 226 + unsigned long flags; 227 + char old_val_str[VALUE_LENGTH]; 228 + 229 + if (suppress_report(&data->location)) 230 + return; 231 + 232 + ubsan_prologue(&data->location, &flags); 233 + 234 + val_to_string(old_val_str, sizeof(old_val_str), data->type, old_val); 235 + 236 + pr_err("negation of %s cannot be represented in type %s:\n", 237 + old_val_str, data->type->type_name); 238 + 239 + ubsan_epilogue(&flags); 240 + } 241 + EXPORT_SYMBOL(__ubsan_handle_negate_overflow); 242 + 243 + 244 + void __ubsan_handle_divrem_overflow(struct overflow_data *data, 245 + unsigned long lhs, 246 + unsigned long rhs) 247 + { 248 + unsigned long flags; 249 + char rhs_val_str[VALUE_LENGTH]; 250 + 251 + if (suppress_report(&data->location)) 252 + return; 253 + 254 + ubsan_prologue(&data->location, &flags); 255 + 256 + val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs); 257 + 258 + if (type_is_signed(data->type) && get_signed_val(data->type, rhs) == -1) 259 + pr_err("division of %s by -1 cannot be represented in type %s\n", 260 + rhs_val_str, data->type->type_name); 261 + else 262 + pr_err("division by zero\n"); 263 + 264 + ubsan_epilogue(&flags); 265 + } 266 + EXPORT_SYMBOL(__ubsan_handle_divrem_overflow); 267 + 268 + static void handle_null_ptr_deref(struct type_mismatch_data *data) 269 + { 270 + unsigned long flags; 271 + 272 + if (suppress_report(&data->location)) 273 + return; 274 + 275 + ubsan_prologue(&data->location, &flags); 276 + 277 + pr_err("%s null pointer of type %s\n", 278 + type_check_kinds[data->type_check_kind], 279 + data->type->type_name); 280 + 281 + ubsan_epilogue(&flags); 282 + } 283 + 284 + static void handle_missaligned_access(struct type_mismatch_data *data, 285 + unsigned long ptr) 286 + { 287 + unsigned long flags; 288 + 289 + if (suppress_report(&data->location)) 290 + return; 291 + 292 + ubsan_prologue(&data->location, &flags); 293 + 294 + pr_err("%s misaligned address %p for type %s\n", 295 + type_check_kinds[data->type_check_kind], 296 + (void *)ptr, data->type->type_name); 297 + pr_err("which requires %ld byte alignment\n", data->alignment); 298 + 299 + ubsan_epilogue(&flags); 300 + } 301 + 302 + static void handle_object_size_mismatch(struct type_mismatch_data *data, 303 + unsigned long ptr) 304 + { 305 + unsigned long flags; 306 + 307 + if (suppress_report(&data->location)) 308 + return; 309 + 310 + ubsan_prologue(&data->location, &flags); 311 + pr_err("%s address %pk with insufficient space\n", 312 + type_check_kinds[data->type_check_kind], 313 + (void *) ptr); 314 + pr_err("for an object of type %s\n", data->type->type_name); 315 + ubsan_epilogue(&flags); 316 + } 317 + 318 + void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, 319 + unsigned long ptr) 320 + { 321 + 322 + if (!ptr) 323 + handle_null_ptr_deref(data); 324 + else if (data->alignment && !IS_ALIGNED(ptr, data->alignment)) 325 + handle_missaligned_access(data, ptr); 326 + else 327 + handle_object_size_mismatch(data, ptr); 328 + } 329 + EXPORT_SYMBOL(__ubsan_handle_type_mismatch); 330 + 331 + void __ubsan_handle_nonnull_return(struct nonnull_return_data *data) 332 + { 333 + unsigned long flags; 334 + 335 + if (suppress_report(&data->location)) 336 + return; 337 + 338 + ubsan_prologue(&data->location, &flags); 339 + 340 + pr_err("null pointer returned from function declared to never return null\n"); 341 + 342 + if (location_is_valid(&data->attr_location)) 343 + print_source_location("returns_nonnull attribute specified in", 344 + &data->attr_location); 345 + 346 + ubsan_epilogue(&flags); 347 + } 348 + EXPORT_SYMBOL(__ubsan_handle_nonnull_return); 349 + 350 + void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data, 351 + unsigned long bound) 352 + { 353 + unsigned long flags; 354 + char bound_str[VALUE_LENGTH]; 355 + 356 + if (suppress_report(&data->location)) 357 + return; 358 + 359 + ubsan_prologue(&data->location, &flags); 360 + 361 + val_to_string(bound_str, sizeof(bound_str), data->type, bound); 362 + pr_err("variable length array bound value %s <= 0\n", bound_str); 363 + 364 + ubsan_epilogue(&flags); 365 + } 366 + EXPORT_SYMBOL(__ubsan_handle_vla_bound_not_positive); 367 + 368 + void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, 369 + unsigned long index) 370 + { 371 + unsigned long flags; 372 + char index_str[VALUE_LENGTH]; 373 + 374 + if (suppress_report(&data->location)) 375 + return; 376 + 377 + ubsan_prologue(&data->location, &flags); 378 + 379 + val_to_string(index_str, sizeof(index_str), data->index_type, index); 380 + pr_err("index %s is out of range for type %s\n", index_str, 381 + data->array_type->type_name); 382 + ubsan_epilogue(&flags); 383 + } 384 + EXPORT_SYMBOL(__ubsan_handle_out_of_bounds); 385 + 386 + void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data, 387 + unsigned long lhs, unsigned long rhs) 388 + { 389 + unsigned long flags; 390 + struct type_descriptor *rhs_type = data->rhs_type; 391 + struct type_descriptor *lhs_type = data->lhs_type; 392 + char rhs_str[VALUE_LENGTH]; 393 + char lhs_str[VALUE_LENGTH]; 394 + 395 + if (suppress_report(&data->location)) 396 + return; 397 + 398 + ubsan_prologue(&data->location, &flags); 399 + 400 + val_to_string(rhs_str, sizeof(rhs_str), rhs_type, rhs); 401 + val_to_string(lhs_str, sizeof(lhs_str), lhs_type, lhs); 402 + 403 + if (val_is_negative(rhs_type, rhs)) 404 + pr_err("shift exponent %s is negative\n", rhs_str); 405 + 406 + else if (get_unsigned_val(rhs_type, rhs) >= 407 + type_bit_width(lhs_type)) 408 + pr_err("shift exponent %s is too large for %u-bit type %s\n", 409 + rhs_str, 410 + type_bit_width(lhs_type), 411 + lhs_type->type_name); 412 + else if (val_is_negative(lhs_type, lhs)) 413 + pr_err("left shift of negative value %s\n", 414 + lhs_str); 415 + else 416 + pr_err("left shift of %s by %s places cannot be" 417 + " represented in type %s\n", 418 + lhs_str, rhs_str, 419 + lhs_type->type_name); 420 + 421 + ubsan_epilogue(&flags); 422 + } 423 + EXPORT_SYMBOL(__ubsan_handle_shift_out_of_bounds); 424 + 425 + 426 + void __noreturn 427 + __ubsan_handle_builtin_unreachable(struct unreachable_data *data) 428 + { 429 + unsigned long flags; 430 + 431 + ubsan_prologue(&data->location, &flags); 432 + pr_err("calling __builtin_unreachable()\n"); 433 + ubsan_epilogue(&flags); 434 + panic("can't return from __builtin_unreachable()"); 435 + } 436 + EXPORT_SYMBOL(__ubsan_handle_builtin_unreachable); 437 + 438 + void __ubsan_handle_load_invalid_value(struct invalid_value_data *data, 439 + unsigned long val) 440 + { 441 + unsigned long flags; 442 + char val_str[VALUE_LENGTH]; 443 + 444 + if (suppress_report(&data->location)) 445 + return; 446 + 447 + ubsan_prologue(&data->location, &flags); 448 + 449 + val_to_string(val_str, sizeof(val_str), data->type, val); 450 + 451 + pr_err("load of value %s is not a valid value for type %s\n", 452 + val_str, data->type->type_name); 453 + 454 + ubsan_epilogue(&flags); 455 + } 456 + EXPORT_SYMBOL(__ubsan_handle_load_invalid_value);
+84
lib/ubsan.h
··· 1 + #ifndef _LIB_UBSAN_H 2 + #define _LIB_UBSAN_H 3 + 4 + enum { 5 + type_kind_int = 0, 6 + type_kind_float = 1, 7 + type_unknown = 0xffff 8 + }; 9 + 10 + struct type_descriptor { 11 + u16 type_kind; 12 + u16 type_info; 13 + char type_name[1]; 14 + }; 15 + 16 + struct source_location { 17 + const char *file_name; 18 + union { 19 + unsigned long reported; 20 + struct { 21 + u32 line; 22 + u32 column; 23 + }; 24 + }; 25 + }; 26 + 27 + struct overflow_data { 28 + struct source_location location; 29 + struct type_descriptor *type; 30 + }; 31 + 32 + struct type_mismatch_data { 33 + struct source_location location; 34 + struct type_descriptor *type; 35 + unsigned long alignment; 36 + unsigned char type_check_kind; 37 + }; 38 + 39 + struct nonnull_arg_data { 40 + struct source_location location; 41 + struct source_location attr_location; 42 + int arg_index; 43 + }; 44 + 45 + struct nonnull_return_data { 46 + struct source_location location; 47 + struct source_location attr_location; 48 + }; 49 + 50 + struct vla_bound_data { 51 + struct source_location location; 52 + struct type_descriptor *type; 53 + }; 54 + 55 + struct out_of_bounds_data { 56 + struct source_location location; 57 + struct type_descriptor *array_type; 58 + struct type_descriptor *index_type; 59 + }; 60 + 61 + struct shift_out_of_bounds_data { 62 + struct source_location location; 63 + struct type_descriptor *lhs_type; 64 + struct type_descriptor *rhs_type; 65 + }; 66 + 67 + struct unreachable_data { 68 + struct source_location location; 69 + }; 70 + 71 + struct invalid_value_data { 72 + struct source_location location; 73 + struct type_descriptor *type; 74 + }; 75 + 76 + #if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__) 77 + typedef __int128 s_max; 78 + typedef unsigned __int128 u_max; 79 + #else 80 + typedef s64 s_max; 81 + typedef u64 u_max; 82 + #endif 83 + 84 + #endif
+1
mm/kasan/Makefile
··· 1 1 KASAN_SANITIZE := n 2 + UBSAN_SANITIZE_kasan.o := n 2 3 3 4 CFLAGS_REMOVE_kasan.o = -pg 4 5 # Function splitter causes unnecessary splits in __asan_load1/__asan_store1
+6
scripts/Makefile.lib
··· 130 130 $(CFLAGS_KASAN)) 131 131 endif 132 132 133 + ifeq ($(CONFIG_UBSAN),y) 134 + _c_flags += $(if $(patsubst n%,, \ 135 + $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \ 136 + $(CFLAGS_UBSAN)) 137 + endif 138 + 133 139 # If building the kernel in a separate objtree expand all occurrences 134 140 # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). 135 141
+17
scripts/Makefile.ubsan
··· 1 + ifdef CONFIG_UBSAN 2 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=shift) 3 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=integer-divide-by-zero) 4 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=unreachable) 5 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=vla-bound) 6 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=null) 7 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=signed-integer-overflow) 8 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=bounds) 9 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=object-size) 10 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=returns-nonnull-attribute) 11 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=bool) 12 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=enum) 13 + 14 + ifdef CONFIG_UBSAN_ALIGNMENT 15 + CFLAGS_UBSAN += $(call cc-option, -fsanitize=alignment) 16 + endif 17 + endif