Fix loop logic in irq_alloc_virt()
PATCH 1/1 Fix loop logic in irq_alloc_virt()
There's a bug in irq_alloc_virt() if it's asked for more than 1 interrupt, if it can't find a slot it might look past the end of the irq_map.
I think this is a fix. No one in the kernel actually calls this with count > 1, so it's not critical.
---
arch/powerpc/kernel/irq.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
arch/powerpc/kernel/irq.c +10 -9
@@ -728,7 +728,6 @@ unsigned int irq_alloc_virt(struct irq_h {unsigned long flags;unsigned int i, j, found =NO_IRQ ; -unsigned int limit = irq_virq_count - count;if (count ==0 || count > (irq_virq_count -NUM_ISA_INTERRUPTS ))return NO_IRQ ;
@@ -745,14 +744,16 @@ unsigned int irq_alloc_virt(struct irq_h/* Look for count consecutive numbers in the allocatable * (non-legacy) space */ -for (i =NUM_ISA_INTERRUPTS ; i <= limit; ) { -for (j = i; j < (i + count); j++) -if (irq_map[j].host !=NULL ) { - i = j +1 ; -continue ; - } - found = i; -break ; +for (i =NUM_ISA_INTERRUPTS , j =0 ; i < irq_virq_count; i++) { +if (irq_map[i].host !=NULL ) + j =0 ; +else + j++; + +if (j == count) { + found = i - count +1 ; +break ; + } }if (found ==NO_IRQ ) {spin_unlock_irqrestore (&irq_big_lock, flags);
Quoted 12 lines · Michael Ellerman
There's a bug in
irq_alloc_virt()if it's asked for more than 1 interrupt, if it can't find a slot it might look past the end of theirq_map.I think this is a fix. No one in the kernel actually calls this with count > 1, so it's not critical.
Index:
to-merge/arch/powerpc/kernel/irq.c
===================================================================arch/powerpc/kernel/irq.c +0
-0@@ -745,14 +744,16 @@ unsigned int irq_alloc_virt(struct irq_h/* Look for count consecutive numbers in the allocatable
arch/powerpc/kernel/irq.c unsigned int irq_alloc_virt(struct irq_h · line 755
Quoted 10 lines
arch/powerpc/kernel/irq.c +0
-8* (non-legacy) space */ -for (i =NUM_ISA_INTERRUPTS ; i <= limit; ) { -for (j = i; j < (i + count); j++) -if (irq_map[j].host !=NULL ) { - i = j +1 ; -continue ; - } - found = i; -break ;
To be clear: the bug is that the continue affects the inner for loop, not the outer one, so i becomes j + 1 and then we continue the inner loop without checking if i is still <= limit.
cheers
Signature · 8 lines
Michael Ellerman IBM OzLabs wwweb: http://michael.ellerman.id.au phone: +61 2 6212 1183 (tie line 70 21183) We do not inherit the earth from our ancestors, we borrow it from our children. - S.M.A.R.T Person
Quoted 5 lines · Michael Ellerman
There's a bug in
irq_alloc_virt()if it's asked for more than 1 interrupt, if it can't find a slot it might look past the end of theirq_map.I think this is a fix. No one in the kernel actually calls this with count > 1, so it's not critical.
Good catch. /me stupid.
Quoted 1 line
Signed-off-by Michael Ellerman <[email protected]>
Quoted 42 lines
---
arch/powerpc/kernel/irq.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)Index:
to-merge/arch/powerpc/kernel/irq.c
===================================================================arch/powerpc/kernel/irq.c +10
-9@@ -728,7 +728,6 @@ unsigned int irq_alloc_virt(struct irq_h {unsigned long flags;unsigned int i, j, found =NO_IRQ ; -unsigned int limit = irq_virq_count - count;if (count ==0 || count > (irq_virq_count -NUM_ISA_INTERRUPTS ))return NO_IRQ ;@@ -745,14 +744,16 @@ unsigned int irq_alloc_virt(struct irq_h/* Look for count consecutive numbers in the allocatable * (non-legacy) space */ -for (i =NUM_ISA_INTERRUPTS ; i <= limit; ) { -for (j = i; j < (i + count); j++) -if (irq_map[j].host !=NULL ) { - i = j +1 ; -continue ; - } - found = i; -break ; +for (i =NUM_ISA_INTERRUPTS , j =0 ; i < irq_virq_count; i++) { +if (irq_map[i].host !=NULL ) + j =0 ; +else + j++; + +if (j == count) { + found = i - count +1 ; +break ; + } }if (found ==NO_IRQ ) {spin_unlock_irqrestore (&irq_big_lock, flags);