| @@ -40,6 +40,13 @@ module_param_named(udelay_interrupt, kcsan_udelay_interrupt, uint, 0644); · 39 unmodified lines |
| 40 | 40 | module_param_named(skip_watch, kcsan_skip_watch, long, 0644); |
| 41 | 41 | module_param_named(interrupt_watcher, kcsan_interrupt_watcher, bool, 0444); |
| 42 | 42 | |
| 43 | +#ifdef CONFIG_KCSAN_WEAK_MEMORY |
| 44 | +static bool kcsan_weak_memory = true; |
| 45 | +module_param_named(weak_memory, kcsan_weak_memory, bool, 0644); |
| 46 | +#else |
| 47 | +#define kcsan_weak_memory false |
| 48 | +#endif |
| 49 | + |
| 43 | 50 | bool kcsan_enabled; |
| 44 | 51 | |
| 45 | 52 | /* Per-CPU kcsan_ctx for interrupts */ |
| @@ -351,6 +358,67 @@ void kcsan_restore_irqtrace(struct task_struct *task) · 305 unmodified lines |
| 351 | 358 | #endif |
| 352 | 359 | } |
| 353 | 360 | |
| 361 | +static __always_inline int get_kcsan_stack_depth(void) |
| 362 | +{ |
| 363 | +#ifdef CONFIG_KCSAN_WEAK_MEMORY |
| 364 | + return current->kcsan_stack_depth; |
| 365 | +#else |
| 366 | + BUILD_BUG(); |
| 367 | + return 0; |
| 368 | +#endif |
| 369 | +} |
| 370 | + |
| 371 | +static __always_inline void add_kcsan_stack_depth(int val) |
| 372 | +{ |
| 373 | +#ifdef CONFIG_KCSAN_WEAK_MEMORY |
| 374 | + current->kcsan_stack_depth += val; |
| 375 | +#else |
| 376 | + BUILD_BUG(); |
| 377 | +#endif |
| 378 | +} |
| 379 | + |
| 380 | +static __always_inline struct kcsan_scoped_access *get_reorder_access(struct kcsan_ctx *ctx) |
| 381 | +{ |
| 382 | +#ifdef CONFIG_KCSAN_WEAK_MEMORY |
| 383 | + return ctx->disable_scoped ? NULL : &ctx->reorder_access; |
| 384 | +#else |
| 385 | + return NULL; |
| 386 | +#endif |
| 387 | +} |
| 388 | + |
| 389 | +static __always_inline bool |
| 390 | +find_reorder_access(struct kcsan_ctx *ctx, const volatile void *ptr, size_t size, |
| 391 | + int type, unsigned long ip) |
| 392 | +{ |
| 393 | + struct kcsan_scoped_access *reorder_access = get_reorder_access(ctx); |
| 394 | + |
| 395 | + if (!reorder_access) |
| 396 | + return false; |
| 397 | + |
| 398 | + /* |
| 399 | + * Note: If accesses are repeated while reorder_access is identical, |
| 400 | + * never matches the new access, because !(type & KCSAN_ACCESS_SCOPED). |
| 401 | + */ |
| 402 | + return reorder_access->ptr == ptr && reorder_access->size == size && |
| 403 | + reorder_access->type == type && reorder_access->ip == ip; |
| 404 | +} |
| 405 | + |
| 406 | +static inline void |
| 407 | +set_reorder_access(struct kcsan_ctx *ctx, const volatile void *ptr, size_t size, |
| 408 | + int type, unsigned long ip) |
| 409 | +{ |
| 410 | + struct kcsan_scoped_access *reorder_access = get_reorder_access(ctx); |
| 411 | + |
| 412 | + if (!reorder_access || !kcsan_weak_memory) |
| 413 | + return; |
| 414 | + |
| 415 | + reorder_access->ptr = ptr; |
| 416 | + reorder_access->size = size; |
| 417 | + reorder_access->type = type | KCSAN_ACCESS_SCOPED; |
| 418 | + reorder_access->ip = ip; |
| 419 | + reorder_access->stack_depth = get_kcsan_stack_depth(); |
| 420 | +} |
| 421 | + |
| 354 | 422 | /* |
| 355 | 423 | * Pull everything together: check_access() below contains the performance |
| 356 | 424 | * critical operations; the fast-path (including check_access) functions should |
| @@ -389,8 +457,10 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr, · 32 unmodified lines |
| 389 | 457 | * The access_mask check relies on value-change comparison. To avoid |
| 390 | 458 | * reporting a race where e.g. the writer set up the watchpoint, but the |
| 391 | 459 | * reader has access_mask!=0, we have to ignore the found watchpoint. |
| 460 | + * |
| 461 | + * reorder_access is never created from an access with access_mask set. |
| 392 | 462 | */ |
| 393 | | − if (ctx->access_mask) |
| 463 | + if (ctx->access_mask && !find_reorder_access(ctx, ptr, size, type, ip)) |
| 394 | 464 | return; |
| 395 | 465 | |
| 396 | 466 | /* |
| @@ -440,11 +510,13 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 43 unmodified lines |
| 440 | 510 | const bool is_assert = (type & KCSAN_ACCESS_ASSERT) != 0; |
| 441 | 511 | atomic_long_t *watchpoint; |
| 442 | 512 | u64 old, new, diff; |
| 443 | | − unsigned long access_mask; |
| 444 | 513 | enum kcsan_value_change value_change = KCSAN_VALUE_CHANGE_MAYBE; |
| 514 | + bool interrupt_watcher = kcsan_interrupt_watcher; |
| 445 | 515 | unsigned long ua_flags = user_access_save(); |
| 446 | 516 | struct kcsan_ctx *ctx = get_ctx(); |
| 517 | + unsigned long access_mask = ctx->access_mask; |
| 447 | 518 | unsigned long irq_flags = 0; |
| 519 | + bool is_reorder_access; |
| 448 | 520 | |
| 449 | 521 | /* |
| 450 | 522 | * Always reset kcsan_skip counter in slow-path to avoid underflow; see |
| @@ -467,6 +539,17 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 16 unmodified lines |
| 467 | 539 | goto out; |
| 468 | 540 | } |
| 469 | 541 | |
| 542 | + /* |
| 543 | + * The local CPU cannot observe reordering of its own accesses, and |
| 544 | + * therefore we need to take care of 2 cases to avoid false positives: |
| 545 | + * |
| 546 | + * 1. Races of the reordered access with interrupts. To avoid, if |
| 547 | + * the current access is reorder_access, disable interrupts. |
| 548 | + * 2. Avoid races of scoped accesses from nested interrupts (below). |
| 549 | + */ |
| 550 | + is_reorder_access = find_reorder_access(ctx, ptr, size, type, ip); |
| 551 | + if (is_reorder_access) |
| 552 | + interrupt_watcher = false; |
| 470 | 553 | /* |
| 471 | 554 | * Avoid races of scoped accesses from nested interrupts (or scheduler). |
| 472 | 555 | * Assume setting up a watchpoint for a non-scoped (normal) access that |
| @@ -482,7 +565,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 9 unmodified lines |
| 482 | 565 | * information is lost if dirtied by KCSAN. |
| 483 | 566 | */ |
| 484 | 567 | kcsan_save_irqtrace(current); |
| 485 | | − if (!kcsan_interrupt_watcher) |
| 568 | + if (!interrupt_watcher) |
| 486 | 569 | local_irq_save(irq_flags); |
| 487 | 570 | |
| 488 | 571 | watchpoint = insert_watchpoint((unsigned long)ptr, size, is_write); |
| @@ -503,7 +586,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 14 unmodified lines |
| 503 | 586 | * Read the current value, to later check and infer a race if the data |
| 504 | 587 | * was modified via a non-instrumented access, e.g. from a device. |
| 505 | 588 | */ |
| 506 | | − old = read_instrumented_memory(ptr, size); |
| 589 | + old = is_reorder_access ? 0 : read_instrumented_memory(ptr, size); |
| 507 | 590 | |
| 508 | 591 | /* |
| 509 | 592 | * Delay this thread, to increase probability of observing a racy |
| @@ -515,8 +598,17 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 5 unmodified lines |
| 515 | 598 | * Re-read value, and check if it is as expected; if not, we infer a |
| 516 | 599 | * racy access. |
| 517 | 600 | */ |
| 518 | | − access_mask = ctx->access_mask; |
| 519 | | − new = read_instrumented_memory(ptr, size); |
| 601 | + if (!is_reorder_access) { |
| 602 | + new = read_instrumented_memory(ptr, size); |
| 603 | + } else { |
| 604 | + /* |
| 605 | + * Reordered accesses cannot be used for value change detection, |
| 606 | + * because the memory location may no longer be accessible and |
| 607 | + * could result in a fault. |
| 608 | + */ |
| 609 | + new = 0; |
| 610 | + access_mask = 0; |
| 611 | + } |
| 520 | 612 | |
| 521 | 613 | diff = old ^ new; |
| 522 | 614 | if (access_mask) |
| @@ -585,11 +677,20 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 62 unmodified lines |
| 585 | 677 | */ |
| 586 | 678 | remove_watchpoint(watchpoint); |
| 587 | 679 | atomic_long_dec(&kcsan_counters[KCSAN_COUNTER_USED_WATCHPOINTS]); |
| 680 | + |
| 588 | 681 | out_unlock: |
| 589 | | − if (!kcsan_interrupt_watcher) |
| 682 | + if (!interrupt_watcher) |
| 590 | 683 | local_irq_restore(irq_flags); |
| 591 | 684 | kcsan_restore_irqtrace(current); |
| 592 | 685 | ctx->disable_scoped--; |
| 686 | + |
| 687 | + /* |
| 688 | + * Reordered accesses cannot be used for value change detection, |
| 689 | + * therefore never consider for reordering if access_mask is set. |
| 690 | + * ASSERT_EXCLUSIVE are not real accesses, ignore them as well. |
| 691 | + */ |
| 692 | + if (!access_mask && !is_assert) |
| 693 | + set_reorder_access(ctx, ptr, size, type, ip); |
| 593 | 694 | out: |
| 594 | 695 | user_access_restore(ua_flags); |
| 595 | 696 | } |
| @@ -597,7 +698,6 @@ out: · 1 unmodified line |
| 597 | 698 | static __always_inline void |
| 598 | 699 | check_access(const volatile void *ptr, size_t size, int type, unsigned long ip) |
| 599 | 700 | { |
| 600 | | − const bool is_write = (type & KCSAN_ACCESS_WRITE) != 0; |
| 601 | 701 | atomic_long_t *watchpoint; |
| 602 | 702 | long encoded_watchpoint; |
| 603 | 703 | |
| @@ -608,12 +708,14 @@ check_access(const volatile void *ptr, size_t size, int type, unsigned long ip) · 4 unmodified lines |
| 608 | 708 | if (unlikely(size == 0)) |
| 609 | 709 | return; |
| 610 | 710 | |
| 711 | +again: |
| 611 | 712 | /* |
| 612 | 713 | * Avoid user_access_save in fast-path: find_watchpoint is safe without |
| 613 | 714 | * user_access_save, as the address that ptr points to is only used to |
| 614 | 715 | * check if a watchpoint exists; ptr is never dereferenced. |
| 615 | 716 | */ |
| 616 | | − watchpoint = find_watchpoint((unsigned long)ptr, size, !is_write, |
| 717 | + watchpoint = find_watchpoint((unsigned long)ptr, size, |
| 718 | + !(type & KCSAN_ACCESS_WRITE), |
| 617 | 719 | &encoded_watchpoint); |
| 618 | 720 | /* |
| 619 | 721 | * It is safe to check kcsan_is_enabled() after find_watchpoint in the |
| @@ -627,9 +729,42 @@ check_access(const volatile void *ptr, size_t size, int type, unsigned long ip) · 7 unmodified lines |
| 627 | 729 | else { |
| 628 | 730 | struct kcsan_ctx *ctx = get_ctx(); /* Call only once in fast-path. */ |
| 629 | 731 | |
| 630 | | − if (unlikely(should_watch(ctx, ptr, size, type))) |
| 732 | + if (unlikely(should_watch(ctx, ptr, size, type))) { |
| 631 | 733 | kcsan_setup_watchpoint(ptr, size, type, ip); |
| 632 | | − else if (unlikely(ctx->scoped_accesses.prev)) |
| 734 | + return; |
| 735 | + } |
| 736 | + |
| 737 | + if (!(type & KCSAN_ACCESS_SCOPED)) { |
| 738 | + struct kcsan_scoped_access *reorder_access = get_reorder_access(ctx); |
| 739 | + |
| 740 | + if (reorder_access) { |
| 741 | + /* |
| 742 | + * reorder_access check: simulates reordering of |
| 743 | + * the access after subsequent operations. |
| 744 | + */ |
| 745 | + ptr = reorder_access->ptr; |
| 746 | + type = reorder_access->type; |
| 747 | + ip = reorder_access->ip; |
| 748 | + /* |
| 749 | + * Upon a nested interrupt, this context's |
| 750 | + * reorder_access can be modified (shared ctx). |
| 751 | + * We know that upon return, reorder_access is |
| 752 | + * always invalidated by setting size to 0 via |
| 753 | + * __tsan_func_exit(). Therefore we must read |
| 754 | + * and check size after the other fields. |
| 755 | + */ |
| 756 | + barrier(); |
| 757 | + size = READ_ONCE(reorder_access->size); |
| 758 | + if (size) |
| 759 | + goto again; |
| 760 | + } |
| 761 | + } |
| 762 | + |
| 763 | + /* |
| 764 | + * Always checked last, right before returning from runtime; |
| 765 | + * if reorder_access is valid, checked after it was checked. |
| 766 | + */ |
| 767 | + if (unlikely(ctx->scoped_accesses.prev)) |
| 633 | 768 | kcsan_check_scoped_accesses(); |
| 634 | 769 | } |
| 635 | 770 | } |
| @@ -916,19 +1051,56 @@ DEFINE_TSAN_VOLATILE_READ_WRITE(8); · 280 unmodified lines |
| 916 | 1051 | DEFINE_TSAN_VOLATILE_READ_WRITE(16); |
| 917 | 1052 | |
| 918 | 1053 | /* |
| 919 | | − * The below are not required by KCSAN, but can still be emitted by the |
| 920 | | − * compiler. |
| 1054 | + * Function entry and exit are used to determine the validty of reorder_access. |
| 1055 | + * Reordering of the access ends at the end of the function scope where the |
| 1056 | + * access happened. This is done for two reasons: |
| 1057 | + * |
| 1058 | + * 1. Artificially limits the scope where missing barriers are detected. |
| 1059 | + * This minimizes false positives due to uninstrumented functions that |
| 1060 | + * contain the required barriers but were missed. |
| 1061 | + * |
| 1062 | + * 2. Simplifies generating the stack trace of the access. |
| 921 | 1063 | */ |
| 922 | 1064 | void __tsan_func_entry(void *call_pc); |
| 923 | | −void __tsan_func_entry(void *call_pc) |
| 1065 | +noinline void __tsan_func_entry(void *call_pc) |
| 924 | 1066 | { |
| 1067 | + if (!IS_ENABLED(CONFIG_KCSAN_WEAK_MEMORY)) |
| 1068 | + return; |
| 1069 | + |
| 1070 | + add_kcsan_stack_depth(1); |
| 925 | 1071 | } |
| 926 | 1072 | EXPORT_SYMBOL(__tsan_func_entry); |
| 1073 | + |
| 927 | 1074 | void __tsan_func_exit(void); |
| 928 | | −void __tsan_func_exit(void) |
| 1075 | +noinline void __tsan_func_exit(void) |
| 929 | 1076 | { |
| 1077 | + struct kcsan_scoped_access *reorder_access; |
| 1078 | + |
| 1079 | + if (!IS_ENABLED(CONFIG_KCSAN_WEAK_MEMORY)) |
| 1080 | + return; |
| 1081 | + |
| 1082 | + reorder_access = get_reorder_access(get_ctx()); |
| 1083 | + if (!reorder_access) |
| 1084 | + goto out; |
| 1085 | + |
| 1086 | + if (get_kcsan_stack_depth() <= reorder_access->stack_depth) { |
| 1087 | + /* |
| 1088 | + * Access check to catch cases where write without a barrier |
| 1089 | + * (supposed release) was last access in function: because |
| 1090 | + * instrumentation is inserted before the real access, a data |
| 1091 | + * race due to the write giving up a c-s would only be caught if |
| 1092 | + * we do the conflicting access after. |
| 1093 | + */ |
| 1094 | + check_access(reorder_access->ptr, reorder_access->size, |
| 1095 | + reorder_access->type, reorder_access->ip); |
| 1096 | + reorder_access->size = 0; |
| 1097 | + reorder_access->stack_depth = INT_MIN; |
| 1098 | + } |
| 1099 | +out: |
| 1100 | + add_kcsan_stack_depth(-1); |
| 930 | 1101 | } |
| 931 | 1102 | EXPORT_SYMBOL(__tsan_func_exit); |
| 1103 | + |
| 932 | 1104 | void __tsan_init(void); |
| 933 | 1105 | void __tsan_init(void) |
| 934 | 1106 | { |