Interrupt recursion smashes kernel memory

Matthew Dillon dillon at apollo.backplane.com
Sun Jan 13 16:44:27 PST 2008


    Ok, it is definitely able to recurse.  Critical sections prevent
    interrupt recursion but also prevent thread preemption, so its a
    chicken and egg problem... I want to prevent interrupt recursion but
    ALLOW thread preemption when scheduling an interrupt thread from
    inside a slow interrupt.

    The slow interrupt code is STI'ing and calling sched_ithd() without
    a critical section held in order to allow it to preempt.  If it does
    preempt, however, the interrupt thread can run, unmask the interrupt,
    and recurse because interrupts are enabled prior to actually getting
    through the doreti.

    I can't use critical sections because those will disable the desired
    thread preemption along with preventing interrupt recursion.

    I can't use gd->intr_nesting_level because the trap code uses doreti
    and isn't expecting intr_nesting_level to be non-zero in most cases.

    I can't leave us CLI'd because, well, its just a bad idea to do that.

    I think the solution is to use TD_NEST_COUNT (curthread->td_nest_count)
    to prevent recursive interrupts from blowing up the stack.

    Please try this patch.

						-Matt

Index: platform/pc32/apic/apic_vector.s
===================================================================
RCS file: /cvs/src/sys/platform/pc32/apic/apic_vector.s,v
retrieving revision 1.36
diff -u -p -r1.36 apic_vector.s
--- platform/pc32/apic/apic_vector.s	22 Jan 2007 19:37:04 -0000	1.36
+++ platform/pc32/apic/apic_vector.s	14 Jan 2008 00:37:34 -0000
@@ -154,6 +154,8 @@ 	movl	$0, lapic_eoi ;						\
 	movl	PCPU(curthread),%ebx ;					\
 	movl	$0,%eax ;	/* CURRENT CPL IN FRAME (REMOVED) */	\
 	pushl	%eax ;							\
+	testl	$-1,TD_NEST_COUNT(%ebx) ;				\
+	jne	1f ;							\
 	cmpl	$TDPRI_CRIT,TD_PRI(%ebx) ;				\
 	jl	2f ;							\
 1: ;									\
@@ -208,6 +210,8 @@ 	movl	$0, lapic_eoi ;						\
 	movl	PCPU(curthread),%ebx ;					\
 	movl	$0,%eax ;	/* CURRENT CPL IN FRAME (REMOVED) */	\
 	pushl	%eax ;		/* cpl do restore */			\
+	testl	$-1,TD_NEST_COUNT(%ebx) ;				\
+	jne	1f ;							\
 	cmpl	$TDPRI_CRIT,TD_PRI(%ebx) ;				\
 	jl	2f ;							\
 1: ;									\
@@ -218,10 +222,13 @@ 	jmp	5f ;							\
 2: ;									\
 	/* set running bit, clear pending bit, run handler */		\
 	andl	$~IRQ_LBIT(irq_num), PCPU(ipending) ;			\
+	incl	TD_NEST_COUNT(%ebx) ;					\
 	sti ;								\
 	pushl	$irq_num ;						\
 	call	sched_ithd ;						\
 	addl	$4,%esp ;						\
+	cli ;								\
+	decl	TD_NEST_COUNT(%ebx) ;					\
 5: ;									\
 	MEXITCOUNT ;							\
 	jmp	doreti ;						\
Index: platform/pc32/icu/icu_vector.s
===================================================================
RCS file: /cvs/src/sys/platform/pc32/icu/icu_vector.s,v
retrieving revision 1.30
diff -u -p -r1.30 icu_vector.s
--- platform/pc32/icu/icu_vector.s	22 Jan 2007 19:37:04 -0000	1.30
+++ platform/pc32/icu/icu_vector.s	14 Jan 2008 00:38:37 -0000
@@ -144,6 +144,8 @@ 	MASK_IRQ(icu, irq_num) ;					\
 	enable_icus ;							\
 	movl	PCPU(curthread),%ebx ;					\
 	pushl	$0 ;			/* DUMMY CPL FOR DORETI */	\
+	testl	$-1,TD_NEST_COUNT(%ebx) ;				\
+	jne	1f ;							\
 	cmpl	$TDPRI_CRIT,TD_PRI(%ebx) ;				\
 	jl	2f ;							\
 1: ;									\
@@ -198,6 +200,8 @@ 	incl    PCPU(cnt) + V_INTR ;           
 	enable_icus ;							\
 	movl	PCPU(curthread),%ebx ;					\
 	pushl	$0 ;			/* DUMMY CPL FOR DORETI */	\
+	testl	$-1,TD_NEST_COUNT(%ebx) ;				\
+	jne	1f ;							\
 	cmpl	$TDPRI_CRIT,TD_PRI(%ebx) ;				\
 	jl	2f ;							\
 1: ;									\
@@ -208,10 +212,13 @@ 	jmp	5f ;							\
 2: ;									\
 	/* set running bit, clear pending bit, run handler */		\
 	andl	$~IRQ_LBIT(irq_num), PCPU(ipending) ;			\
+	incl	TD_NEST_COUNT(%ebx) ;					\
 	sti ;								\
 	pushl	$irq_num ;						\
 	call	sched_ithd ;						\
 	addl	$4,%esp ;						\
+	cli ;								\
+	decl	TD_NEST_COUNT(%ebx) ;					\
 5: ;									\
 	MEXITCOUNT ;							\
 	jmp	doreti ;						\





More information about the Kernel mailing list