[PATCH 1/1] drivers/perf: Fix kernel panic due to the invalid mon_ctx pointer
Shanker Donthineni
sdonthineni at nvidia.com
Thu Oct 26 07:29:30 PDT 2023
The return pointer from the resctrl_arch_mon_ctx_alloc_no_wait() function
is saved in a 32-bit variable 'hwc->idx,' which results in the loss of
the upper 32 bits. This, in turn, triggers a kernel panic when attempting
to access a corrupted pointer.
This patch addresses the issue by utilizing the IDR data structure to
keep track of a 32-bit value associated with a pointer (64-bit value).
Signed-off-by: Shanker Donthineni <sdonthineni at nvidia.com>
---
drivers/perf/resctrl_pmu.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/perf/resctrl_pmu.c b/drivers/perf/resctrl_pmu.c
index 99a2b90b5d83..68cda619da48 100644
--- a/drivers/perf/resctrl_pmu.c
+++ b/drivers/perf/resctrl_pmu.c
@@ -6,6 +6,8 @@
#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/resctrl.h>
+#include <linux/mutex.h>
+#include <linux/idr.h>
struct resctrl_pmu {
struct pmu pmu;
@@ -25,6 +27,9 @@ RESCTRL_PMU_EVENT_ATTR_EXTRACTOR(event, config, 0, 7);
RESCTRL_PMU_EVENT_ATTR_EXTRACTOR(domain, config, 16, 23);
RESCTRL_PMU_EVENT_ATTR_EXTRACTOR(resctrl_id, config1, 0, 63);
+static DEFINE_MUTEX(resctrl_pmu_lock);
+static DEFINE_IDR(resctrl_pmu_idr);
+
static void resctrl_pmu_do_nothing(struct pmu *pmu)
{
}
@@ -69,12 +74,17 @@ static void resctrl_pmu_event_destroy(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw;
u16 event_num = get_event(event);
struct rdt_resource *r;
+ void *mon_ctx;
r = resctrl_event_get_resource(event_num);
if (!r)
return;
- resctrl_arch_mon_ctx_free(r, event_num, hwc->idx);
+ mutex_lock(&resctrl_pmu_lock);
+ mon_ctx = idr_remove(&resctrl_pmu_idr, hwc->idx);
+ mutex_unlock(&resctrl_pmu_lock);
+
+ resctrl_arch_mon_ctx_free(r, event_num, mon_ctx);
}
static int resctrl_pmu_event_init(struct perf_event *event)
@@ -87,6 +97,7 @@ static int resctrl_pmu_event_init(struct perf_event *event)
struct rdt_domain *d;
u16 event_num, domain_id;
u32 closid, rmid;
+ void *mon_ctx;
int err;
u64 id;
@@ -144,7 +155,12 @@ static int resctrl_pmu_event_init(struct perf_event *event)
return -EINVAL;
}
- hwc->idx = resctrl_arch_mon_ctx_alloc_no_wait(r, event_num);
+ mon_ctx = resctrl_arch_mon_ctx_alloc_no_wait(r, event_num);
+
+ mutex_lock(&resctrl_pmu_lock);
+ hwc->idx = idr_alloc(&resctrl_pmu_idr, mon_ctx, 0, INT_MAX, GFP_KERNEL);
+ mutex_unlock(&resctrl_pmu_lock);
+
if (hwc->idx == -ENOSPC)
return -ENOSPC;
event->destroy = resctrl_pmu_event_destroy;
@@ -162,6 +178,7 @@ static void resctrl_pmu_event_update(struct perf_event *event)
struct rdt_resource *r;
struct rdt_domain *d;
u32 closid, rmid;
+ void *mon_ctx;
int err;
event_num = get_event(event);
@@ -179,11 +196,15 @@ static void resctrl_pmu_event_update(struct perf_event *event)
if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask))
return;
+ mutex_lock(&resctrl_pmu_lock);
+ mon_ctx = idr_find(&resctrl_pmu_idr, hwc->idx);
+ mutex_unlock(&resctrl_pmu_lock);
+
do {
prev = local64_read(&hwc->prev_count);
err = resctrl_arch_rmid_read(r, d, closid, rmid,
- event_num, &now, hwc->idx);
+ event_num, &now, mon_ctx);
if (err)
return;
} while (local64_cmpxchg(&hwc->prev_count, prev, now) != prev);
--
2.25.1
More information about the linux-arm-kernel
mailing list