Messages in this thread Patch in this message | | | From | kan.liang@linux ... | Subject | [PATCH] perf/x86: Reset the counter to prevent the leak for a RDPMC task | Date | Thu, 30 Jul 2020 05:38:15 -0700 |
| |
From: Kan Liang <kan.liang@linux.intel.com>
The counter value of a perf task may leak to another RDPMC task. For example, a perf stat task as below is running on CPU 0.
perf stat -e 'branches,cycles' -- taskset -c 0 ./workload
In the meantime, an RDPMC task, which is also running on CPU 0, may read the GP counters periodically. (The RDPMC task creates a fixed event, but read four GP counters.)
$ taskset -c 0 ./rdpmc_read_all_counters index 0x0 value 0x8001e5970f99 index 0x1 value 0x8005d750edb6 index 0x2 value 0x0 index 0x3 value 0x0
index 0x0 value 0x8002358e48a5 index 0x1 value 0x8006bd1e3bc9 index 0x2 value 0x0 index 0x3 value 0x0
The counter value of the perf stat task leaks to the RDPMC task because perf never clears the counter when it's stopped.
A counter/event stops for the following cases: - Schedule the monitored task, e.g., context switch or task exit; - Adjust the event period, e.g., Throttle, in frequency mode; - Update the event's address range filters.
For the first case, following tasks may reuse the counter. To prevent the leak, the counter has to be reset, when the event is scheduled out. The del() is eventually invoked for the schedule out. The counter should be reset in x86_pmu_del().
For the rest of the cases, the counter/event is temporarily stopped and will be restarted soon. Other tasks don't have a chance to reuse the counter. Reset the counter is not necessary.
The RDPMC instruction is only available for the X86 platform. Only apply the fix for the X86 platform.
After applying the patch,
$ taskset -c 0 ./rdpmc_read_all_counters index 0x0 value 0x0 index 0x1 value 0x0 index 0x2 value 0x0 index 0x3 value 0x0
index 0x0 value 0x0 index 0x1 value 0x0 index 0x2 value 0x0 index 0x3 value 0x0
Signed-off-by: Kan Liang <kan.liang@linux.intel.com> --- arch/x86/events/core.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 01ba5fec5765..72b2c7e1bb20 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1499,6 +1499,13 @@ static void x86_pmu_del(struct perf_event *event, int flags) */ x86_pmu_stop(event, PERF_EF_UPDATE); + /* + * The counter value may leak to an RDPMC task. + * Clear the counter if the userspace RDPMC usage is enabled. + */ + if (READ_ONCE(x86_pmu.attr_rdpmc)) + wrmsrl(event->hw.event_base, 0); + for (i = 0; i < cpuc->n_events; i++) { if (event == cpuc->event_list[i]) break; -- 2.17.1
| |