aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-12-11 23:01:41 +0100
committerZefan Li <lizefan@huawei.com>2015-04-14 17:33:46 +0800
commit0d030473658c7760c4cdd4fd0cc61e287b6023b3 (patch)
tree0e66b9c5b5a6760e43c38bb8899fb2964bf5deba /include
parent81cc271d2c4a179aae41c503562af9e11ce94adc (diff)
genirq: Prevent proc race against freeing of irq descriptors
commit c291ee622165cb2c8d4e7af63fffd499354a23be upstream. Since the rework of the sparse interrupt code to actually free the unused interrupt descriptors there exists a race between the /proc interfaces to the irq subsystem and the code which frees the interrupt descriptor. CPU0 CPU1 show_interrupts() desc = irq_to_desc(X); free_desc(desc) remove_from_radix_tree(); kfree(desc); raw_spinlock_irq(&desc->lock); /proc/interrupts is the only interface which can actively corrupt kernel memory via the lock access. /proc/stat can only read from freed memory. Extremly hard to trigger, but possible. The interfaces in /proc/irq/N/ are not affected by this because the removal of the proc file is serialized in procfs against concurrent readers/writers. The removal happens before the descriptor is freed. For architectures which have CONFIG_SPARSE_IRQ=n this is a non issue as the descriptor is never freed. It's merely cleared out with the irq descriptor lock held. So any concurrent proc access will either see the old correct value or the cleared out ones. Protect the lookup and access to the irq descriptor in show_interrupts() with the sparse_irq_lock. Provide kstat_irqs_usr() which is protecting the lookup and access with sparse_irq_lock and switch /proc/stat to use it. Document the existing kstat_irqs interfaces so it's clear that the caller needs to take care about protection. The users of these interfaces are either not affected due to SPARSE_IRQ=n or already protected against removal. Fixes: 1f5a5b87f78f "genirq: Implement a sane sparse_irq allocator" Signed-off-by: Thomas Gleixner <tglx@linutronix.de> [lizf: Backported to 3.4: - define kstat_irqs() for CONFIG_GENERIC_HARDIRQS - add ifdef/endif CONFIG_SPARSE_IRQ] Signed-off-by: Zefan Li <lizefan@huawei.com>
Diffstat (limited to 'include')
-rw-r--r--include/linux/kernel_stat.h5
1 files changed, 5 insertions, 0 deletions
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index 2fbd9053c2df..8e62498eeab3 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -104,8 +104,13 @@ static inline unsigned int kstat_irqs(unsigned int irq)
return sum;
}
+static inline unsigned int kstat_irqs_usr(unsigned int irq)
+{
+ return kstat_irqs(irq);
+}
#else
extern unsigned int kstat_irqs(unsigned int irq);
+extern unsigned int kstat_irqs_usr(unsigned int irq);
#endif
/*