From: Greg Kroah-Hartman Date: Tue, 20 Jan 2015 07:38:28 +0000 (+0800) Subject: 3.14-stable patches X-Git-Tag: v3.10.66~43 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=446770db374eb19ff00d206740349dfb0882d5db;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: genirq-prevent-proc-race-against-freeing-of-irq-descriptors.patch --- diff --git a/queue-3.14/genirq-prevent-proc-race-against-freeing-of-irq-descriptors.patch b/queue-3.14/genirq-prevent-proc-race-against-freeing-of-irq-descriptors.patch new file mode 100644 index 00000000000..23e896a8671 --- /dev/null +++ b/queue-3.14/genirq-prevent-proc-race-against-freeing-of-irq-descriptors.patch @@ -0,0 +1,229 @@ +From c291ee622165cb2c8d4e7af63fffd499354a23be Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 11 Dec 2014 23:01:41 +0100 +Subject: genirq: Prevent proc race against freeing of irq descriptors + +From: Thomas Gleixner + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + fs/proc/stat.c | 2 - + include/linux/kernel_stat.h | 1 + kernel/irq/internals.h | 8 ++++++ + kernel/irq/irqdesc.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ + kernel/irq/proc.c | 22 +++++++++++++++++- + 5 files changed, 83 insertions(+), 2 deletions(-) + +--- a/fs/proc/stat.c ++++ b/fs/proc/stat.c +@@ -159,7 +159,7 @@ static int show_stat(struct seq_file *p, + + /* sum again ? it could be updated? */ + for_each_irq_nr(j) +- seq_put_decimal_ull(p, ' ', kstat_irqs(j)); ++ seq_put_decimal_ull(p, ' ', kstat_irqs_usr(j)); + + seq_printf(p, + "\nctxt %llu\n" +--- a/include/linux/kernel_stat.h ++++ b/include/linux/kernel_stat.h +@@ -74,6 +74,7 @@ static inline unsigned int kstat_softirq + * Number of interrupts per specific IRQ source, since bootup + */ + extern unsigned int kstat_irqs(unsigned int irq); ++extern unsigned int kstat_irqs_usr(unsigned int irq); + + /* + * Number of interrupts per cpu, since bootup +--- a/kernel/irq/internals.h ++++ b/kernel/irq/internals.h +@@ -74,6 +74,14 @@ extern void irq_percpu_disable(struct ir + extern void mask_irq(struct irq_desc *desc); + extern void unmask_irq(struct irq_desc *desc); + ++#ifdef CONFIG_SPARSE_IRQ ++extern void irq_lock_sparse(void); ++extern void irq_unlock_sparse(void); ++#else ++static inline void irq_lock_sparse(void) { } ++static inline void irq_unlock_sparse(void) { } ++#endif ++ + extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); + + irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action); +--- a/kernel/irq/irqdesc.c ++++ b/kernel/irq/irqdesc.c +@@ -131,6 +131,16 @@ static void free_masks(struct irq_desc * + static inline void free_masks(struct irq_desc *desc) { } + #endif + ++void irq_lock_sparse(void) ++{ ++ mutex_lock(&sparse_irq_lock); ++} ++ ++void irq_unlock_sparse(void) ++{ ++ mutex_unlock(&sparse_irq_lock); ++} ++ + static struct irq_desc *alloc_desc(int irq, int node, struct module *owner) + { + struct irq_desc *desc; +@@ -167,6 +177,12 @@ static void free_desc(unsigned int irq) + + unregister_irq_proc(irq, desc); + ++ /* ++ * sparse_irq_lock protects also show_interrupts() and ++ * kstat_irq_usr(). Once we deleted the descriptor from the ++ * sparse tree we can free it. Access in proc will fail to ++ * lookup the descriptor. ++ */ + mutex_lock(&sparse_irq_lock); + delete_irq_desc(irq); + mutex_unlock(&sparse_irq_lock); +@@ -489,6 +505,15 @@ void dynamic_irq_cleanup(unsigned int ir + raw_spin_unlock_irqrestore(&desc->lock, flags); + } + ++/** ++ * kstat_irqs_cpu - Get the statistics for an interrupt on a cpu ++ * @irq: The interrupt number ++ * @cpu: The cpu number ++ * ++ * Returns the sum of interrupt counts on @cpu since boot for ++ * @irq. The caller must ensure that the interrupt is not removed ++ * concurrently. ++ */ + unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) + { + struct irq_desc *desc = irq_to_desc(irq); +@@ -497,6 +522,14 @@ unsigned int kstat_irqs_cpu(unsigned int + *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; + } + ++/** ++ * kstat_irqs - Get the statistics for an interrupt ++ * @irq: The interrupt number ++ * ++ * Returns the sum of interrupt counts on all cpus since boot for ++ * @irq. The caller must ensure that the interrupt is not removed ++ * concurrently. ++ */ + unsigned int kstat_irqs(unsigned int irq) + { + struct irq_desc *desc = irq_to_desc(irq); +@@ -509,3 +542,22 @@ unsigned int kstat_irqs(unsigned int irq + sum += *per_cpu_ptr(desc->kstat_irqs, cpu); + return sum; + } ++ ++/** ++ * kstat_irqs_usr - Get the statistics for an interrupt ++ * @irq: The interrupt number ++ * ++ * Returns the sum of interrupt counts on all cpus since boot for ++ * @irq. Contrary to kstat_irqs() this can be called from any ++ * preemptible context. It's protected against concurrent removal of ++ * an interrupt descriptor when sparse irqs are enabled. ++ */ ++unsigned int kstat_irqs_usr(unsigned int irq) ++{ ++ int sum; ++ ++ irq_lock_sparse(); ++ sum = kstat_irqs(irq); ++ irq_unlock_sparse(); ++ return sum; ++} +--- a/kernel/irq/proc.c ++++ b/kernel/irq/proc.c +@@ -15,6 +15,23 @@ + + #include "internals.h" + ++/* ++ * Access rules: ++ * ++ * procfs protects read/write of /proc/irq/N/ files against a ++ * concurrent free of the interrupt descriptor. remove_proc_entry() ++ * immediately prevents new read/writes to happen and waits for ++ * already running read/write functions to complete. ++ * ++ * We remove the proc entries first and then delete the interrupt ++ * descriptor from the radix tree and free it. So it is guaranteed ++ * that irq_to_desc(N) is valid as long as the read/writes are ++ * permitted by procfs. ++ * ++ * The read from /proc/interrupts is a different problem because there ++ * is no protection. So the lookup and the access to irqdesc ++ * information must be protected by sparse_irq_lock. ++ */ + static struct proc_dir_entry *root_irq_dir; + + #ifdef CONFIG_SMP +@@ -437,9 +454,10 @@ int show_interrupts(struct seq_file *p, + seq_putc(p, '\n'); + } + ++ irq_lock_sparse(); + desc = irq_to_desc(i); + if (!desc) +- return 0; ++ goto outsparse; + + raw_spin_lock_irqsave(&desc->lock, flags); + for_each_online_cpu(j) +@@ -479,6 +497,8 @@ int show_interrupts(struct seq_file *p, + seq_putc(p, '\n'); + out: + raw_spin_unlock_irqrestore(&desc->lock, flags); ++outsparse: ++ irq_unlock_sparse(); + return 0; + } + #endif diff --git a/queue-3.14/series b/queue-3.14/series index 6e29095891a..c18696e1559 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -32,3 +32,4 @@ cfg80211-fix-160-mhz-channels-with-80-80-and-160-mhz-drivers.patch rtlwifi-rtl8192ce-set-fw_ready-flag.patch hp_accel-add-support-for-hp-zbook-15.patch tick-powerclamp-remove-tick_nohz_idle-abuse.patch +genirq-prevent-proc-race-against-freeing-of-irq-descriptors.patch