Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

lib/ubsan: don't serialize UBSAN report

At the moment, UBSAN report will be serialized using a spin_lock(). On
RT-systems, spinlocks are turned to rt_spin_lock and may sleep. This
will result to the following splat if the undefined behavior is in a
context that can sleep:

BUG: sleeping function called from invalid context at /src/linux/kernel/locking/rtmutex.c:968
in_atomic(): 1, irqs_disabled(): 128, pid: 3447, name: make
1 lock held by make/3447:
#0: 000000009a966332 (&mm->mmap_sem){++++}, at: do_page_fault+0x140/0x4f8
irq event stamp: 6284
hardirqs last enabled at (6283): [<ffff000011326520>] _raw_spin_unlock_irqrestore+0x90/0xa0
hardirqs last disabled at (6284): [<ffff0000113262b0>] _raw_spin_lock_irqsave+0x30/0x78
softirqs last enabled at (2430): [<ffff000010088ef8>] fpsimd_restore_current_state+0x60/0xe8
softirqs last disabled at (2427): [<ffff000010088ec0>] fpsimd_restore_current_state+0x28/0xe8
Preemption disabled at:
[<ffff000011324a4c>] rt_mutex_futex_unlock+0x4c/0xb0
CPU: 3 PID: 3447 Comm: make Tainted: G W 5.2.14-rt7-01890-ge6e057589653 #911
Call trace:
dump_backtrace+0x0/0x148
show_stack+0x14/0x20
dump_stack+0xbc/0x104
___might_sleep+0x154/0x210
rt_spin_lock+0x68/0xa0
ubsan_prologue+0x30/0x68
handle_overflow+0x64/0xe0
__ubsan_handle_add_overflow+0x10/0x18
__lock_acquire+0x1c28/0x2a28
lock_acquire+0xf0/0x370
_raw_spin_lock_irqsave+0x58/0x78
rt_mutex_futex_unlock+0x4c/0xb0
rt_spin_unlock+0x28/0x70
get_page_from_freelist+0x428/0x2b60
__alloc_pages_nodemask+0x174/0x1708
alloc_pages_vma+0x1ac/0x238
__handle_mm_fault+0x4ac/0x10b0
handle_mm_fault+0x1d8/0x3b0
do_page_fault+0x1c8/0x4f8
do_translation_fault+0xb8/0xe0
do_mem_abort+0x3c/0x98
el0_da+0x20/0x24

The spin_lock() will protect against multiple CPUs to output a report
together, I guess to prevent them from being interleaved. However, they
can still interleave with other messages (and even splat from
__might_sleep).

So the lock usefulness seems pretty limited. Rather than trying to
accomodate RT-system by switching to a raw_spin_lock(), the lock is now
completely dropped.

Link: http://lkml.kernel.org/r/20190920100835.14999-1-julien.grall@arm.com
Signed-off-by: Julien Grall <julien.grall@arm.com>
Reported-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Julien Grall and committed by
Linus Torvalds
ce5c31db 8f6a7f96

+23 -41
+23 -41
lib/ubsan.c
··· 140 140 } 141 141 } 142 142 143 - static DEFINE_SPINLOCK(report_lock); 144 - 145 - static void ubsan_prologue(struct source_location *location, 146 - unsigned long *flags) 143 + static void ubsan_prologue(struct source_location *location) 147 144 { 148 145 current->in_ubsan++; 149 - spin_lock_irqsave(&report_lock, *flags); 150 146 151 147 pr_err("========================================" 152 148 "========================================\n"); 153 149 print_source_location("UBSAN: Undefined behaviour in", location); 154 150 } 155 151 156 - static void ubsan_epilogue(unsigned long *flags) 152 + static void ubsan_epilogue(void) 157 153 { 158 154 dump_stack(); 159 155 pr_err("========================================" 160 156 "========================================\n"); 161 - spin_unlock_irqrestore(&report_lock, *flags); 157 + 162 158 current->in_ubsan--; 163 159 } 164 160 ··· 163 167 { 164 168 165 169 struct type_descriptor *type = data->type; 166 - unsigned long flags; 167 170 char lhs_val_str[VALUE_LENGTH]; 168 171 char rhs_val_str[VALUE_LENGTH]; 169 172 170 173 if (suppress_report(&data->location)) 171 174 return; 172 175 173 - ubsan_prologue(&data->location, &flags); 176 + ubsan_prologue(&data->location); 174 177 175 178 val_to_string(lhs_val_str, sizeof(lhs_val_str), type, lhs); 176 179 val_to_string(rhs_val_str, sizeof(rhs_val_str), type, rhs); ··· 181 186 rhs_val_str, 182 187 type->type_name); 183 188 184 - ubsan_epilogue(&flags); 189 + ubsan_epilogue(); 185 190 } 186 191 187 192 void __ubsan_handle_add_overflow(struct overflow_data *data, ··· 209 214 void __ubsan_handle_negate_overflow(struct overflow_data *data, 210 215 void *old_val) 211 216 { 212 - unsigned long flags; 213 217 char old_val_str[VALUE_LENGTH]; 214 218 215 219 if (suppress_report(&data->location)) 216 220 return; 217 221 218 - ubsan_prologue(&data->location, &flags); 222 + ubsan_prologue(&data->location); 219 223 220 224 val_to_string(old_val_str, sizeof(old_val_str), data->type, old_val); 221 225 222 226 pr_err("negation of %s cannot be represented in type %s:\n", 223 227 old_val_str, data->type->type_name); 224 228 225 - ubsan_epilogue(&flags); 229 + ubsan_epilogue(); 226 230 } 227 231 EXPORT_SYMBOL(__ubsan_handle_negate_overflow); 228 232 ··· 229 235 void __ubsan_handle_divrem_overflow(struct overflow_data *data, 230 236 void *lhs, void *rhs) 231 237 { 232 - unsigned long flags; 233 238 char rhs_val_str[VALUE_LENGTH]; 234 239 235 240 if (suppress_report(&data->location)) 236 241 return; 237 242 238 - ubsan_prologue(&data->location, &flags); 243 + ubsan_prologue(&data->location); 239 244 240 245 val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs); 241 246 ··· 244 251 else 245 252 pr_err("division by zero\n"); 246 253 247 - ubsan_epilogue(&flags); 254 + ubsan_epilogue(); 248 255 } 249 256 EXPORT_SYMBOL(__ubsan_handle_divrem_overflow); 250 257 251 258 static void handle_null_ptr_deref(struct type_mismatch_data_common *data) 252 259 { 253 - unsigned long flags; 254 - 255 260 if (suppress_report(data->location)) 256 261 return; 257 262 258 - ubsan_prologue(data->location, &flags); 263 + ubsan_prologue(data->location); 259 264 260 265 pr_err("%s null pointer of type %s\n", 261 266 type_check_kinds[data->type_check_kind], 262 267 data->type->type_name); 263 268 264 - ubsan_epilogue(&flags); 269 + ubsan_epilogue(); 265 270 } 266 271 267 272 static void handle_misaligned_access(struct type_mismatch_data_common *data, 268 273 unsigned long ptr) 269 274 { 270 - unsigned long flags; 271 - 272 275 if (suppress_report(data->location)) 273 276 return; 274 277 275 - ubsan_prologue(data->location, &flags); 278 + ubsan_prologue(data->location); 276 279 277 280 pr_err("%s misaligned address %p for type %s\n", 278 281 type_check_kinds[data->type_check_kind], 279 282 (void *)ptr, data->type->type_name); 280 283 pr_err("which requires %ld byte alignment\n", data->alignment); 281 284 282 - ubsan_epilogue(&flags); 285 + ubsan_epilogue(); 283 286 } 284 287 285 288 static void handle_object_size_mismatch(struct type_mismatch_data_common *data, 286 289 unsigned long ptr) 287 290 { 288 - unsigned long flags; 289 - 290 291 if (suppress_report(data->location)) 291 292 return; 292 293 293 - ubsan_prologue(data->location, &flags); 294 + ubsan_prologue(data->location); 294 295 pr_err("%s address %p with insufficient space\n", 295 296 type_check_kinds[data->type_check_kind], 296 297 (void *) ptr); 297 298 pr_err("for an object of type %s\n", data->type->type_name); 298 - ubsan_epilogue(&flags); 299 + ubsan_epilogue(); 299 300 } 300 301 301 302 static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data, ··· 338 351 339 352 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, void *index) 340 353 { 341 - unsigned long flags; 342 354 char index_str[VALUE_LENGTH]; 343 355 344 356 if (suppress_report(&data->location)) 345 357 return; 346 358 347 - ubsan_prologue(&data->location, &flags); 359 + ubsan_prologue(&data->location); 348 360 349 361 val_to_string(index_str, sizeof(index_str), data->index_type, index); 350 362 pr_err("index %s is out of range for type %s\n", index_str, 351 363 data->array_type->type_name); 352 - ubsan_epilogue(&flags); 364 + ubsan_epilogue(); 353 365 } 354 366 EXPORT_SYMBOL(__ubsan_handle_out_of_bounds); 355 367 356 368 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data, 357 369 void *lhs, void *rhs) 358 370 { 359 - unsigned long flags; 360 371 struct type_descriptor *rhs_type = data->rhs_type; 361 372 struct type_descriptor *lhs_type = data->lhs_type; 362 373 char rhs_str[VALUE_LENGTH]; ··· 364 379 if (suppress_report(&data->location)) 365 380 goto out; 366 381 367 - ubsan_prologue(&data->location, &flags); 382 + ubsan_prologue(&data->location); 368 383 369 384 val_to_string(rhs_str, sizeof(rhs_str), rhs_type, rhs); 370 385 val_to_string(lhs_str, sizeof(lhs_str), lhs_type, lhs); ··· 387 402 lhs_str, rhs_str, 388 403 lhs_type->type_name); 389 404 390 - ubsan_epilogue(&flags); 405 + ubsan_epilogue(); 391 406 out: 392 407 user_access_restore(ua_flags); 393 408 } ··· 396 411 397 412 void __ubsan_handle_builtin_unreachable(struct unreachable_data *data) 398 413 { 399 - unsigned long flags; 400 - 401 - ubsan_prologue(&data->location, &flags); 414 + ubsan_prologue(&data->location); 402 415 pr_err("calling __builtin_unreachable()\n"); 403 - ubsan_epilogue(&flags); 416 + ubsan_epilogue(); 404 417 panic("can't return from __builtin_unreachable()"); 405 418 } 406 419 EXPORT_SYMBOL(__ubsan_handle_builtin_unreachable); ··· 406 423 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data, 407 424 void *val) 408 425 { 409 - unsigned long flags; 410 426 char val_str[VALUE_LENGTH]; 411 427 412 428 if (suppress_report(&data->location)) 413 429 return; 414 430 415 - ubsan_prologue(&data->location, &flags); 431 + ubsan_prologue(&data->location); 416 432 417 433 val_to_string(val_str, sizeof(val_str), data->type, val); 418 434 419 435 pr_err("load of value %s is not a valid value for type %s\n", 420 436 val_str, data->type->type_name); 421 437 422 - ubsan_epilogue(&flags); 438 + ubsan_epilogue(); 423 439 } 424 440 EXPORT_SYMBOL(__ubsan_handle_load_invalid_value);