Serenity Operating System
1/*
2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Format.h>
8#include <AK/UBSanitizer.h>
9#include <Kernel/Arch/Processor.h>
10#include <Kernel/KSyms.h>
11
12using namespace Kernel;
13using namespace AK::UBSanitizer;
14
15Atomic<bool> AK::UBSanitizer::g_ubsan_is_deadly { true };
16
17extern "C" {
18
19static void print_location(SourceLocation const& location)
20{
21 if (!location.filename())
22 critical_dmesgln("KUBSAN: in unknown file");
23 else
24 critical_dmesgln("KUBSAN: at {}, line {}, column: {}", location.filename(), location.line(), location.column());
25 dump_backtrace(g_ubsan_is_deadly ? PrintToScreen::Yes : PrintToScreen::No);
26 if (g_ubsan_is_deadly) {
27 critical_dmesgln("UB is configured to be deadly, halting the system.");
28 Processor::halt();
29 }
30}
31
32void __ubsan_handle_load_invalid_value(InvalidValueData const&, ValueHandle) __attribute__((used));
33void __ubsan_handle_load_invalid_value(InvalidValueData const& data, ValueHandle)
34{
35 critical_dmesgln("KUBSAN: load-invalid-value: {} ({}-bit)", data.type.name(), data.type.bit_width());
36 print_location(data.location);
37}
38
39void __ubsan_handle_nonnull_arg(NonnullArgData const&) __attribute__((used));
40void __ubsan_handle_nonnull_arg(NonnullArgData const& data)
41{
42 critical_dmesgln("KUBSAN: null pointer passed as argument {}, which is declared to never be null", data.argument_index);
43 print_location(data.location);
44}
45
46void __ubsan_handle_nullability_arg(NonnullArgData const&) __attribute__((used));
47void __ubsan_handle_nullability_arg(NonnullArgData const& data)
48{
49 critical_dmesgln("KUBSAN: null pointer passed as argument {}, which is declared to never be null", data.argument_index);
50 print_location(data.location);
51}
52
53void __ubsan_handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation const&) __attribute__((used));
54void __ubsan_handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation const& location)
55{
56 critical_dmesgln("KUBSAN: null pointer return from function declared to never return null");
57 print_location(location);
58}
59
60void __ubsan_handle_nullability_return_v1(NonnullReturnData const& data, SourceLocation const& location) __attribute__((used));
61void __ubsan_handle_nullability_return_v1(NonnullReturnData const&, SourceLocation const& location)
62{
63 critical_dmesgln("KUBSAN: null pointer return from function declared to never return null");
64 print_location(location);
65}
66
67void __ubsan_handle_vla_bound_not_positive(VLABoundData const&, ValueHandle) __attribute__((used));
68void __ubsan_handle_vla_bound_not_positive(VLABoundData const& data, ValueHandle)
69{
70 critical_dmesgln("KUBSAN: VLA bound not positive {} ({}-bit)", data.type.name(), data.type.bit_width());
71 print_location(data.location);
72}
73
74void __ubsan_handle_add_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
75void __ubsan_handle_add_overflow(OverflowData const& data, ValueHandle, ValueHandle)
76{
77 critical_dmesgln("KUBSAN: addition overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
78
79 print_location(data.location);
80}
81
82void __ubsan_handle_sub_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
83void __ubsan_handle_sub_overflow(OverflowData const& data, ValueHandle, ValueHandle)
84{
85 critical_dmesgln("KUBSAN: subtraction overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
86
87 print_location(data.location);
88}
89
90void __ubsan_handle_negate_overflow(OverflowData const&, ValueHandle) __attribute__((used));
91void __ubsan_handle_negate_overflow(OverflowData const& data, ValueHandle)
92{
93 critical_dmesgln("KUBSAN: negation overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
94
95 print_location(data.location);
96}
97
98void __ubsan_handle_mul_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
99void __ubsan_handle_mul_overflow(OverflowData const& data, ValueHandle, ValueHandle)
100{
101 critical_dmesgln("KUBSAN: multiplication overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
102 print_location(data.location);
103}
104
105void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
106void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData const& data, ValueHandle, ValueHandle)
107{
108 critical_dmesgln("KUBSAN: shift out of bounds, {} ({}-bit) shifted by {} ({}-bit)", data.lhs_type.name(), data.lhs_type.bit_width(), data.rhs_type.name(), data.rhs_type.bit_width());
109 print_location(data.location);
110}
111
112void __ubsan_handle_divrem_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
113void __ubsan_handle_divrem_overflow(OverflowData const& data, ValueHandle, ValueHandle)
114{
115 critical_dmesgln("KUBSAN: divrem overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
116 print_location(data.location);
117}
118
119void __ubsan_handle_out_of_bounds(OutOfBoundsData const&, ValueHandle) __attribute__((used));
120void __ubsan_handle_out_of_bounds(OutOfBoundsData const& data, ValueHandle)
121{
122 critical_dmesgln("KUBSAN: out of bounds access into array of {} ({}-bit), index type {} ({}-bit)", data.array_type.name(), data.array_type.bit_width(), data.index_type.name(), data.index_type.bit_width());
123 print_location(data.location);
124}
125
126void __ubsan_handle_type_mismatch_v1(TypeMismatchData const&, ValueHandle) __attribute__((used));
127void __ubsan_handle_type_mismatch_v1(TypeMismatchData const& data, ValueHandle ptr)
128{
129 constexpr StringView kinds[] = {
130 "load of"sv,
131 "store to"sv,
132 "reference binding to"sv,
133 "member access within"sv,
134 "member call on"sv,
135 "constructor call on"sv,
136 "downcast of"sv,
137 "downcast of"sv,
138 "upcast of"sv,
139 "cast to virtual base of"sv,
140 "_Nonnull binding to"sv,
141 "dynamic operation on"sv
142 };
143
144 FlatPtr alignment = (FlatPtr)1 << data.log_alignment;
145 auto kind = kinds[data.type_check_kind];
146
147 if (!ptr)
148 critical_dmesgln("KUBSAN: {} null pointer of type {}", kind, data.type.name());
149 else if ((FlatPtr)ptr & (alignment - 1))
150 critical_dmesgln("KUBSAN: {} misaligned address {:p} of type {}", kind, ptr, data.type.name());
151 else
152 critical_dmesgln("KUBSAN: {} address {:p} with insufficient space for type {}", kind, ptr, data.type.name());
153
154 print_location(data.location);
155}
156
157void __ubsan_handle_alignment_assumption(AlignmentAssumptionData const&, ValueHandle, ValueHandle, ValueHandle) __attribute__((used));
158void __ubsan_handle_alignment_assumption(AlignmentAssumptionData const& data, ValueHandle pointer, ValueHandle alignment, ValueHandle offset)
159{
160 if (offset)
161 critical_dmesgln("KUBSAN: assumption of {:p} byte alignment (with offset of {:p} byte) for pointer {:p} of type {} failed", alignment, offset, pointer, data.type.name());
162 else
163 critical_dmesgln("KUBSAN: assumption of {:p} byte alignment for pointer {:p} of type {} failed", alignment, pointer, data.type.name());
164
165 print_location(data.location);
166}
167
168void __ubsan_handle_builtin_unreachable(UnreachableData const&) __attribute__((used));
169void __ubsan_handle_builtin_unreachable(UnreachableData const& data)
170{
171 critical_dmesgln("KUBSAN: execution reached an unreachable program point");
172 print_location(data.location);
173}
174
175void __ubsan_handle_missing_return(UnreachableData const&) __attribute__((used));
176void __ubsan_handle_missing_return(UnreachableData const& data)
177{
178 critical_dmesgln("KUBSAN: execution reached the end of a value-returning function without returning a value");
179 print_location(data.location);
180}
181
182void __ubsan_handle_implicit_conversion(ImplicitConversionData const&, ValueHandle, ValueHandle) __attribute__((used));
183void __ubsan_handle_implicit_conversion(ImplicitConversionData const& data, ValueHandle, ValueHandle)
184{
185 char const* src_signed = data.from_type.is_signed() ? "" : "un";
186 char const* dst_signed = data.to_type.is_signed() ? "" : "un";
187 critical_dmesgln("KUBSAN: implicit conversion from type {} ({}-bit, {}signed) to type {} ({}-bit, {}signed)", data.from_type.name(), data.from_type.bit_width(), src_signed, data.to_type.name(), data.to_type.bit_width(), dst_signed);
188 print_location(data.location);
189}
190
191void __ubsan_handle_invalid_builtin(const InvalidBuiltinData) __attribute__((used));
192void __ubsan_handle_invalid_builtin(const InvalidBuiltinData data)
193{
194 critical_dmesgln("KUBSAN: passing invalid argument");
195 print_location(data.location);
196}
197
198void __ubsan_handle_pointer_overflow(PointerOverflowData const&, ValueHandle, ValueHandle) __attribute__((used));
199void __ubsan_handle_pointer_overflow(PointerOverflowData const& data, ValueHandle base, ValueHandle result)
200{
201 if (base == 0 && result == 0)
202 critical_dmesgln("KUBSAN: applied zero offset to nullptr");
203 else if (base == 0 && result != 0)
204 critical_dmesgln("KUBSAN: applied non-zero offset {:p} to nullptr", result);
205 else if (base != 0 && result == 0)
206 critical_dmesgln("KUBSAN: applying non-zero offset to non-null pointer {:p} produced null pointer", base);
207 else
208 critical_dmesgln("KUBSAN: addition of unsigned offset to {:p} overflowed to {:p}", base, result);
209 print_location(data.location);
210}
211}