Commit c6d308534aef6c99904bf5862066360ae067abc4

Authored by Andrey Ryabinin
Committed by Linus Torvalds
1 parent 68920c9732

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>

Showing 17 changed files with 693 additions and 1 deletions Side-by-side Diff

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
... ... @@ -411,7 +411,7 @@
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,6 +784,7 @@
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
... ... @@ -31,6 +31,7 @@
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
arch/x86/boot/Makefile
... ... @@ -60,6 +60,7 @@
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  
arch/x86/boot/compressed/Makefile
... ... @@ -33,6 +33,7 @@
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
arch/x86/entry/vdso/Makefile
... ... @@ -4,6 +4,7 @@
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
arch/x86/realmode/rm/Makefile
... ... @@ -70,4 +70,5 @@
70 70 -I$(srctree)/arch/x86/boot
71 71 KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
72 72 GCOV_PROFILE := n
  73 +UBSAN_SANITIZE := n
drivers/firmware/efi/libstub/Makefile
... ... @@ -22,6 +22,7 @@
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  
include/linux/sched.h
... ... @@ -1643,6 +1643,9 @@
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;
... ... @@ -1893,6 +1893,8 @@
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  
  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.
... ... @@ -209,4 +209,7 @@
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
  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);
  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 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
scripts/Makefile.lib
... ... @@ -130,6 +130,12 @@
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  
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