DivestOS/Patches/Linux_CVEs/CVE-2016-3768/ANY/0001.patch
2017-11-07 17:32:46 -05:00

91 lines
3.3 KiB
Diff

From d75be03af111fb5a31eba82f665242e6d8b07008 Mon Sep 17 00:00:00 2001
From: Arun KS <arunks@codeaurora.org>
Date: Wed, 11 May 2016 10:11:36 +0530
Subject: msm: perf: Do not allocate new hw_event if event is duplicate.
During a perf_event_enable, kernel/events/core.c calls pmu->add() which
is platform implementation(arch/arm/kernel/perf_event.c). Due to the
duplicate constraints, arch/arm/mach-msm/perf_event_msm_krait_l2.c
drivers marks the event as OFF but returns TRUE to perf_event.c which
goes ahead and allocates the hw_event and enables it.
Since event is marked OFF, kernel events core will try to enable this event
again during next perf_event_enable. Which results in same event enabled
on multiple hw_events. But during the perf_release, event struct is freed
and only one hw_event is released. This results in dereferencing the
invalid pointer and hence the crash.
Fix this by returning error in case of constraint event duplicate. Hence
avoiding the same event programmed on multiple hw event counters.
Change-Id: Ia3360be027dfe87ac753191ffe7e0bc947e72455
Signed-off-by: Arun KS <arunks@codeaurora.org>
---
arch/arm/kernel/perf_event.c | 1 +
arch/arm/mach-msm/perf_event_msm_krait_l2.c | 1 +
arch/arm/mach-msm/perf_event_msm_l2.c | 4 +++-
kernel/events/core.c | 7 -------
4 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 1541a80..a1264ac 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -308,6 +308,7 @@ armpmu_add(struct perf_event *event, int flags)
pr_err("Event: %llx failed constraint check.\n",
event->attr.config);
event->state = PERF_EVENT_STATE_OFF;
+ err = -EPERM;
goto out;
}
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index d816794..57f82d0 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -463,6 +463,7 @@ static int msm_l2_test_set_ev_constraint(struct perf_event *event)
if (!(event->cpu < 0)) {
event->state = PERF_EVENT_STATE_OFF;
event->attr.constraint_duplicate = 1;
+ err = -EPERM;
}
}
out:
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
index f78487a..93695e2 100644
--- a/arch/arm/mach-msm/perf_event_msm_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -836,8 +836,10 @@ static int msm_l2_test_set_ev_constraint(struct perf_event *event)
* This sets the event OFF on all but one
* CPU.
*/
- if (!(event->cpu < 0))
+ if (!(event->cpu < 0)) {
event->state = PERF_EVENT_STATE_OFF;
+ err = -EPERM;
+ }
}
out:
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 33ad70a..7ebe09a 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -3030,13 +3030,6 @@ static void put_event(struct perf_event *event)
if (!atomic_long_dec_and_test(&event->refcount))
return;
- /*
- * Event can be in state OFF because of a constraint check.
- * Change to ACTIVE so that it gets cleaned up correctly.
- */
- if ((event->state == PERF_EVENT_STATE_OFF) &&
- event->attr.constraint_duplicate)
- event->state = PERF_EVENT_STATE_ACTIVE;
rcu_read_lock();
owner = ACCESS_ONCE(event->owner);
--
cgit v1.1