Commit cf37b1a0 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Greg Kroah-Hartman

x86/vdso: Prevent segfaults due to hoisted vclock reads

commit ff17bbe0 upstream.

GCC 5.5.0 sometimes cleverly hoists reads of the pvclock and/or hvclock
pages before the vclock mode checks.  This creates a path through
vclock_gettime() in which no vclock is enabled at all (due to disabled
TSC on old CPUs, for example) but the pvclock or hvclock page
nevertheless read.  This will segfault on bare metal.

This fixes commit 459e3a21 ("gcc-9: properly declare the
{pv,hv}clock_page storage") in the sense that, before that commit, GCC
didn't seem to generate the offending code.  There was nothing wrong
with that commit per se, and -stable maintainers should backport this to
all supported kernels regardless of whether the offending commit was
present, since the same crash could just as easily be triggered by the
phase of the moon.

On GCC 9.1.1, this doesn't seem to affect the generated code at all, so
I'm not too concerned about performance regressions from this fix.

Cc: stable@vger.kernel.org
Cc: x86@kernel.org
Cc: Borislav Petkov <bp@alien8.de>
Reported-by: default avatarDuncan Roe <duncan_roe@optusnet.com.au>
Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent df2d3135
...@@ -128,13 +128,24 @@ notrace static inline u64 vgetcyc(int mode) ...@@ -128,13 +128,24 @@ notrace static inline u64 vgetcyc(int mode)
{ {
if (mode == VCLOCK_TSC) if (mode == VCLOCK_TSC)
return (u64)rdtsc_ordered(); return (u64)rdtsc_ordered();
/*
* For any memory-mapped vclock type, we need to make sure that gcc
* doesn't cleverly hoist a load before the mode check. Otherwise we
* might end up touching the memory-mapped page even if the vclock in
* question isn't enabled, which will segfault. Hence the barriers.
*/
#ifdef CONFIG_PARAVIRT_CLOCK #ifdef CONFIG_PARAVIRT_CLOCK
else if (mode == VCLOCK_PVCLOCK) if (mode == VCLOCK_PVCLOCK) {
barrier();
return vread_pvclock(); return vread_pvclock();
}
#endif #endif
#ifdef CONFIG_HYPERV_TSCPAGE #ifdef CONFIG_HYPERV_TSCPAGE
else if (mode == VCLOCK_HVCLOCK) if (mode == VCLOCK_HVCLOCK) {
barrier();
return vread_hvclock(); return vread_hvclock();
}
#endif #endif
return U64_MAX; return U64_MAX;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment