From 203592a0390a38f65c5ca941c389ca470d73eeeb Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 19 May 2017 10:51:55 -0700 Subject: [PATCH] kernel - Fix excessive call stack depth on stuck interrupt * Fix an issue where a stuck level interrupt can result in an excessively deep call-stack and possible panic. * Fixed by disallow thread preemption when curthread->td_nest_count is >= 2. The critical section count test is not sufficient for the fast-interrupt unpend -> preemption case. --- sys/kern/kern_intr.c | 10 ++-------- sys/kern/lwkt_thread.c | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index f012ac4edd..d53e48882a 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -673,22 +673,16 @@ ithread_livelock_wakeup(systimer_t st, int in_ipi __unused, /* * Schedule ithread within fast intr handler * - * XXX Protect sched_ithd_hard() call with gd_intr_nesting_level? - * Interrupts aren't enabled, but still... + * Temporarily bump the current thread's td_nest_count to prevent deep + * preemptions and splz/doreti stacks. */ static __inline void ithread_fast_sched(int intr, thread_t td) { ++td->td_nest_count; - - /* - * We are already in critical section, exit it now to - * allow preemption. - */ crit_exit_quick(td); sched_ithd_hard(intr); crit_enter_quick(td); - --td->td_nest_count; } diff --git a/sys/kern/lwkt_thread.c b/sys/kern/lwkt_thread.c index 46faf9a76d..079bfb9d73 100644 --- a/sys/kern/lwkt_thread.c +++ b/sys/kern/lwkt_thread.c @@ -857,10 +857,15 @@ lwkt_switch_return(thread_t otd) /* * Request that the target thread preempt the current thread. Preemption - * can only occur if our only critical section is the one that we were called - * with, the relative priority of the target thread is higher, and the target - * thread holds no tokens. This also only works if we are not holding any - * spinlocks (obviously). + * can only occur only: + * + * - If our critical section is the one that we were called with + * - The relative priority of the target thread is higher + * - The target is not excessively interrupt-nested via td_nest_count + * - The target thread holds no tokens. + * - The target thread is not already scheduled and belongs to the + * current cpu. + * - The current thread is not holding any spin-locks. * * THE CALLER OF LWKT_PREEMPT() MUST BE IN A CRITICAL SECTION. Typically * this is called via lwkt_schedule() through the td_preemptable callback. @@ -911,6 +916,10 @@ lwkt_preempt(thread_t ntd, int critcount) ++preempt_miss; return; } + if (td->td_nest_count >= 2) { + ++preempt_miss; + return; + } if (td->td_cscount) { ++preempt_miss; return; -- 2.11.4.GIT