proc: save LOC in vsyscall test

Do one fork in vsyscall detection code and let SIGSEGV handler exit and
carry information to the parent saving LOC.

[adobriyan@gmail.com: redo original patch, delete unnecessary variables, minimise code changes]
Link: https://lkml.kernel.org/r/YvoWzAn5dlhF75xa@localhost.localdomain
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Tested-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Brian Foster 2022-08-15 12:50:04 +03:00 committed by Andrew Morton
parent 4f1d2a030d
commit f4068af3a6

View File

@ -213,22 +213,22 @@ static int make_exe(const uint8_t *payload, size_t len)
/*
* 0: vsyscall VMA doesn't exist vsyscall=none
* 1: vsyscall VMA is r-xp vsyscall=emulate
* 2: vsyscall VMA is --xp vsyscall=xonly
* 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 *str_vsyscall;
static const char str_vsyscall_0[] = "";
static const char str_vsyscall_1[] =
"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";
static const char str_vsyscall_2[] =
"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n";
static const char str_vsyscall_2[] =
"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";
#ifdef __x86_64__
static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___)
{
_exit(1);
_exit(g_vsyscall);
}
/*
@ -255,6 +255,7 @@ static void vsyscall(void)
act.sa_sigaction = sigaction_SIGSEGV;
(void)sigaction(SIGSEGV, &act, NULL);
g_vsyscall = 0;
/* gettimeofday(NULL, NULL); */
asm volatile (
"call %P0"
@ -262,45 +263,20 @@ static void vsyscall(void)
: "i" (0xffffffffff600000), "D" (NULL), "S" (NULL)
: "rax", "rcx", "r11"
);
exit(0);
g_vsyscall = 1;
*(volatile int *)0xffffffffff600000UL;
g_vsyscall = 2;
exit(g_vsyscall);
}
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) {
/* vsyscall page exists and is executable. */
if (WIFEXITED(wstatus)) {
g_vsyscall = WEXITSTATUS(wstatus);
} else {
/* vsyscall page doesn't exist. */
g_vsyscall = 0;
return;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork, errno %d\n", errno);
fprintf(stderr, "error: wstatus %08x\n", wstatus);
exit(1);
}
if (pid == 0) {
struct rlimit rlim = {0, 0};
(void)setrlimit(RLIMIT_CORE, &rlim);
/* Hide "segfault at ffffffffff600000" messages. */
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = sigaction_SIGSEGV;
(void)sigaction(SIGSEGV, &act, NULL);
*(volatile int *)0xffffffffff600000UL;
exit(0);
}
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) {
/* vsyscall page is readable and executable. */
g_vsyscall = 1;
return;
}
/* vsyscall page is executable but unreadable. */
g_vsyscall = 2;
}
int main(void)