Page MenuHomeFreeBSD

D12099.id32320.diff
No OneTemporary

D12099.id32320.diff

Index: share/man/man5/src.conf.5
===================================================================
--- share/man/man5/src.conf.5
+++ share/man/man5/src.conf.5
@@ -1509,6 +1509,10 @@
.It
.Va WITHOUT_LLDB
.El
+.It Va WITH_UBSAN
+Set to enable kernel undefined behaviour sanitization.
+.It Va WITH_UBSAN_SANITIZE_ALL
+Set to check all kernel source files for undefined behaviour.
.It Va WITHOUT_UNBOUND
Set to not build
.Xr unbound 8
Index: sys/conf/NOTES
===================================================================
--- sys/conf/NOTES
+++ sys/conf/NOTES
@@ -3031,3 +3031,6 @@
# Encrypted kernel crash dumps.
options EKCD
+
+# Kernel undefined behaviour sanitization
+options UBSAN
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3909,6 +3909,7 @@
libkern/strtouq.c standard
libkern/strvalid.c standard
libkern/timingsafe_bcmp.c standard
+libkern/ubsan.c optional ubsan
libkern/zlib.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | netgraph_deflate | ddb_ctf | gzio
net/altq/altq_cbq.c optional altq
Index: sys/conf/kern.pre.mk
===================================================================
--- sys/conf/kern.pre.mk
+++ sys/conf/kern.pre.mk
@@ -110,6 +110,16 @@
.endif
DEFINED_PROF= ${PROF}
+DISABLE_UBSAN= -fno-sanitize=undefined
+.if ${WITH_UBSAN} != "no"
+ENABLE_UBSAN= -fsanitize=undefined
+.if ${WITH_UBSAN_SANITIZE_ALL} != "no"
+CFLAGS+= ${ENABLE_UBSAN}
+.endif
+.else
+ENABLE_UBSAN=
+.endif
+
# Put configuration-specific C flags last (except for ${PROF}) so that they
# can override the others.
CFLAGS+= ${CONF_CFLAGS}
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -998,3 +998,5 @@
MMCCAM
# Encrypted kernel crash dumps
EKCD opt_ekcd.h
+
+UBSAN opt_ubsan.h
Index: sys/libkern/ubsan.c
===================================================================
--- /dev/null
+++ sys/libkern/ubsan.c
@@ -0,0 +1,398 @@
+/*-
+ * Copyright (c) 2017 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * As a reference, this code uses the software from the contrib/compiler-rt
+ * implementation of the userspace UBSAN runtime, which is developed as part
+ * of the LLVM project under the University of Illinois Open Source License.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <machine/atomic.h>
+
+enum type_kinds {
+ TK_INTEGER = 0x0000,
+ TK_FLOAT = 0x0001,
+ TK_UNKNOWN = 0xffff
+};
+
+struct type_descriptor {
+ uint16_t type_kind;
+ uint16_t type_info;
+ char type_name[1];
+};
+
+struct source_location {
+ char *filename;
+ uint32_t line;
+ uint32_t column;
+};
+
+struct overflow_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+};
+
+struct shift_out_of_bounds_data {
+ struct source_location loc;
+ struct type_descriptor *lhs_type;
+ struct type_descriptor *rhs_type;
+};
+
+struct out_of_bounds_data {
+ struct source_location loc;
+ struct type_descriptor *array_type;
+ struct type_descriptor *index_type;
+};
+
+struct non_null_return_data {
+ struct source_location attr_loc;
+};
+
+struct type_mismatch_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+ unsigned char log_alignment;
+ unsigned char type_check_kind;
+};
+
+struct vla_bound_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+};
+
+struct invalid_value_data {
+ struct source_location loc;
+ struct type_descriptor *type;
+};
+
+struct unreachable_data {
+ struct source_location loc;
+};
+
+const char *type_check_kinds[] = {
+ "load of", "store to", "reference binding to", "member access within",
+ "member call on", "constructor call on", "downcast of", "downcast of",
+ "upcast of", "cast to virtual base of", "_Nonnull binding to"
+};
+
+void __ubsan_handle_add_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs);
+
+void __ubsan_handle_sub_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs);
+
+void __ubsan_handle_mul_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs);
+
+void __ubsan_handle_divrem_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs);
+
+void __ubsan_handle_negate_overflow(struct overflow_data *data, uintptr_t old);
+
+void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
+ uintptr_t lhs, uintptr_t rhs);
+
+void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
+ uintptr_t index);
+
+void __ubsan_handle_nonnull_return(struct non_null_return_data *data,
+ struct source_location *loc);
+
+void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data *data,
+ uintptr_t ptr);
+
+void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
+ uintptr_t bound);
+
+void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
+ uintptr_t val);
+
+void __ubsan_handle_builtin_unreachable(struct unreachable_data *data);
+
+static unsigned
+bit_width(struct type_descriptor *type)
+{
+ return 1 << (type->type_info >> 1);
+}
+
+static int
+is_inline_int(struct type_descriptor *type)
+{
+ return bit_width(type) <= 8*sizeof(uintptr_t);
+}
+
+static int
+is_signed(struct type_descriptor *type)
+{
+ return type->type_info & 1;
+}
+
+static intmax_t
+signed_val(struct type_descriptor *type, uintptr_t val)
+{
+ if (is_inline_int(type)) {
+ unsigned extra_bits = 8*sizeof(intmax_t) - bit_width(type);
+ return (intmax_t)val << extra_bits >> extra_bits;
+ }
+ return *(intmax_t *)val;
+}
+
+static uintmax_t
+unsigned_val(struct type_descriptor *type, uintptr_t val)
+{
+ if (is_inline_int(type))
+ return val;
+ return *(uintmax_t *)val;
+}
+
+static void
+format_value(char *dest, size_t size, struct type_descriptor *type,
+ uintptr_t value)
+{
+ if (type->type_kind == TK_INTEGER) {
+ if (is_signed(type)) {
+ snprintf(dest, size, "%ld",
+ (int64_t)signed_val(type, value));
+ } else {
+ snprintf(dest, size, "%lu",
+ (uint64_t)unsigned_val(type, value));
+ }
+ } else {
+ snprintf(dest, size, "<unknown>");
+ }
+}
+
+static int
+ubsan_init(struct source_location *loc)
+{
+ uint32_t old_column;
+
+ old_column = atomic_swap_32(&loc->column, 0xffffffff);
+ if (old_column == 0xffffffff)
+ return 0;
+ printf("%s:%u:%u: runtime error: ", strrchr(loc->filename, '/') + 1,
+ loc->line, old_column);
+ return 1;
+}
+
+static void
+handle_overflow(struct overflow_data *data, uintptr_t lhs, const char *operator,
+ uintptr_t rhs)
+{
+ char lhs_str[20];
+ char rhs_str[20];
+ int data_signed;
+
+ if (!ubsan_init(&data->loc))
+ return;
+
+ data_signed = is_signed(data->type);
+ format_value(lhs_str, sizeof(lhs_str), data->type, lhs);
+ format_value(rhs_str, sizeof(rhs_str), data->type, rhs);
+
+ printf("%s integer overflow: %s %s %s cannot be represented"
+ "in type %s\n", data_signed ? "signed" : "unsigned", lhs_str,
+ operator, rhs_str, data->type->type_name);
+}
+
+void
+__ubsan_handle_add_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs)
+{
+ handle_overflow(data, lhs, "+", rhs);
+}
+
+void
+__ubsan_handle_sub_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs)
+{
+ handle_overflow(data, lhs, "-", rhs);
+}
+
+void
+__ubsan_handle_mul_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs)
+{
+ handle_overflow(data, lhs, "*", rhs);
+}
+
+void
+__ubsan_handle_divrem_overflow(struct overflow_data *data, uintptr_t lhs,
+ uintptr_t rhs)
+{
+ struct type_descriptor *type = data->type;
+
+ if (!ubsan_init(&data->loc))
+ return;
+
+ if (is_signed(type) && signed_val(type, rhs) == -1)
+ printf("division of %ld by -1 cannot be represented"
+ "in type %s\n", signed_val(data->type, lhs),
+ data->type->type_name);
+ else
+ printf("division by zero\n");
+}
+
+void
+__ubsan_handle_negate_overflow(struct overflow_data *data, uintptr_t old)
+{
+ struct type_descriptor *type = data->type;
+
+ if (!ubsan_init(&data->loc))
+ return;
+
+ if (is_signed(type))
+ printf("negation of %ld cannot be represented in type %s; "
+ "cast to an unsigned type to negate this value to itself\n",
+ signed_val(type, old), data->type->type_name);
+ else
+ printf("negation of %ld cannot be represented in type %s\n",
+ unsigned_val(type, old), data->type->type_name);
+}
+
+void
+__ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
+ uintptr_t lhs, uintptr_t rhs)
+{
+ if (!ubsan_init(&data->loc))
+ return;
+
+ if (is_signed(data->rhs_type) && signed_val(data->rhs_type, rhs) < 0) {
+ printf("shift exponent %ld is negative\n",
+ signed_val(data->rhs_type, rhs));
+ } else if (unsigned_val(data->rhs_type, rhs) >=
+ bit_width(data->lhs_type)) {
+ printf("shift exponent %lu is too large for %u-bit type %s\n",
+ unsigned_val(data->rhs_type, rhs),
+ bit_width(data->rhs_type), data->lhs_type->type_name);
+ } else if (is_signed(data->lhs_type) &&
+ signed_val(data->lhs_type, lhs) < 0) {
+ printf("left shift of negative value %ld\n",
+ signed_val(data->lhs_type, lhs));
+ } else {
+ printf("left shift of %lu by %lu places cannot be represented"
+ "in type %s\n", unsigned_val(data->lhs_type, lhs),
+ unsigned_val(data->rhs_type, rhs),
+ data->lhs_type->type_name);
+ }
+}
+
+void
+__ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, uintptr_t index)
+{
+ char index_str[20];
+
+ if (!ubsan_init(&data->loc))
+ return;
+
+ format_value(index_str, sizeof(index_str), data->index_type, index);
+ printf("index %s out of bounds for type %s\n",
+ index_str, data->array_type->type_name);
+}
+
+void
+__ubsan_handle_nonnull_return(struct non_null_return_data *data,
+ struct source_location *loc)
+{
+ struct source_location attr_loc = data->attr_loc;
+
+ if (!ubsan_init(loc))
+ return;
+
+ printf("null pointer returned from function declared"
+ "to never return null\n");
+ if (attr_loc.filename) {
+ printf("%s:%u:%u: note: returns_nonnull attribute"
+ "specified here\n", strrchr(attr_loc.filename, '/') + 1,
+ attr_loc.line, attr_loc.column);
+ }
+}
+
+void
+__ubsan_handle_type_mismatch_v1(struct type_mismatch_data *data, uintptr_t ptr)
+{
+ unsigned alignment;
+
+ if (!ubsan_init(&data->loc))
+ return;
+
+ alignment = 1 << data->log_alignment;
+ if (!ptr)
+ printf("%s null pointer of type %s\n",
+ type_check_kinds[data->type_check_kind],
+ data->type->type_name);
+ else if (ptr & (alignment - 1))
+ printf("%s misaligned address %p for type %s, "
+ "which requires %u byte alignment\n",
+ type_check_kinds[data->type_check_kind], (void *)ptr,
+ data->type->type_name, alignment);
+ else
+ printf("%s address %p with insufficient space "
+ "for an object of type %s\n",
+ type_check_kinds[data->type_check_kind], (void *)ptr,
+ data->type->type_name);
+}
+
+void
+__ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
+ uintptr_t bound)
+{
+ char bound_str[20];
+
+ if (!ubsan_init(&data->loc))
+ return;
+
+ format_value(bound_str, sizeof(bound_str), data->type, bound);
+ printf("variable length array bound evaluates"
+ "to non-positive value %s\n", bound_str);
+}
+
+void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
+ unsigned long val)
+{
+ char val_str[20];
+
+ if (!ubsan_init(&data->loc))
+ return;
+
+ format_value(val_str, sizeof(val_str), data->type, val);
+ printf("load of value %s, which is not a valid value for type %s\n",
+ val_str, data->type->type_name);
+}
+
+void
+__ubsan_handle_builtin_unreachable(struct unreachable_data *data)
+{
+ if (!ubsan_init(&data->loc))
+ return;
+
+ printf("execution reached a __builtin_unreachable() call\n");
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Oct 27, 7:19 PM (17 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24311320
Default Alt Text
D12099.id32320.diff (12 KB)

Event Timeline