Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6f5a30c authored by Will Deacon's avatar Will Deacon Committed by Russell King
Browse files

ARM: 7356/1: perf: check that we have an event in the PMU IRQ handlers



The PMU IRQ handlers in perf assume that if a counter has overflowed
then perf must be responsible. In the paranoid world of crazy hardware,
this could be false, so check that we do have a valid event before
attempting to dereference NULL in the interrupt path.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarMing Lei <tom.leiming@gmail.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 99c1745b
Loading
Loading
Loading
Loading
+2 −18
Original line number Diff line number Diff line
@@ -467,23 +467,6 @@ armv6pmu_enable_event(struct hw_perf_event *hwc,
	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}

static int counter_is_active(unsigned long pmcr, int idx)
{
	unsigned long mask = 0;
	if (idx == ARMV6_CYCLE_COUNTER)
		mask = ARMV6_PMCR_CCOUNT_IEN;
	else if (idx == ARMV6_COUNTER0)
		mask = ARMV6_PMCR_COUNT0_IEN;
	else if (idx == ARMV6_COUNTER1)
		mask = ARMV6_PMCR_COUNT1_IEN;

	if (mask)
		return pmcr & mask;

	WARN_ONCE(1, "invalid counter number (%d)\n", idx);
	return 0;
}

static irqreturn_t
armv6pmu_handle_irq(int irq_num,
		    void *dev)
@@ -513,7 +496,8 @@ armv6pmu_handle_irq(int irq_num,
		struct perf_event *event = cpuc->events[idx];
		struct hw_perf_event *hwc;

		if (!counter_is_active(pmcr, idx))
		/* Ignore if we don't have an event. */
		if (!event)
			continue;

		/*
+4 −0
Original line number Diff line number Diff line
@@ -960,6 +960,10 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
		struct perf_event *event = cpuc->events[idx];
		struct hw_perf_event *hwc;

		/* Ignore if we don't have an event. */
		if (!event)
			continue;

		/*
		 * We have a single interrupt for all counters. Check that
		 * each counter has overflowed before we process it.
+6 −0
Original line number Diff line number Diff line
@@ -255,6 +255,9 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
		struct perf_event *event = cpuc->events[idx];
		struct hw_perf_event *hwc;

		if (!event)
			continue;

		if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
			continue;

@@ -592,6 +595,9 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
		struct perf_event *event = cpuc->events[idx];
		struct hw_perf_event *hwc;

		if (!event)
			continue;

		if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
			continue;