| From 715bd9d12f84d8f5cc8ad21d888f9bc304a8eb0b Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@kernel.org> |
| Date: Mon, 1 Oct 2018 12:52:15 -0700 |
| Subject: x86/vdso: Fix asm constraints on vDSO syscall fallbacks |
| |
| From: Andy Lutomirski <luto@kernel.org> |
| |
| commit 715bd9d12f84d8f5cc8ad21d888f9bc304a8eb0b upstream. |
| |
| The syscall fallbacks in the vDSO have incorrect asm constraints. |
| They are not marked as writing to their outputs -- instead, they are |
| marked as clobbering "memory", which is useless. In particular, gcc |
| is smart enough to know that the timespec parameter hasn't escaped, |
| so a memory clobber doesn't clobber it. And passing a pointer as an |
| asm *input* does not tell gcc that the pointed-to value is changed. |
| |
| Add in the fact that the asm instructions weren't volatile, and gcc |
| was free to omit them entirely unless their sole output (the return |
| value) is used. Which it is (phew!), but that stops happening with |
| some upcoming patches. |
| |
| As a trivial example, the following code: |
| |
| void test_fallback(struct timespec *ts) |
| { |
| vdso_fallback_gettime(CLOCK_MONOTONIC, ts); |
| } |
| |
| compiles to: |
| |
| 00000000000000c0 <test_fallback>: |
| c0: c3 retq |
| |
| To add insult to injury, the RCX and R11 clobbers on 64-bit |
| builds were missing. |
| |
| The "memory" clobber is also unnecessary -- no ordering with respect to |
| other memory operations is needed, but that's going to be fixed in a |
| separate not-for-stable patch. |
| |
| Fixes: 2aae950b21e4 ("x86_64: Add vDSO for x86-64 with gettimeofday/clock_gettime/getcpu") |
| Signed-off-by: Andy Lutomirski <luto@kernel.org> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: stable@vger.kernel.org |
| Link: https://lkml.kernel.org/r/2c0231690551989d2fafa60ed0e7b5cc8b403908.1538422295.git.luto@kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/entry/vdso/vclock_gettime.c | 18 ++++++++++-------- |
| 1 file changed, 10 insertions(+), 8 deletions(-) |
| |
| --- a/arch/x86/entry/vdso/vclock_gettime.c |
| +++ b/arch/x86/entry/vdso/vclock_gettime.c |
| @@ -37,8 +37,9 @@ extern u8 pvclock_page |
| notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) |
| { |
| long ret; |
| - asm("syscall" : "=a" (ret) : |
| - "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory"); |
| + asm ("syscall" : "=a" (ret), "=m" (*ts) : |
| + "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : |
| + "memory", "rcx", "r11"); |
| return ret; |
| } |
| |
| @@ -46,8 +47,9 @@ notrace static long vdso_fallback_gtod(s |
| { |
| long ret; |
| |
| - asm("syscall" : "=a" (ret) : |
| - "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory"); |
| + asm ("syscall" : "=a" (ret), "=m" (*tv), "=m" (*tz) : |
| + "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : |
| + "memory", "rcx", "r11"); |
| return ret; |
| } |
| |
| @@ -58,12 +60,12 @@ notrace static long vdso_fallback_gettim |
| { |
| long ret; |
| |
| - asm( |
| + asm ( |
| "mov %%ebx, %%edx \n" |
| "mov %2, %%ebx \n" |
| "call __kernel_vsyscall \n" |
| "mov %%edx, %%ebx \n" |
| - : "=a" (ret) |
| + : "=a" (ret), "=m" (*ts) |
| : "0" (__NR_clock_gettime), "g" (clock), "c" (ts) |
| : "memory", "edx"); |
| return ret; |
| @@ -73,12 +75,12 @@ notrace static long vdso_fallback_gtod(s |
| { |
| long ret; |
| |
| - asm( |
| + asm ( |
| "mov %%ebx, %%edx \n" |
| "mov %2, %%ebx \n" |
| "call __kernel_vsyscall \n" |
| "mov %%edx, %%ebx \n" |
| - : "=a" (ret) |
| + : "=a" (ret), "=m" (*tv), "=m" (*tz) |
| : "0" (__NR_gettimeofday), "g" (tv), "c" (tz) |
| : "memory", "edx"); |
| return ret; |