Technical Root Cause Analysis
1. Functions, Structs, and Fields Involved
- Files:
lib/timerqueue.c, include/linux/rbtree.h, kernel/time/hrtimer.c
- Functions:
timerqueue_linked_add(), rb_add_linked(), __rb_add(), __tq_linked_less()
- Structs & Fields:
struct timerqueue_linked_node: contains struct rb_node_linked node and ktime_t expires
struct timerqueue_linked_head: contains struct rb_root_linked rb_root
struct hrtimer: embeds struct timerqueue_linked_node node
struct hrtimer_clock_base: holds struct timerqueue_linked_head active
2. Crash Mechanism & Invariant Violation
The crash report flags a KASAN use-after-free read of size 8 at address ffffc90003947c00:
3. Reason for Call Trace Truncation & Secondary Crash
The reported call trace abruptly terminates after timerqueue_linked_add+0x365/0x430:
Call Trace:
<IRQ>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0x13d/0x4b0 mm/kasan/report.c:482
kasan_report+0xdf/0x1c0 mm/kasan/report.c:595
__tq_linked_less lib/timerqueue.c:91 [inline]
__rb_add include/linux/rbtree.h:231 [inline]
rb_add_linked include/linux/rbtree.h:281 [inline]
timerqueue_linked_add+0x365/0x430 lib/timerqueue.c:96
BUG: IRQ stack guard page was hit at ffffc900006f0ff8 (stack is ffffc900006f1000..ffffc900006f9000)
- When
__tq_linked_less() triggered the KASAN check in IRQ context, kasan_report() called print_report() -> print_address_description() (mm/kasan/report.c:378), which immediately calls dump_stack_lvl(KERN_ERR) before printing any object descriptions.
- The unwinder in
dump_stack_lvl() began printing frames from current RSP up through timerqueue_linked_add.
- The 32 KB per-CPU IRQ stack (
ffffc900006f1000..ffffc900006f9000) was already nearly exhausted before timerqueue_linked_add() was reached. The additional stack frames consumed by the KASAN reporting and stack-unwinding machinery pushed RSP down to ffffc900006f0ff8 (8 bytes below the bottom of the IRQ stack).
- Pushing to
ffffc900006f0ff8 hit the unmapped IRQ stack guard page, triggering a double fault (#DF). Handled on the IST exception stack by handle_stack_overflow() (arch/x86/kernel/traps.c:547), the kernel emitted BUG: IRQ stack guard page was hit at ffffc900006f0ff8 and panicked immediately.
- Consequently, the unwinder could not finish dumping the caller of
timerqueue_linked_add() or the subsequent KASAN allocation/free history, leaving the external caller that allocated and prematurely freed the on-stack struct hrtimer unrecorded in the report. Investigation of kernel/time/hrtimer.c confirmed that internal enqueue/dequeue logic in enqueue_hrtimer() and remove_and_enqueue_same_base() properly manages the tree and holding cpu_base->lock.