Merge tag 'for-5.18/write-streams-2022-03-18' of git://git.kernel.dk/linux-block
[linux-2.6-block.git] / lib / ubsan.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
c6d30853
AR
2/*
3 * UBSAN error reporting functions
4 *
5 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6 * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
c6d30853
AR
7 */
8
9#include <linux/bitops.h>
10#include <linux/bug.h>
11#include <linux/ctype.h>
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/types.h>
15#include <linux/sched.h>
d08965a2 16#include <linux/uaccess.h>
1195505f 17#include <kunit/test-bug.h>
c6d30853
AR
18
19#include "ubsan.h"
20
d3c22797 21static const char * const type_check_kinds[] = {
c6d30853
AR
22 "load of",
23 "store to",
24 "reference binding to",
25 "member access within",
26 "member call on",
27 "constructor call on",
28 "downcast of",
29 "downcast of"
30};
31
32#define REPORTED_BIT 31
33
34#if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN)
35#define COLUMN_MASK (~(1U << REPORTED_BIT))
36#define LINE_MASK (~0U)
37#else
38#define COLUMN_MASK (~0U)
39#define LINE_MASK (~(1U << REPORTED_BIT))
40#endif
41
42#define VALUE_LENGTH 40
43
44static bool was_reported(struct source_location *location)
45{
46 return test_and_set_bit(REPORTED_BIT, &location->reported);
47}
48
c6d30853
AR
49static bool suppress_report(struct source_location *loc)
50{
51 return current->in_ubsan || was_reported(loc);
52}
53
54static bool type_is_int(struct type_descriptor *type)
55{
56 return type->type_kind == type_kind_int;
57}
58
59static bool type_is_signed(struct type_descriptor *type)
60{
61 WARN_ON(!type_is_int(type));
62 return type->type_info & 1;
63}
64
65static unsigned type_bit_width(struct type_descriptor *type)
66{
67 return 1 << (type->type_info >> 1);
68}
69
70static bool is_inline_int(struct type_descriptor *type)
71{
72 unsigned inline_bits = sizeof(unsigned long)*8;
73 unsigned bits = type_bit_width(type);
74
75 WARN_ON(!type_is_int(type));
76
77 return bits <= inline_bits;
78}
79
f0996bc2 80static s_max get_signed_val(struct type_descriptor *type, void *val)
c6d30853
AR
81{
82 if (is_inline_int(type)) {
83 unsigned extra_bits = sizeof(s_max)*8 - type_bit_width(type);
f0996bc2
AR
84 unsigned long ulong_val = (unsigned long)val;
85
86 return ((s_max)ulong_val) << extra_bits >> extra_bits;
c6d30853
AR
87 }
88
89 if (type_bit_width(type) == 64)
90 return *(s64 *)val;
91
92 return *(s_max *)val;
93}
94
f0996bc2 95static bool val_is_negative(struct type_descriptor *type, void *val)
c6d30853
AR
96{
97 return type_is_signed(type) && get_signed_val(type, val) < 0;
98}
99
f0996bc2 100static u_max get_unsigned_val(struct type_descriptor *type, void *val)
c6d30853
AR
101{
102 if (is_inline_int(type))
f0996bc2 103 return (unsigned long)val;
c6d30853
AR
104
105 if (type_bit_width(type) == 64)
106 return *(u64 *)val;
107
108 return *(u_max *)val;
109}
110
111static void val_to_string(char *str, size_t size, struct type_descriptor *type,
f0996bc2 112 void *value)
c6d30853
AR
113{
114 if (type_is_int(type)) {
115 if (type_bit_width(type) == 128) {
c12d3362 116#if defined(CONFIG_ARCH_SUPPORTS_INT128)
c6d30853
AR
117 u_max val = get_unsigned_val(type, value);
118
119 scnprintf(str, size, "0x%08x%08x%08x%08x",
120 (u32)(val >> 96),
121 (u32)(val >> 64),
122 (u32)(val >> 32),
123 (u32)(val));
124#else
125 WARN_ON(1);
126#endif
127 } else if (type_is_signed(type)) {
128 scnprintf(str, size, "%lld",
129 (s64)get_signed_val(type, value));
130 } else {
131 scnprintf(str, size, "%llu",
132 (u64)get_unsigned_val(type, value));
133 }
134 }
135}
136
ef065653 137static void ubsan_prologue(struct source_location *loc, const char *reason)
c6d30853
AR
138{
139 current->in_ubsan++;
c6d30853
AR
140
141 pr_err("========================================"
142 "========================================\n");
ef065653
KC
143 pr_err("UBSAN: %s in %s:%d:%d\n", reason, loc->file_name,
144 loc->line & LINE_MASK, loc->column & COLUMN_MASK);
1195505f
UG
145
146 kunit_fail_current_test("%s in %s", reason, loc->file_name);
c6d30853
AR
147}
148
ce5c31db 149static void ubsan_epilogue(void)
c6d30853
AR
150{
151 dump_stack();
152 pr_err("========================================"
153 "========================================\n");
ce5c31db 154
c6d30853 155 current->in_ubsan--;
1d28c8d6 156
d83ce027 157 if (panic_on_warn)
1d28c8d6 158 panic("panic_on_warn set ...\n");
c6d30853
AR
159}
160
469cbd01 161void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs)
c6d30853 162{
469cbd01 163 struct overflow_data *data = _data;
c6d30853
AR
164 char rhs_val_str[VALUE_LENGTH];
165
166 if (suppress_report(&data->location))
167 return;
168
ef065653 169 ubsan_prologue(&data->location, "division-overflow");
c6d30853
AR
170
171 val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs);
172
173 if (type_is_signed(data->type) && get_signed_val(data->type, rhs) == -1)
174 pr_err("division of %s by -1 cannot be represented in type %s\n",
175 rhs_val_str, data->type->type_name);
176 else
177 pr_err("division by zero\n");
178
ce5c31db 179 ubsan_epilogue();
c6d30853
AR
180}
181EXPORT_SYMBOL(__ubsan_handle_divrem_overflow);
182
42440c1f 183static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
c6d30853 184{
42440c1f 185 if (suppress_report(data->location))
c6d30853
AR
186 return;
187
ef065653 188 ubsan_prologue(data->location, "null-ptr-deref");
c6d30853
AR
189
190 pr_err("%s null pointer of type %s\n",
191 type_check_kinds[data->type_check_kind],
192 data->type->type_name);
193
ce5c31db 194 ubsan_epilogue();
c6d30853
AR
195}
196
42440c1f 197static void handle_misaligned_access(struct type_mismatch_data_common *data,
c6d30853
AR
198 unsigned long ptr)
199{
42440c1f 200 if (suppress_report(data->location))
c6d30853
AR
201 return;
202
ef065653 203 ubsan_prologue(data->location, "misaligned-access");
c6d30853
AR
204
205 pr_err("%s misaligned address %p for type %s\n",
206 type_check_kinds[data->type_check_kind],
207 (void *)ptr, data->type->type_name);
208 pr_err("which requires %ld byte alignment\n", data->alignment);
209
ce5c31db 210 ubsan_epilogue();
c6d30853
AR
211}
212
42440c1f 213static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
c6d30853
AR
214 unsigned long ptr)
215{
42440c1f 216 if (suppress_report(data->location))
c6d30853
AR
217 return;
218
ef065653 219 ubsan_prologue(data->location, "object-size-mismatch");
901d805c 220 pr_err("%s address %p with insufficient space\n",
c6d30853
AR
221 type_check_kinds[data->type_check_kind],
222 (void *) ptr);
223 pr_err("for an object of type %s\n", data->type->type_name);
ce5c31db 224 ubsan_epilogue();
c6d30853
AR
225}
226
42440c1f 227static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
c6d30853
AR
228 unsigned long ptr)
229{
d08965a2 230 unsigned long flags = user_access_save();
c6d30853
AR
231
232 if (!ptr)
233 handle_null_ptr_deref(data);
234 else if (data->alignment && !IS_ALIGNED(ptr, data->alignment))
b8fe1120 235 handle_misaligned_access(data, ptr);
c6d30853
AR
236 else
237 handle_object_size_mismatch(data, ptr);
d08965a2
PZ
238
239 user_access_restore(flags);
c6d30853 240}
42440c1f
AR
241
242void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
f0996bc2 243 void *ptr)
42440c1f
AR
244{
245 struct type_mismatch_data_common common_data = {
246 .location = &data->location,
247 .type = data->type,
248 .alignment = data->alignment,
249 .type_check_kind = data->type_check_kind
250 };
251
f0996bc2 252 ubsan_type_mismatch_common(&common_data, (unsigned long)ptr);
42440c1f 253}
c6d30853
AR
254EXPORT_SYMBOL(__ubsan_handle_type_mismatch);
255
469cbd01 256void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr)
42440c1f 257{
469cbd01 258 struct type_mismatch_data_v1 *data = _data;
42440c1f
AR
259 struct type_mismatch_data_common common_data = {
260 .location = &data->location,
261 .type = data->type,
262 .alignment = 1UL << data->log_alignment,
263 .type_check_kind = data->type_check_kind
264 };
265
f0996bc2 266 ubsan_type_mismatch_common(&common_data, (unsigned long)ptr);
42440c1f
AR
267}
268EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1);
269
469cbd01 270void __ubsan_handle_out_of_bounds(void *_data, void *index)
c6d30853 271{
469cbd01 272 struct out_of_bounds_data *data = _data;
c6d30853
AR
273 char index_str[VALUE_LENGTH];
274
275 if (suppress_report(&data->location))
276 return;
277
ef065653 278 ubsan_prologue(&data->location, "array-index-out-of-bounds");
c6d30853
AR
279
280 val_to_string(index_str, sizeof(index_str), data->index_type, index);
281 pr_err("index %s is out of range for type %s\n", index_str,
282 data->array_type->type_name);
ce5c31db 283 ubsan_epilogue();
c6d30853
AR
284}
285EXPORT_SYMBOL(__ubsan_handle_out_of_bounds);
286
469cbd01 287void __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs)
c6d30853 288{
469cbd01 289 struct shift_out_of_bounds_data *data = _data;
c6d30853
AR
290 struct type_descriptor *rhs_type = data->rhs_type;
291 struct type_descriptor *lhs_type = data->lhs_type;
292 char rhs_str[VALUE_LENGTH];
293 char lhs_str[VALUE_LENGTH];
9a50dcaf 294 unsigned long ua_flags = user_access_save();
c6d30853
AR
295
296 if (suppress_report(&data->location))
9a50dcaf 297 goto out;
c6d30853 298
ef065653 299 ubsan_prologue(&data->location, "shift-out-of-bounds");
c6d30853
AR
300
301 val_to_string(rhs_str, sizeof(rhs_str), rhs_type, rhs);
302 val_to_string(lhs_str, sizeof(lhs_str), lhs_type, lhs);
303
304 if (val_is_negative(rhs_type, rhs))
305 pr_err("shift exponent %s is negative\n", rhs_str);
306
307 else if (get_unsigned_val(rhs_type, rhs) >=
308 type_bit_width(lhs_type))
309 pr_err("shift exponent %s is too large for %u-bit type %s\n",
310 rhs_str,
311 type_bit_width(lhs_type),
312 lhs_type->type_name);
313 else if (val_is_negative(lhs_type, lhs))
314 pr_err("left shift of negative value %s\n",
315 lhs_str);
316 else
317 pr_err("left shift of %s by %s places cannot be"
318 " represented in type %s\n",
319 lhs_str, rhs_str,
320 lhs_type->type_name);
321
ce5c31db 322 ubsan_epilogue();
9a50dcaf
PZ
323out:
324 user_access_restore(ua_flags);
c6d30853
AR
325}
326EXPORT_SYMBOL(__ubsan_handle_shift_out_of_bounds);
327
328
469cbd01 329void __ubsan_handle_builtin_unreachable(void *_data)
c6d30853 330{
469cbd01 331 struct unreachable_data *data = _data;
ef065653 332 ubsan_prologue(&data->location, "unreachable");
c6d30853 333 pr_err("calling __builtin_unreachable()\n");
ce5c31db 334 ubsan_epilogue();
c6d30853
AR
335 panic("can't return from __builtin_unreachable()");
336}
337EXPORT_SYMBOL(__ubsan_handle_builtin_unreachable);
338
469cbd01 339void __ubsan_handle_load_invalid_value(void *_data, void *val)
c6d30853 340{
469cbd01 341 struct invalid_value_data *data = _data;
c6d30853
AR
342 char val_str[VALUE_LENGTH];
343
344 if (suppress_report(&data->location))
345 return;
346
ef065653 347 ubsan_prologue(&data->location, "invalid-load");
c6d30853
AR
348
349 val_to_string(val_str, sizeof(val_str), data->type, val);
350
351 pr_err("load of value %s is not a valid value for type %s\n",
352 val_str, data->type->type_name);
353
ce5c31db 354 ubsan_epilogue();
c6d30853
AR
355}
356EXPORT_SYMBOL(__ubsan_handle_load_invalid_value);
28abcc96
NC
357
358void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
359 unsigned long align,
360 unsigned long offset);
361void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
362 unsigned long align,
363 unsigned long offset)
364{
365 struct alignment_assumption_data *data = _data;
366 unsigned long real_ptr;
367
368 if (suppress_report(&data->location))
369 return;
370
371 ubsan_prologue(&data->location, "alignment-assumption");
372
373 if (offset)
374 pr_err("assumption of %lu byte alignment (with offset of %lu byte) for pointer of type %s failed",
375 align, offset, data->type->type_name);
376 else
377 pr_err("assumption of %lu byte alignment for pointer of type %s failed",
378 align, data->type->type_name);
379
380 real_ptr = ptr - offset;
381 pr_err("%saddress is %lu aligned, misalignment offset is %lu bytes",
382 offset ? "offset " : "", BIT(real_ptr ? __ffs(real_ptr) : 0),
383 real_ptr & (align - 1));
384
385 ubsan_epilogue();
386}
387EXPORT_SYMBOL(__ubsan_handle_alignment_assumption);