summaryrefslogtreecommitdiff
path: root/Kernel/UBSanitizer.cpp
blob: 5d714bcaea07818b9b1150657ba215c0cc983413 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <AK/Format.h>
#include <AK/UBSanitizer.h>
#include <Kernel/Arch/Processor.h>
#include <Kernel/KSyms.h>

using namespace Kernel;
using namespace AK::UBSanitizer;

Atomic<bool> AK::UBSanitizer::g_ubsan_is_deadly { true };

extern "C" {

static void print_location(SourceLocation const& location)
{
    if (!location.filename())
        critical_dmesgln("KUBSAN: in unknown file");
    else
        critical_dmesgln("KUBSAN: at {}, line {}, column: {}", location.filename(), location.line(), location.column());
    dump_backtrace(g_ubsan_is_deadly ? PrintToScreen::Yes : PrintToScreen::No);
    if (g_ubsan_is_deadly) {
        critical_dmesgln("UB is configured to be deadly, halting the system.");
        Processor::halt();
    }
}

void __ubsan_handle_load_invalid_value(InvalidValueData const&, ValueHandle) __attribute__((used));
void __ubsan_handle_load_invalid_value(InvalidValueData const& data, ValueHandle)
{
    critical_dmesgln("KUBSAN: load-invalid-value: {} ({}-bit)", data.type.name(), data.type.bit_width());
    print_location(data.location);
}

void __ubsan_handle_nonnull_arg(NonnullArgData const&) __attribute__((used));
void __ubsan_handle_nonnull_arg(NonnullArgData const& data)
{
    critical_dmesgln("KUBSAN: null pointer passed as argument {}, which is declared to never be null", data.argument_index);
    print_location(data.location);
}

void __ubsan_handle_nullability_arg(NonnullArgData const&) __attribute__((used));
void __ubsan_handle_nullability_arg(NonnullArgData const& data)
{
    critical_dmesgln("KUBSAN: null pointer passed as argument {}, which is declared to never be null", data.argument_index);
    print_location(data.location);
}

void __ubsan_handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation const&) __attribute__((used));
void __ubsan_handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation const& location)
{
    critical_dmesgln("KUBSAN: null pointer return from function declared to never return null");
    print_location(location);
}

void __ubsan_handle_nullability_return_v1(NonnullReturnData const& data, SourceLocation const& location) __attribute__((used));
void __ubsan_handle_nullability_return_v1(NonnullReturnData const&, SourceLocation const& location)
{
    critical_dmesgln("KUBSAN: null pointer return from function declared to never return null");
    print_location(location);
}

void __ubsan_handle_vla_bound_not_positive(VLABoundData const&, ValueHandle) __attribute__((used));
void __ubsan_handle_vla_bound_not_positive(VLABoundData const& data, ValueHandle)
{
    critical_dmesgln("KUBSAN: VLA bound not positive {} ({}-bit)", data.type.name(), data.type.bit_width());
    print_location(data.location);
}

void __ubsan_handle_add_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
void __ubsan_handle_add_overflow(OverflowData const& data, ValueHandle, ValueHandle)
{
    critical_dmesgln("KUBSAN: addition overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());

    print_location(data.location);
}

void __ubsan_handle_sub_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
void __ubsan_handle_sub_overflow(OverflowData const& data, ValueHandle, ValueHandle)
{
    critical_dmesgln("KUBSAN: subtraction overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());

    print_location(data.location);
}

void __ubsan_handle_negate_overflow(OverflowData const&, ValueHandle) __attribute__((used));
void __ubsan_handle_negate_overflow(OverflowData const& data, ValueHandle)
{
    critical_dmesgln("KUBSAN: negation overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());

    print_location(data.location);
}

void __ubsan_handle_mul_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
void __ubsan_handle_mul_overflow(OverflowData const& data, ValueHandle, ValueHandle)
{
    critical_dmesgln("KUBSAN: multiplication overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
    print_location(data.location);
}

void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData const& data, ValueHandle, ValueHandle)
{
    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());
    print_location(data.location);
}

void __ubsan_handle_divrem_overflow(OverflowData const&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
void __ubsan_handle_divrem_overflow(OverflowData const& data, ValueHandle, ValueHandle)
{
    critical_dmesgln("KUBSAN: divrem overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
    print_location(data.location);
}

void __ubsan_handle_out_of_bounds(OutOfBoundsData const&, ValueHandle) __attribute__((used));
void __ubsan_handle_out_of_bounds(OutOfBoundsData const& data, ValueHandle)
{
    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());
    print_location(data.location);
}

void __ubsan_handle_type_mismatch_v1(TypeMismatchData const&, ValueHandle) __attribute__((used));
void __ubsan_handle_type_mismatch_v1(TypeMismatchData const& data, ValueHandle ptr)
{
    constexpr StringView kinds[] = {
        "load of"sv,
        "store to"sv,
        "reference binding to"sv,
        "member access within"sv,
        "member call on"sv,
        "constructor call on"sv,
        "downcast of"sv,
        "downcast of"sv,
        "upcast of"sv,
        "cast to virtual base of"sv,
        "_Nonnull binding to"sv,
        "dynamic operation on"sv
    };

    FlatPtr alignment = (FlatPtr)1 << data.log_alignment;
    auto kind = kinds[data.type_check_kind];

    if (!ptr)
        critical_dmesgln("KUBSAN: {} null pointer of type {}", kind, data.type.name());
    else if ((FlatPtr)ptr & (alignment - 1))
        critical_dmesgln("KUBSAN: {} misaligned address {:p} of type {}", kind, ptr, data.type.name());
    else
        critical_dmesgln("KUBSAN: {} address {:p} with insufficient space for type {}", kind, ptr, data.type.name());

    print_location(data.location);
}

void __ubsan_handle_alignment_assumption(AlignmentAssumptionData const&, ValueHandle, ValueHandle, ValueHandle) __attribute__((used));
void __ubsan_handle_alignment_assumption(AlignmentAssumptionData const& data, ValueHandle pointer, ValueHandle alignment, ValueHandle offset)
{
    if (offset)
        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());
    else
        critical_dmesgln("KUBSAN: assumption of {:p} byte alignment for pointer {:p} of type {} failed", alignment, pointer, data.type.name());

    print_location(data.location);
}

void __ubsan_handle_builtin_unreachable(UnreachableData const&) __attribute__((used));
void __ubsan_handle_builtin_unreachable(UnreachableData const& data)
{
    critical_dmesgln("KUBSAN: execution reached an unreachable program point");
    print_location(data.location);
}

void __ubsan_handle_missing_return(UnreachableData const&) __attribute__((used));
void __ubsan_handle_missing_return(UnreachableData const& data)
{
    critical_dmesgln("KUBSAN: execution reached the end of a value-returning function without returning a value");
    print_location(data.location);
}

void __ubsan_handle_implicit_conversion(ImplicitConversionData const&, ValueHandle, ValueHandle) __attribute__((used));
void __ubsan_handle_implicit_conversion(ImplicitConversionData const& data, ValueHandle, ValueHandle)
{
    char const* src_signed = data.from_type.is_signed() ? "" : "un";
    char const* dst_signed = data.to_type.is_signed() ? "" : "un";
    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);
    print_location(data.location);
}

void __ubsan_handle_invalid_builtin(const InvalidBuiltinData) __attribute__((used));
void __ubsan_handle_invalid_builtin(const InvalidBuiltinData data)
{
    critical_dmesgln("KUBSAN: passing invalid argument");
    print_location(data.location);
}

void __ubsan_handle_pointer_overflow(PointerOverflowData const&, ValueHandle, ValueHandle) __attribute__((used));
void __ubsan_handle_pointer_overflow(PointerOverflowData const& data, ValueHandle base, ValueHandle result)
{
    if (base == 0 && result == 0)
        critical_dmesgln("KUBSAN: applied zero offset to nullptr");
    else if (base == 0 && result != 0)
        critical_dmesgln("KUBSAN: applied non-zero offset {:p} to nullptr", result);
    else if (base != 0 && result == 0)
        critical_dmesgln("KUBSAN: applying non-zero offset to non-null pointer {:p} produced null pointer", base);
    else
        critical_dmesgln("KUBSAN: addition of unsigned offset to {:p} overflowed to {:p}", base, result);
    print_location(data.location);
}
}