Hi,
On 06. 01. 2023. 20:30, Alexey Dobriyan wrote:
vsyscall detection code uses direct call to the beginning of the vsyscall page:
asm ("call %P0" :: "i" (0xffffffffff600000))
It generates "call rel32" instruction but it is not relocated if binary is PIE, so binary segfaults into random userspace address and vsyscall page status is detected incorrectly.
Do more direct:
asm ("call *%rax")
which doesn't do need any relocaltions.
Mark g_vsyscall as volatile for a good measure, I didn't find instruction setting it to 0. Now the code is obviously correct:
xor eax, eax mov rdi, rbp mov rsi, rbp mov DWORD PTR [rip+0x2d15], eax # g_vsyscall = 0 mov rax, 0xffffffffff600000 call rax mov DWORD PTR [rip+0x2d02], 1 # g_vsyscall = 1 mov eax, DWORD PTR ds:0xffffffffff600000 mov DWORD PTR [rip+0x2cf1], 2 # g_vsyscall = 2 mov edi, [rip+0x2ceb] # exit(g_vsyscall) call exit
Note: fixed proc-empty-vm test oopses 5.19.0-28-generic kernel but this is separate story.
Signed-off-by: Alexey Dobriyan adobriyan@gmail.com Reported-by: Mirsad Goran Todorovac mirsad.todorovac@alu.unizg.hr
tools/testing/selftests/proc/proc-empty-vm.c | 12 +++++++----- tools/testing/selftests/proc/proc-pid-vm.c | 9 +++++---- 2 files changed, 12 insertions(+), 9 deletions(-)
--- a/tools/testing/selftests/proc/proc-empty-vm.c +++ b/tools/testing/selftests/proc/proc-empty-vm.c @@ -25,6 +25,7 @@ #undef NDEBUG #include <assert.h> #include <errno.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -41,7 +42,7 @@
- 1: vsyscall VMA is --xp vsyscall=xonly
- 2: vsyscall VMA is r-xp vsyscall=emulate
*/ -static int g_vsyscall; +static volatile int g_vsyscall; static const char *g_proc_pid_maps_vsyscall; static const char *g_proc_pid_smaps_vsyscall; @@ -147,11 +148,12 @@ static void vsyscall(void) g_vsyscall = 0; /* gettimeofday(NULL, NULL); */
asm volatile (uint64_t rax = 0xffffffffff600000;
"call %P0"
:
: "i" (0xffffffffff600000), "D" (NULL), "S" (NULL)
nt> - : "rax", "rcx", "r11"
"call *%[rax]"
: [rax] "+a" (rax)
: "D" (NULL), "S" (NULL)
);: "rcx", "r11"
g_vsyscall = 1; --- a/tools/testing/selftests/proc/proc-pid-vm.c +++ b/tools/testing/selftests/proc/proc-pid-vm.c @@ -257,11 +257,12 @@ static void vsyscall(void) g_vsyscall = 0; /* gettimeofday(NULL, NULL); */
asm volatile (uint64_t rax = 0xffffffffff600000;
"call %P0"
:
: "i" (0xffffffffff600000), "D" (NULL), "S" (NULL)
: "rax", "rcx", "r11"
"call *%[rax]"
: [rax] "+a" (rax)
: "D" (NULL), "S" (NULL)
);: "rcx", "r11"
g_vsyscall = 1;
I can confirm that the patch fixed the core dump in the exact environment that used to reproduce the bug.
Apparently, it seems that gcc 12.2.0 -O2 optimiser on Ubuntu 22.10 kinetic kudu did some new creative stuff to Alexey's code. For someone interested, I have saved the assembly with and w/o -O2 ...
However, I have just found some spurious bug in proc-uptime-001.
But, this is another story ...
Thanks, Mirsad
-- Mirsad Goran Todorovac Sistem inženjer Grafički fakultet | Akademija likovnih umjetnosti Sveučilište u Zagrebu