Re: [PATCH] selftests/proc: Add support for vsyscall=xonly

From: Shigeru Yoshida
Date: Sat Aug 13 2022 - 11:23:02 EST


ping?

On Sat, 6 Aug 2022 22:57:49 +0900, Shigeru Yoshida wrote:
> There are 3 vsyscall modes: emulate, xonly, and none. proc-pid-vm
> detects the existence of the vsyscall with memory load on the vsyscall
> page.
>
> This works for emulate and none vsyscall modes, but fails for xonly
> because read permission is omitted with xonly vsyscall page, and it
> results in the following error:
>
> # ./proc-pid-vm
> proc-pid-vm: proc-pid-vm.c:328: main: Assertion `rv == len' failed.
> Aborted (core dumped)
>
> This patch fixes this issue with introducing the following rule:
>
> 1. vsyscall mode is emulate if it can load memory
> 2. vsyscall mode is xonly if it can call gettimeofday() on vsyscall
> 3. vsyscall mode is node otherwise
>
> Signed-off-by: Shigeru Yoshida <syoshida@xxxxxxxxxx>
> ---
> tools/testing/selftests/proc/proc-pid-vm.c | 77 ++++++++++++++++++----
> 1 file changed, 65 insertions(+), 12 deletions(-)
>
> diff --git a/tools/testing/selftests/proc/proc-pid-vm.c b/tools/testing/selftests/proc/proc-pid-vm.c
> index 28604c9f805c..dffd263beef3 100644
> --- a/tools/testing/selftests/proc/proc-pid-vm.c
> +++ b/tools/testing/selftests/proc/proc-pid-vm.c
> @@ -211,10 +211,16 @@ static int make_exe(const uint8_t *payload, size_t len)
> }
> #endif
>
> -static bool g_vsyscall = false;
> -
> -static const char str_vsyscall[] =
> -"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";
> +static enum { EMULATE, XONLY, NONE } g_vsyscall_mode;
> +
> +static const char * const str_vsyscall[] = {
> + /* emulate */
> + "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n",
> + /* xonly */
> + "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n",
> + /* none */
> + "",
> +};
>
> #ifdef __x86_64__
> static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___)
> @@ -225,7 +231,33 @@ static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___)
> /*
> * vsyscall page can't be unmapped, probe it with memory load.
> */
> -static void vsyscall(void)
> +static bool vsyscall_emulate(void)
> +{
> + *(volatile int *)0xffffffffff600000UL;
> + return true;
> +}
> +
> +/*
> + * vsyscall page can't be unmapped, probe it with calling gettimeofday().
> + */
> +static bool vsyscall_xonly(void)
> +{
> + int ret;
> + struct timeval tv;
> + int (*f)(struct timeval *tv, struct timezone *tz);
> +
> + /* Try to call gettimeofday() on vsyscall*/
> + f = (void *)0xffffffffff600000UL;
> + ret = f(&tv, NULL);
> + if (ret < 0) {
> + fprintf(stderr, "gettimeofday() on vsyscall, ret %d\n", ret);
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool vsyscall_test(bool (*test)(void))
> {
> pid_t pid;
> int wstatus;
> @@ -246,13 +278,27 @@ static void vsyscall(void)
> act.sa_sigaction = sigaction_SIGSEGV;
> (void)sigaction(SIGSEGV, &act, NULL);
>
> - *(volatile int *)0xffffffffff600000UL;
> + if (!test())
> + exit(1);
> +
> exit(0);
> }
> waitpid(pid, &wstatus, 0);
> if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) {
> - g_vsyscall = true;
> + return true;
> }
> +
> + return false;
> +}
> +
> +static void vsyscall(void)
> +{
> + if (vsyscall_test(vsyscall_emulate))
> + g_vsyscall_mode = EMULATE;
> + else if (vsyscall_test(vsyscall_xonly))
> + g_vsyscall_mode = XONLY;
> + else
> + g_vsyscall_mode = NONE;
> }
>
> int main(void)
> @@ -314,11 +360,14 @@ int main(void)
>
> /* Test /proc/$PID/maps */
> {
> - const size_t len = strlen(buf0) + (g_vsyscall ? strlen(str_vsyscall) : 0);
> + size_t len = strlen(buf0);
> char buf[256];
> ssize_t rv;
> int fd;
>
> + if (g_vsyscall_mode != NONE)
> + len += strlen(str_vsyscall[g_vsyscall_mode]);
> +
> snprintf(buf, sizeof(buf), "/proc/%u/maps", pid);
> fd = open(buf, O_RDONLY);
> if (fd == -1) {
> @@ -327,8 +376,10 @@ int main(void)
> rv = read(fd, buf, sizeof(buf));
> assert(rv == len);
> assert(memcmp(buf, buf0, strlen(buf0)) == 0);
> - if (g_vsyscall) {
> - assert(memcmp(buf + strlen(buf0), str_vsyscall, strlen(str_vsyscall)) == 0);
> + if (g_vsyscall_mode != NONE) {
> + assert(memcmp(buf + strlen(buf0),
> + str_vsyscall[g_vsyscall_mode],
> + strlen(str_vsyscall[g_vsyscall_mode])) == 0);
> }
> }
>
> @@ -374,8 +425,10 @@ int main(void)
> assert(memmem(buf, rv, S[i], strlen(S[i])));
> }
>
> - if (g_vsyscall) {
> - assert(memmem(buf, rv, str_vsyscall, strlen(str_vsyscall)));
> + if (g_vsyscall_mode != NONE) {
> + assert(memmem(buf, rv,
> + str_vsyscall[g_vsyscall_mode],
> + strlen(str_vsyscall[g_vsyscall_mode])));
> }
> }
>
> --
> 2.37.1
>