debugobject: Prevent init race with static objects

Statically initialized objects are usually not initialized via the init()
function of the subsystem. They are special cased and the subsystem
provides a function to validate whether an object which is not yet tracked
by debugobjects is statically initialized. This means the object is started
to be tracked on first use, e.g. activation.

This works perfectly fine, unless there are two concurrent operations on
that object. Schspa decoded the problem:

T0 T1

debug_object_assert_init(addr)
lock_hash_bucket()
obj = lookup_object(addr);
if (!obj) {
unlock_hash_bucket();
- > preemption
lock_subsytem_object(addr);
activate_object(addr)
lock_hash_bucket();
obj = lookup_object(addr);
if (!obj) {
unlock_hash_bucket();
if (is_static_object(addr))
init_and_track(addr);
lock_hash_bucket();
obj = lookup_object(addr);
obj->state = ACTIVATED;
unlock_hash_bucket();

subsys function modifies content of addr,
so static object detection does
not longer work.

unlock_subsytem_object(addr);

if (is_static_object(addr)) <- Fails

debugobject emits a warning and invokes the fixup function which
reinitializes the already active object in the worst case.

This race exists forever, but was never observed until mod_timer() got a
debug_object_assert_init() added which is outside of the timer base lock
held section right at the beginning of the function to cover the lockless
early exit points too.

Rework the code so that the lookup, the static object check and the
tracking object association happens atomically under the hash bucket
lock. This prevents the issue completely as all callers are serialized on
the hash bucket lock and therefore cannot observe inconsistent state.

Fixes: 3ac7fe5a4aab ("infrastructure to debug (dynamic) objects")
Reported-by: syzbot+5093ba19745994288b53@syzkaller.appspotmail.com
Debugged-by: Schspa Shi <schspa@gmail.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://syzkaller.appspot.com/bug?id=22c8a5938eab640d1c6bcc0e3dc7be519d878462
Link: https://lore.kernel.org/lkml/20230303161906.831686-1-schspa@gmail.com
Link: https://lore.kernel.org/r/87zg7dzgao.ffs@tglx

Changed files
+66 -59
lib
+66 -59
lib/debugobjects.c
··· 216 216 return obj; 217 217 } 218 218 219 - /* 220 - * Allocate a new object. If the pool is empty, switch off the debugger. 221 - * Must be called with interrupts disabled. 222 - */ 223 219 static struct debug_obj * 224 220 alloc_object(void *addr, struct debug_bucket *b, const struct debug_obj_descr *descr) 225 221 { ··· 548 552 WARN_ON(1); 549 553 } 550 554 555 + static struct debug_obj *lookup_object_or_alloc(void *addr, struct debug_bucket *b, 556 + const struct debug_obj_descr *descr, 557 + bool onstack, bool alloc_ifstatic) 558 + { 559 + struct debug_obj *obj = lookup_object(addr, b); 560 + enum debug_obj_state state = ODEBUG_STATE_NONE; 561 + 562 + if (likely(obj)) 563 + return obj; 564 + 565 + /* 566 + * debug_object_init() unconditionally allocates untracked 567 + * objects. It does not matter whether it is a static object or 568 + * not. 569 + * 570 + * debug_object_assert_init() and debug_object_activate() allow 571 + * allocation only if the descriptor callback confirms that the 572 + * object is static and considered initialized. For non-static 573 + * objects the allocation needs to be done from the fixup callback. 574 + */ 575 + if (unlikely(alloc_ifstatic)) { 576 + if (!descr->is_static_object || !descr->is_static_object(addr)) 577 + return ERR_PTR(-ENOENT); 578 + /* Statically allocated objects are considered initialized */ 579 + state = ODEBUG_STATE_INIT; 580 + } 581 + 582 + obj = alloc_object(addr, b, descr); 583 + if (likely(obj)) { 584 + obj->state = state; 585 + debug_object_is_on_stack(addr, onstack); 586 + return obj; 587 + } 588 + 589 + /* Out of memory. Do the cleanup outside of the locked region */ 590 + debug_objects_enabled = 0; 591 + return NULL; 592 + } 593 + 551 594 static void 552 595 __debug_object_init(void *addr, const struct debug_obj_descr *descr, int onstack) 553 596 { 554 597 enum debug_obj_state state; 555 - bool check_stack = false; 556 598 struct debug_bucket *db; 557 599 struct debug_obj *obj; 558 600 unsigned long flags; ··· 606 572 607 573 raw_spin_lock_irqsave(&db->lock, flags); 608 574 609 - obj = lookup_object(addr, db); 610 - if (!obj) { 611 - obj = alloc_object(addr, db, descr); 612 - if (!obj) { 613 - debug_objects_enabled = 0; 614 - raw_spin_unlock_irqrestore(&db->lock, flags); 615 - debug_objects_oom(); 616 - return; 617 - } 618 - check_stack = true; 575 + obj = lookup_object_or_alloc(addr, db, descr, onstack, false); 576 + if (unlikely(!obj)) { 577 + raw_spin_unlock_irqrestore(&db->lock, flags); 578 + debug_objects_oom(); 579 + return; 619 580 } 620 581 621 582 switch (obj->state) { ··· 636 607 } 637 608 638 609 raw_spin_unlock_irqrestore(&db->lock, flags); 639 - if (check_stack) 640 - debug_object_is_on_stack(addr, onstack); 641 610 } 642 611 643 612 /** ··· 675 648 */ 676 649 int debug_object_activate(void *addr, const struct debug_obj_descr *descr) 677 650 { 651 + struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; 678 652 enum debug_obj_state state; 679 653 struct debug_bucket *db; 680 654 struct debug_obj *obj; 681 655 unsigned long flags; 682 656 int ret; 683 - struct debug_obj o = { .object = addr, 684 - .state = ODEBUG_STATE_NOTAVAILABLE, 685 - .descr = descr }; 686 657 687 658 if (!debug_objects_enabled) 688 659 return 0; ··· 689 664 690 665 raw_spin_lock_irqsave(&db->lock, flags); 691 666 692 - obj = lookup_object(addr, db); 693 - if (obj) { 667 + obj = lookup_object_or_alloc(addr, db, descr, false, true); 668 + if (likely(!IS_ERR_OR_NULL(obj))) { 694 669 bool print_object = false; 695 670 696 671 switch (obj->state) { ··· 723 698 724 699 raw_spin_unlock_irqrestore(&db->lock, flags); 725 700 726 - /* 727 - * We are here when a static object is activated. We 728 - * let the type specific code confirm whether this is 729 - * true or not. if true, we just make sure that the 730 - * static object is tracked in the object tracker. If 731 - * not, this must be a bug, so we try to fix it up. 732 - */ 733 - if (descr->is_static_object && descr->is_static_object(addr)) { 734 - /* track this static object */ 735 - debug_object_init(addr, descr); 736 - debug_object_activate(addr, descr); 737 - } else { 738 - debug_print_object(&o, "activate"); 739 - ret = debug_object_fixup(descr->fixup_activate, addr, 740 - ODEBUG_STATE_NOTAVAILABLE); 741 - return ret ? 0 : -EINVAL; 701 + /* If NULL the allocation has hit OOM */ 702 + if (!obj) { 703 + debug_objects_oom(); 704 + return 0; 742 705 } 743 - return 0; 706 + 707 + /* Object is neither static nor tracked. It's not initialized */ 708 + debug_print_object(&o, "activate"); 709 + ret = debug_object_fixup(descr->fixup_activate, addr, ODEBUG_STATE_NOTAVAILABLE); 710 + return ret ? 0 : -EINVAL; 744 711 } 745 712 EXPORT_SYMBOL_GPL(debug_object_activate); 746 713 ··· 886 869 */ 887 870 void debug_object_assert_init(void *addr, const struct debug_obj_descr *descr) 888 871 { 872 + struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; 889 873 struct debug_bucket *db; 890 874 struct debug_obj *obj; 891 875 unsigned long flags; ··· 897 879 db = get_bucket((unsigned long) addr); 898 880 899 881 raw_spin_lock_irqsave(&db->lock, flags); 882 + obj = lookup_object_or_alloc(addr, db, descr, false, true); 883 + raw_spin_unlock_irqrestore(&db->lock, flags); 884 + if (likely(!IS_ERR_OR_NULL(obj))) 885 + return; 900 886 901 - obj = lookup_object(addr, db); 887 + /* If NULL the allocation has hit OOM */ 902 888 if (!obj) { 903 - struct debug_obj o = { .object = addr, 904 - .state = ODEBUG_STATE_NOTAVAILABLE, 905 - .descr = descr }; 906 - 907 - raw_spin_unlock_irqrestore(&db->lock, flags); 908 - /* 909 - * Maybe the object is static, and we let the type specific 910 - * code confirm. Track this static object if true, else invoke 911 - * fixup. 912 - */ 913 - if (descr->is_static_object && descr->is_static_object(addr)) { 914 - /* Track this static object */ 915 - debug_object_init(addr, descr); 916 - } else { 917 - debug_print_object(&o, "assert_init"); 918 - debug_object_fixup(descr->fixup_assert_init, addr, 919 - ODEBUG_STATE_NOTAVAILABLE); 920 - } 889 + debug_objects_oom(); 921 890 return; 922 891 } 923 892 924 - raw_spin_unlock_irqrestore(&db->lock, flags); 893 + /* Object is neither tracked nor static. It's not initialized. */ 894 + debug_print_object(&o, "assert_init"); 895 + debug_object_fixup(descr->fixup_assert_init, addr, ODEBUG_STATE_NOTAVAILABLE); 925 896 } 926 897 EXPORT_SYMBOL_GPL(debug_object_assert_init); 927 898