Blame view

lib/ubsan.c 10.1 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
2
3
4
5
6
  /*
   * UBSAN error reporting functions
   *
   * Copyright (c) 2014 Samsung Electronics Co., Ltd.
   * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
7
8
9
10
11
12
13
14
15
   */
  
  #include <linux/bitops.h>
  #include <linux/bug.h>
  #include <linux/ctype.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/types.h>
  #include <linux/sched.h>
d08965a27   Peter Zijlstra   x86/uaccess, ubsa...
16
  #include <linux/uaccess.h>
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
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
  
  #include "ubsan.h"
  
  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"
  };
  
  #define REPORTED_BIT 31
  
  #if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN)
  #define COLUMN_MASK (~(1U << REPORTED_BIT))
  #define LINE_MASK   (~0U)
  #else
  #define COLUMN_MASK   (~0U)
  #define LINE_MASK (~(1U << REPORTED_BIT))
  #endif
  
  #define VALUE_LENGTH 40
  
  static bool was_reported(struct source_location *location)
  {
  	return test_and_set_bit(REPORTED_BIT, &location->reported);
  }
  
  static void print_source_location(const char *prefix,
  				struct source_location *loc)
  {
  	pr_err("%s %s:%d:%d
  ", prefix, loc->file_name,
  		loc->line & LINE_MASK, loc->column & COLUMN_MASK);
  }
  
  static bool suppress_report(struct source_location *loc)
  {
  	return current->in_ubsan || was_reported(loc);
  }
  
  static bool type_is_int(struct type_descriptor *type)
  {
  	return type->type_kind == type_kind_int;
  }
  
  static bool type_is_signed(struct type_descriptor *type)
  {
  	WARN_ON(!type_is_int(type));
  	return  type->type_info & 1;
  }
  
  static unsigned type_bit_width(struct type_descriptor *type)
  {
  	return 1 << (type->type_info >> 1);
  }
  
  static bool is_inline_int(struct type_descriptor *type)
  {
  	unsigned inline_bits = sizeof(unsigned long)*8;
  	unsigned bits = type_bit_width(type);
  
  	WARN_ON(!type_is_int(type));
  
  	return bits <= inline_bits;
  }
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
86
  static s_max get_signed_val(struct type_descriptor *type, void *val)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
87
88
89
  {
  	if (is_inline_int(type)) {
  		unsigned extra_bits = sizeof(s_max)*8 - type_bit_width(type);
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
90
91
92
  		unsigned long ulong_val = (unsigned long)val;
  
  		return ((s_max)ulong_val) << extra_bits >> extra_bits;
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
93
94
95
96
97
98
99
  	}
  
  	if (type_bit_width(type) == 64)
  		return *(s64 *)val;
  
  	return *(s_max *)val;
  }
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
100
  static bool val_is_negative(struct type_descriptor *type, void *val)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
101
102
103
  {
  	return type_is_signed(type) && get_signed_val(type, val) < 0;
  }
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
104
  static u_max get_unsigned_val(struct type_descriptor *type, void *val)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
105
106
  {
  	if (is_inline_int(type))
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
107
  		return (unsigned long)val;
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
108
109
110
111
112
113
114
115
  
  	if (type_bit_width(type) == 64)
  		return *(u64 *)val;
  
  	return *(u_max *)val;
  }
  
  static void val_to_string(char *str, size_t size, struct type_descriptor *type,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
116
  			void *value)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  {
  	if (type_is_int(type)) {
  		if (type_bit_width(type) == 128) {
  #if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__)
  			u_max val = get_unsigned_val(type, value);
  
  			scnprintf(str, size, "0x%08x%08x%08x%08x",
  				(u32)(val >> 96),
  				(u32)(val >> 64),
  				(u32)(val >> 32),
  				(u32)(val));
  #else
  			WARN_ON(1);
  #endif
  		} else if (type_is_signed(type)) {
  			scnprintf(str, size, "%lld",
  				(s64)get_signed_val(type, value));
  		} else {
  			scnprintf(str, size, "%llu",
  				(u64)get_unsigned_val(type, value));
  		}
  	}
  }
735e7a12a   Julien Grall   lib/ubsan: don't ...
140
  static void ubsan_prologue(struct source_location *location)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
141
142
  {
  	current->in_ubsan++;
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
143
144
145
146
147
148
  
  	pr_err("========================================"
  		"========================================
  ");
  	print_source_location("UBSAN: Undefined behaviour in", location);
  }
735e7a12a   Julien Grall   lib/ubsan: don't ...
149
  static void ubsan_epilogue(void)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
150
151
152
153
154
  {
  	dump_stack();
  	pr_err("========================================"
  		"========================================
  ");
735e7a12a   Julien Grall   lib/ubsan: don't ...
155

c6d308534   Andrey Ryabinin   UBSAN: run-time u...
156
157
  	current->in_ubsan--;
  }
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
158
159
  static void handle_overflow(struct overflow_data *data, void *lhs,
  			void *rhs, char op)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
160
161
162
  {
  
  	struct type_descriptor *type = data->type;
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
163
164
165
166
167
  	char lhs_val_str[VALUE_LENGTH];
  	char rhs_val_str[VALUE_LENGTH];
  
  	if (suppress_report(&data->location))
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
168
  	ubsan_prologue(&data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
169
170
171
172
173
174
175
176
177
178
179
180
  
  	val_to_string(lhs_val_str, sizeof(lhs_val_str), type, lhs);
  	val_to_string(rhs_val_str, sizeof(rhs_val_str), type, rhs);
  	pr_err("%s integer overflow:
  ",
  		type_is_signed(type) ? "signed" : "unsigned");
  	pr_err("%s %c %s cannot be represented in type %s
  ",
  		lhs_val_str,
  		op,
  		rhs_val_str,
  		type->type_name);
735e7a12a   Julien Grall   lib/ubsan: don't ...
181
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
182
183
184
  }
  
  void __ubsan_handle_add_overflow(struct overflow_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
185
  				void *lhs, void *rhs)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
186
187
188
189
190
191
192
  {
  
  	handle_overflow(data, lhs, rhs, '+');
  }
  EXPORT_SYMBOL(__ubsan_handle_add_overflow);
  
  void __ubsan_handle_sub_overflow(struct overflow_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
193
  				void *lhs, void *rhs)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
194
195
196
197
198
199
  {
  	handle_overflow(data, lhs, rhs, '-');
  }
  EXPORT_SYMBOL(__ubsan_handle_sub_overflow);
  
  void __ubsan_handle_mul_overflow(struct overflow_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
200
  				void *lhs, void *rhs)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
201
202
203
204
205
206
  {
  	handle_overflow(data, lhs, rhs, '*');
  }
  EXPORT_SYMBOL(__ubsan_handle_mul_overflow);
  
  void __ubsan_handle_negate_overflow(struct overflow_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
207
  				void *old_val)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
208
  {
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
209
210
211
212
  	char old_val_str[VALUE_LENGTH];
  
  	if (suppress_report(&data->location))
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
213
  	ubsan_prologue(&data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
214
215
216
217
218
219
  
  	val_to_string(old_val_str, sizeof(old_val_str), data->type, old_val);
  
  	pr_err("negation of %s cannot be represented in type %s:
  ",
  		old_val_str, data->type->type_name);
735e7a12a   Julien Grall   lib/ubsan: don't ...
220
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
221
222
223
224
225
  }
  EXPORT_SYMBOL(__ubsan_handle_negate_overflow);
  
  
  void __ubsan_handle_divrem_overflow(struct overflow_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
226
  				void *lhs, void *rhs)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
227
  {
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
228
229
230
231
  	char rhs_val_str[VALUE_LENGTH];
  
  	if (suppress_report(&data->location))
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
232
  	ubsan_prologue(&data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
233
234
235
236
237
238
239
240
241
242
  
  	val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs);
  
  	if (type_is_signed(data->type) && get_signed_val(data->type, rhs) == -1)
  		pr_err("division of %s by -1 cannot be represented in type %s
  ",
  			rhs_val_str, data->type->type_name);
  	else
  		pr_err("division by zero
  ");
735e7a12a   Julien Grall   lib/ubsan: don't ...
243
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
244
245
  }
  EXPORT_SYMBOL(__ubsan_handle_divrem_overflow);
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
246
  static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
247
  {
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
248
  	if (suppress_report(data->location))
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
249
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
250
  	ubsan_prologue(data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
251
252
253
254
255
  
  	pr_err("%s null pointer of type %s
  ",
  		type_check_kinds[data->type_check_kind],
  		data->type->type_name);
735e7a12a   Julien Grall   lib/ubsan: don't ...
256
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
257
  }
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
258
  static void handle_misaligned_access(struct type_mismatch_data_common *data,
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
259
260
  				unsigned long ptr)
  {
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
261
  	if (suppress_report(data->location))
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
262
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
263
  	ubsan_prologue(data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
264
265
266
267
268
269
270
  
  	pr_err("%s misaligned address %p for type %s
  ",
  		type_check_kinds[data->type_check_kind],
  		(void *)ptr, data->type->type_name);
  	pr_err("which requires %ld byte alignment
  ", data->alignment);
735e7a12a   Julien Grall   lib/ubsan: don't ...
271
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
272
  }
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
273
  static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
274
275
  					unsigned long ptr)
  {
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
276
  	if (suppress_report(data->location))
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
277
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
278
  	ubsan_prologue(data->location);
901d805c3   Nicolas Iooss   UBSAN: fix typo i...
279
280
  	pr_err("%s address %p with insufficient space
  ",
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
281
282
283
284
  		type_check_kinds[data->type_check_kind],
  		(void *) ptr);
  	pr_err("for an object of type %s
  ", data->type->type_name);
735e7a12a   Julien Grall   lib/ubsan: don't ...
285
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
286
  }
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
287
  static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
288
289
  				unsigned long ptr)
  {
d08965a27   Peter Zijlstra   x86/uaccess, ubsa...
290
  	unsigned long flags = user_access_save();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
291
292
293
294
  
  	if (!ptr)
  		handle_null_ptr_deref(data);
  	else if (data->alignment && !IS_ALIGNED(ptr, data->alignment))
b8fe1120b   Andrew Morton   lib/ubsan.c: s/mi...
295
  		handle_misaligned_access(data, ptr);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
296
297
  	else
  		handle_object_size_mismatch(data, ptr);
d08965a27   Peter Zijlstra   x86/uaccess, ubsa...
298
299
  
  	user_access_restore(flags);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
300
  }
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
301
302
  
  void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
303
  				void *ptr)
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
304
305
306
307
308
309
310
  {
  	struct type_mismatch_data_common common_data = {
  		.location = &data->location,
  		.type = data->type,
  		.alignment = data->alignment,
  		.type_check_kind = data->type_check_kind
  	};
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
311
  	ubsan_type_mismatch_common(&common_data, (unsigned long)ptr);
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
312
  }
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
313
  EXPORT_SYMBOL(__ubsan_handle_type_mismatch);
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
314
  void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
315
  				void *ptr)
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
316
317
318
319
320
321
322
323
  {
  
  	struct type_mismatch_data_common common_data = {
  		.location = &data->location,
  		.type = data->type,
  		.alignment = 1UL << data->log_alignment,
  		.type_check_kind = data->type_check_kind
  	};
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
324
  	ubsan_type_mismatch_common(&common_data, (unsigned long)ptr);
42440c1f9   Andrey Ryabinin   lib/ubsan: add ty...
325
326
  }
  EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1);
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
327
  void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, void *index)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
328
  {
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
329
330
331
332
  	char index_str[VALUE_LENGTH];
  
  	if (suppress_report(&data->location))
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
333
  	ubsan_prologue(&data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
334
335
336
337
338
  
  	val_to_string(index_str, sizeof(index_str), data->index_type, index);
  	pr_err("index %s is out of range for type %s
  ", index_str,
  		data->array_type->type_name);
735e7a12a   Julien Grall   lib/ubsan: don't ...
339
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
340
341
342
343
  }
  EXPORT_SYMBOL(__ubsan_handle_out_of_bounds);
  
  void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
344
  					void *lhs, void *rhs)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
345
  {
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
346
347
348
349
  	struct type_descriptor *rhs_type = data->rhs_type;
  	struct type_descriptor *lhs_type = data->lhs_type;
  	char rhs_str[VALUE_LENGTH];
  	char lhs_str[VALUE_LENGTH];
39303579e   Peter Zijlstra   ubsan, x86: Annot...
350
  	unsigned long ua_flags = user_access_save();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
351
352
  
  	if (suppress_report(&data->location))
39303579e   Peter Zijlstra   ubsan, x86: Annot...
353
  		goto out;
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
354

735e7a12a   Julien Grall   lib/ubsan: don't ...
355
  	ubsan_prologue(&data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  
  	val_to_string(rhs_str, sizeof(rhs_str), rhs_type, rhs);
  	val_to_string(lhs_str, sizeof(lhs_str), lhs_type, lhs);
  
  	if (val_is_negative(rhs_type, rhs))
  		pr_err("shift exponent %s is negative
  ", rhs_str);
  
  	else if (get_unsigned_val(rhs_type, rhs) >=
  		type_bit_width(lhs_type))
  		pr_err("shift exponent %s is too large for %u-bit type %s
  ",
  			rhs_str,
  			type_bit_width(lhs_type),
  			lhs_type->type_name);
  	else if (val_is_negative(lhs_type, lhs))
  		pr_err("left shift of negative value %s
  ",
  			lhs_str);
  	else
  		pr_err("left shift of %s by %s places cannot be"
  			" represented in type %s
  ",
  			lhs_str, rhs_str,
  			lhs_type->type_name);
735e7a12a   Julien Grall   lib/ubsan: don't ...
381
  	ubsan_epilogue();
39303579e   Peter Zijlstra   ubsan, x86: Annot...
382
383
  out:
  	user_access_restore(ua_flags);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
384
385
  }
  EXPORT_SYMBOL(__ubsan_handle_shift_out_of_bounds);
1c23b4108   Arnd Bergmann   lib/ubsan.c: don'...
386
  void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
387
  {
735e7a12a   Julien Grall   lib/ubsan: don't ...
388
  	ubsan_prologue(&data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
389
390
  	pr_err("calling __builtin_unreachable()
  ");
735e7a12a   Julien Grall   lib/ubsan: don't ...
391
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
392
393
394
395
396
  	panic("can't return from __builtin_unreachable()");
  }
  EXPORT_SYMBOL(__ubsan_handle_builtin_unreachable);
  
  void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
f0996bc29   Andrey Ryabinin   ubsan: Fix nasty ...
397
  				void *val)
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
398
  {
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
399
400
401
402
  	char val_str[VALUE_LENGTH];
  
  	if (suppress_report(&data->location))
  		return;
735e7a12a   Julien Grall   lib/ubsan: don't ...
403
  	ubsan_prologue(&data->location);
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
404
405
406
407
408
409
  
  	val_to_string(val_str, sizeof(val_str), data->type, val);
  
  	pr_err("load of value %s is not a valid value for type %s
  ",
  		val_str, data->type->type_name);
735e7a12a   Julien Grall   lib/ubsan: don't ...
410
  	ubsan_epilogue();
c6d308534   Andrey Ryabinin   UBSAN: run-time u...
411
412
  }
  EXPORT_SYMBOL(__ubsan_handle_load_invalid_value);