Skip to content

Commit a0db36e

Browse files
committed
Merge tag 'irq-urgent-2024-05-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq fixes from Ingo Molnar: - Fix x86 IRQ vector leak caused by a CPU offlining race - Fix build failure in the riscv-imsic irqchip driver caused by an API-change semantic conflict - Fix use-after-free in irq_find_at_or_after() * tag 'irq-urgent-2024-05-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: genirq/irqdesc: Prevent use-after-free in irq_find_at_or_after() genirq/cpuhotplug, x86/vector: Prevent vector leak during CPU offline irqchip/riscv-imsic: Fixup riscv_ipi_set_virq_range() conflict
2 parents 3a390f2 + b84a8ab commit a0db36e

File tree

3 files changed

+18
-12
lines changed

3 files changed

+18
-12
lines changed

arch/x86/kernel/apic/vector.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,8 @@ static void __vector_schedule_cleanup(struct apic_chip_data *apicd)
10351035
add_timer_on(&cl->timer, cpu);
10361036
}
10371037
} else {
1038-
apicd->prev_vector = 0;
1038+
pr_warn("IRQ %u schedule cleanup for offline CPU %u\n", apicd->irq, cpu);
1039+
free_moved_vector(apicd);
10391040
}
10401041
raw_spin_unlock(&vector_lock);
10411042
}
@@ -1072,6 +1073,7 @@ void irq_complete_move(struct irq_cfg *cfg)
10721073
*/
10731074
void irq_force_complete_move(struct irq_desc *desc)
10741075
{
1076+
unsigned int cpu = smp_processor_id();
10751077
struct apic_chip_data *apicd;
10761078
struct irq_data *irqd;
10771079
unsigned int vector;
@@ -1096,10 +1098,11 @@ void irq_force_complete_move(struct irq_desc *desc)
10961098
goto unlock;
10971099

10981100
/*
1099-
* If prev_vector is empty, no action required.
1101+
* If prev_vector is empty or the descriptor is neither currently
1102+
* nor previously on the outgoing CPU no action required.
11001103
*/
11011104
vector = apicd->prev_vector;
1102-
if (!vector)
1105+
if (!vector || (apicd->cpu != cpu && apicd->prev_cpu != cpu))
11031106
goto unlock;
11041107

11051108
/*

kernel/irq/cpuhotplug.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ static bool migrate_one_irq(struct irq_desc *desc)
6969
return false;
7070
}
7171

72+
/*
73+
* Complete an eventually pending irq move cleanup. If this
74+
* interrupt was moved in hard irq context, then the vectors need
75+
* to be cleaned up. It can't wait until this interrupt actually
76+
* happens and this CPU was involved.
77+
*/
78+
irq_force_complete_move(desc);
79+
7280
/*
7381
* No move required, if:
7482
* - Interrupt is per cpu
@@ -87,14 +95,6 @@ static bool migrate_one_irq(struct irq_desc *desc)
8795
return false;
8896
}
8997

90-
/*
91-
* Complete an eventually pending irq move cleanup. If this
92-
* interrupt was moved in hard irq context, then the vectors need
93-
* to be cleaned up. It can't wait until this interrupt actually
94-
* happens and this CPU was involved.
95-
*/
96-
irq_force_complete_move(desc);
97-
9898
/*
9999
* If there is a setaffinity pending, then try to reuse the pending
100100
* mask, so the last change of the affinity does not get lost. If

kernel/irq/irqdesc.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,10 @@ static int irq_find_free_area(unsigned int from, unsigned int cnt)
160160
static unsigned int irq_find_at_or_after(unsigned int offset)
161161
{
162162
unsigned long index = offset;
163-
struct irq_desc *desc = mt_find(&sparse_irqs, &index, nr_irqs);
163+
struct irq_desc *desc;
164+
165+
guard(rcu)();
166+
desc = mt_find(&sparse_irqs, &index, nr_irqs);
164167

165168
return desc ? irq_desc_get_irq(desc) : nr_irqs;
166169
}

0 commit comments

Comments
 (0)