Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

x86/vdso: Prevent segfaults due to hoisted vclock reads

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 459e3a21535a ("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: Duncan Roe <duncan_roe@optusnet.com.au>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andy Lutomirski and committed by
Linus Torvalds
ff17bbe0 a4c33bbb

+13 -2
+13 -2
arch/x86/entry/vdso/vclock_gettime.c
··· 128 128 { 129 129 if (mode == VCLOCK_TSC) 130 130 return (u64)rdtsc_ordered(); 131 + 132 + /* 133 + * For any memory-mapped vclock type, we need to make sure that gcc 134 + * doesn't cleverly hoist a load before the mode check. Otherwise we 135 + * might end up touching the memory-mapped page even if the vclock in 136 + * question isn't enabled, which will segfault. Hence the barriers. 137 + */ 131 138 #ifdef CONFIG_PARAVIRT_CLOCK 132 - else if (mode == VCLOCK_PVCLOCK) 139 + if (mode == VCLOCK_PVCLOCK) { 140 + barrier(); 133 141 return vread_pvclock(); 142 + } 134 143 #endif 135 144 #ifdef CONFIG_HYPERV_TSCPAGE 136 - else if (mode == VCLOCK_HVCLOCK) 145 + if (mode == VCLOCK_HVCLOCK) { 146 + barrier(); 137 147 return vread_hvclock(); 148 + } 138 149 #endif 139 150 return U64_MAX; 140 151 }