Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133579745
D12099.id32303.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D12099.id32303.diff
View Options
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,366 @@
+#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
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 27, 7:19 PM (17 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24311321
Default Alt Text
D12099.id32303.diff (11 KB)
Attached To
Mode
D12099: Add minimal kernel runtime for UBSAN
Attached
Detach File
Event Timeline
Log In to Comment