From: Charlie Jenkins <charlie@rivosinc.com>
To: zhouquan@iscas.ac.cn
Cc: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, oleg@redhat.com,
paul.walmsley@sifive.com, palmer@dabbelt.com,
aou@eecs.berkeley.edu, andy.chiu@sifive.com, shuah@kernel.org
Subject: Re: [RFC PATCH 2/2] riscv: selftests: Add a ptrace test to check a0 of restarted syscall
Date: Wed, 19 Jun 2024 19:55:01 -0700 [thread overview]
Message-ID: <ZnOaBeNnNpvrE5ss@ghost> (raw)
In-Reply-To: <b5fbdd3417e925dbe5db4716e51ce49d21d27f2f.1718693532.git.zhouquan@iscas.ac.cn>
On Wed, Jun 19, 2024 at 10:01:47AM +0800, zhouquan@iscas.ac.cn wrote:
> From: Quan Zhou <zhouquan@iscas.ac.cn>
>
> This test creates two processes: a tracer and a tracee. The tracer actively
> sends a SIGUSR1 signal in user mode to interrupt the read syscall being
> executed by the tracee. We will reset a0/orig_a0 and then observe the value
> of a0 held by the restarted read syscall.
I don't quite follow what the goal of this test is. With orig_a0 being
added to the previous patch for ptrace, a more constrained test could
ensure that this value is respected.
>
> Compared to the test program, a more common scenario is the use of the
> exece syscall, which sends a signal in the kernel path to restart
> the syscall.
>
> Signed-off-by: Quan Zhou <zhouquan@iscas.ac.cn>
> ---
> tools/testing/selftests/riscv/Makefile | 2 +-
> tools/testing/selftests/riscv/abi/.gitignore | 1 +
> tools/testing/selftests/riscv/abi/Makefile | 12 ++
> .../riscv/abi/ptrace_restart_syscall.c | 148 ++++++++++++++++++
> 4 files changed, 162 insertions(+), 1 deletion(-)
> create mode 100644 tools/testing/selftests/riscv/abi/.gitignore
> create mode 100644 tools/testing/selftests/riscv/abi/Makefile
> create mode 100644 tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c
>
> diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile
> index 7ce03d832b64..98541dc2f164 100644
> --- a/tools/testing/selftests/riscv/Makefile
> +++ b/tools/testing/selftests/riscv/Makefile
> @@ -5,7 +5,7 @@
> ARCH ?= $(shell uname -m 2>/dev/null || echo not)
>
> ifneq (,$(filter $(ARCH),riscv))
> -RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn
> +RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn abi
> else
> RISCV_SUBTARGETS :=
> endif
> diff --git a/tools/testing/selftests/riscv/abi/.gitignore b/tools/testing/selftests/riscv/abi/.gitignore
> new file mode 100644
> index 000000000000..e1e00ffb9db9
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/abi/.gitignore
> @@ -0,0 +1 @@
> +abi
The gitignore should contain a list of all of the generated binaries
that should be ignored. Can you put ptrace_restart_syscall in here
instead of abi?
> diff --git a/tools/testing/selftests/riscv/abi/Makefile b/tools/testing/selftests/riscv/abi/Makefile
> new file mode 100644
> index 000000000000..634fa7de74e6
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/abi/Makefile
> @@ -0,0 +1,12 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 ARM Limited
> +# Originally tools/testing/arm64/abi/Makefile
> +
> +CFLAGS += -I$(top_srcdir)/tools/include
> +
> +TEST_GEN_PROGS := ptrace_restart_syscall
> +
> +include ../../lib.mk
> +
> +$(OUTPUT)/ptrace_restart_syscall: ptrace_restart_syscall.c
> + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^
> diff --git a/tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c b/tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c
> new file mode 100644
> index 000000000000..3e25548cb95e
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c
> @@ -0,0 +1,148 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <errno.h>
> +#include <sys/types.h>
> +#include <sys/ptrace.h>
> +#include <sys/stat.h>
> +#include <sys/user.h>
> +#include <sys/wait.h>
> +#include <sys/uio.h>
> +#include <linux/elf.h>
> +#include <linux/unistd.h>
> +#include <asm/ptrace.h>
> +
> +#include "../../kselftest_harness.h"
> +
> +#define ORIG_A0_AFTER_MODIFIED 0x5
> +#define MODIFY_A0 0x01
> +#define MODIFY_ORIG_A0 0x02
> +
> +#define perr_and_exit(fmt, ...) do { \
> + char buf[256]; \
> + snprintf(buf, sizeof(buf), "%s:%d: " fmt ": %m\n", \
> + __func__, __LINE__, ##__VA_ARGS__); \
> + perror(buf); \
> + exit(-1); \
> +} while (0)
> +
> +static inline void resume_and_wait_tracee(pid_t pid, int flag)
> +{
> + int status;
> +
> + if (ptrace(flag, pid, 0, 0))
> + perr_and_exit("failed to resume the tracee %d", pid);
> +
> + if (waitpid(pid, &status, 0) != pid)
> + perr_and_exit("failed to wait for the tracee %d", pid);
> +}
> +
> +static void ptrace_restart_syscall(int opt, int *result)
> +{
> + int status;
> + int p[2], fd_zero;
> + pid_t pid;
> +
> + struct user_regs_struct regs;
> + struct iovec iov = {
> + .iov_base = ®s,
> + .iov_len = sizeof(regs),
> + };
> +
> + if (pipe(p))
> + perr_and_exit("failed to create a pipe");
> +
> + fd_zero = open("/dev/zero", O_RDONLY);
> + if (fd_zero < 0)
> + perr_and_exit("failed to open /dev/zero");
> +
> + pid = fork();
> + if (pid == 0) {
> + char c;
> +
> + /* Mark oneself being traced */
> + if (ptrace(PTRACE_TRACEME, 0, 0, 0))
> + perr_and_exit("failed to request for tracer to trace me");
> +
> + kill(getpid(), SIGSTOP);
> +
> + if (read(p[0], &c, 1) != 1)
> + exit(1);
> +
> + exit(0);
> + } else if (pid < 0)
> + exit(1);
> +
> + if (waitpid(pid, &status, 0) != pid)
> + perr_and_exit("failed to wait for the tracee %d\n", pid);
> +
> + /* Resume the tracee until the next syscall */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Deliver a signal to interrupt the syscall */
> + kill(pid, SIGUSR1);
> +
> + /* The tracee stops at syscall exit */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Check tracee orig_a0 before syscall restart */
> + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))
> + perr_and_exit("failed to get tracee registers");
> + if (regs.orig_a0 != p[0])
> + perr_and_exit("unexpected a0");
> +
> + /* Modify a0/orig_a0 for the restarted syscall */
> + switch (opt) {
> + case MODIFY_A0:
> + regs.a0 = fd_zero;
> + break;
> + case MODIFY_ORIG_A0:
> + regs.orig_a0 = fd_zero;
> + break;
> + }
> +
> + if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov))
> + perr_and_exit("failed to set tracee registers");
> +
> + /* Ignore SIGUSR1 signal */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Stop at the entry point of the restarted syscall */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Now, check regs.a0 of the restarted syscall */
> + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))
> + perr_and_exit("failed to get tracee registers");
> + *result = regs.a0;
> +
> + /* Resume the tracee */
> + ptrace(PTRACE_CONT, pid, 0, 0);
> + if (waitpid(pid, &status, 0) != pid)
> + perr_and_exit("failed to wait for the tracee");
> +}
> +
> +TEST(ptrace_modify_a0)
> +{
> + int result;
> +
> + ptrace_restart_syscall(MODIFY_A0, &result);
> +
> + /* The tracer's modification of a0 cannot affect the restarted tracee */
> + EXPECT_NE(ORIG_A0_AFTER_MODIFIED, result);
> +}
> +
> +TEST(ptrace_modify_orig_a0)
> +{
> + int result;
> +
> + ptrace_restart_syscall(MODIFY_ORIG_A0, &result);
> +
> + /* The tracer must modify orig_a0 to actually change the tracee's a0 */
> + EXPECT_EQ(ORIG_A0_AFTER_MODIFIED, result);
How does the value end up being 5?
- Charlie
> +}
> +
> +TEST_HARNESS_MAIN
> --
> 2.34.1
>
WARNING: multiple messages have this Message-ID (diff)
From: Charlie Jenkins <charlie@rivosinc.com>
To: zhouquan@iscas.ac.cn
Cc: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, oleg@redhat.com,
paul.walmsley@sifive.com, palmer@dabbelt.com,
aou@eecs.berkeley.edu, andy.chiu@sifive.com, shuah@kernel.org
Subject: Re: [RFC PATCH 2/2] riscv: selftests: Add a ptrace test to check a0 of restarted syscall
Date: Wed, 19 Jun 2024 19:55:01 -0700 [thread overview]
Message-ID: <ZnOaBeNnNpvrE5ss@ghost> (raw)
In-Reply-To: <b5fbdd3417e925dbe5db4716e51ce49d21d27f2f.1718693532.git.zhouquan@iscas.ac.cn>
On Wed, Jun 19, 2024 at 10:01:47AM +0800, zhouquan@iscas.ac.cn wrote:
> From: Quan Zhou <zhouquan@iscas.ac.cn>
>
> This test creates two processes: a tracer and a tracee. The tracer actively
> sends a SIGUSR1 signal in user mode to interrupt the read syscall being
> executed by the tracee. We will reset a0/orig_a0 and then observe the value
> of a0 held by the restarted read syscall.
I don't quite follow what the goal of this test is. With orig_a0 being
added to the previous patch for ptrace, a more constrained test could
ensure that this value is respected.
>
> Compared to the test program, a more common scenario is the use of the
> exece syscall, which sends a signal in the kernel path to restart
> the syscall.
>
> Signed-off-by: Quan Zhou <zhouquan@iscas.ac.cn>
> ---
> tools/testing/selftests/riscv/Makefile | 2 +-
> tools/testing/selftests/riscv/abi/.gitignore | 1 +
> tools/testing/selftests/riscv/abi/Makefile | 12 ++
> .../riscv/abi/ptrace_restart_syscall.c | 148 ++++++++++++++++++
> 4 files changed, 162 insertions(+), 1 deletion(-)
> create mode 100644 tools/testing/selftests/riscv/abi/.gitignore
> create mode 100644 tools/testing/selftests/riscv/abi/Makefile
> create mode 100644 tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c
>
> diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile
> index 7ce03d832b64..98541dc2f164 100644
> --- a/tools/testing/selftests/riscv/Makefile
> +++ b/tools/testing/selftests/riscv/Makefile
> @@ -5,7 +5,7 @@
> ARCH ?= $(shell uname -m 2>/dev/null || echo not)
>
> ifneq (,$(filter $(ARCH),riscv))
> -RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn
> +RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn abi
> else
> RISCV_SUBTARGETS :=
> endif
> diff --git a/tools/testing/selftests/riscv/abi/.gitignore b/tools/testing/selftests/riscv/abi/.gitignore
> new file mode 100644
> index 000000000000..e1e00ffb9db9
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/abi/.gitignore
> @@ -0,0 +1 @@
> +abi
The gitignore should contain a list of all of the generated binaries
that should be ignored. Can you put ptrace_restart_syscall in here
instead of abi?
> diff --git a/tools/testing/selftests/riscv/abi/Makefile b/tools/testing/selftests/riscv/abi/Makefile
> new file mode 100644
> index 000000000000..634fa7de74e6
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/abi/Makefile
> @@ -0,0 +1,12 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 ARM Limited
> +# Originally tools/testing/arm64/abi/Makefile
> +
> +CFLAGS += -I$(top_srcdir)/tools/include
> +
> +TEST_GEN_PROGS := ptrace_restart_syscall
> +
> +include ../../lib.mk
> +
> +$(OUTPUT)/ptrace_restart_syscall: ptrace_restart_syscall.c
> + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^
> diff --git a/tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c b/tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c
> new file mode 100644
> index 000000000000..3e25548cb95e
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/abi/ptrace_restart_syscall.c
> @@ -0,0 +1,148 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <errno.h>
> +#include <sys/types.h>
> +#include <sys/ptrace.h>
> +#include <sys/stat.h>
> +#include <sys/user.h>
> +#include <sys/wait.h>
> +#include <sys/uio.h>
> +#include <linux/elf.h>
> +#include <linux/unistd.h>
> +#include <asm/ptrace.h>
> +
> +#include "../../kselftest_harness.h"
> +
> +#define ORIG_A0_AFTER_MODIFIED 0x5
> +#define MODIFY_A0 0x01
> +#define MODIFY_ORIG_A0 0x02
> +
> +#define perr_and_exit(fmt, ...) do { \
> + char buf[256]; \
> + snprintf(buf, sizeof(buf), "%s:%d: " fmt ": %m\n", \
> + __func__, __LINE__, ##__VA_ARGS__); \
> + perror(buf); \
> + exit(-1); \
> +} while (0)
> +
> +static inline void resume_and_wait_tracee(pid_t pid, int flag)
> +{
> + int status;
> +
> + if (ptrace(flag, pid, 0, 0))
> + perr_and_exit("failed to resume the tracee %d", pid);
> +
> + if (waitpid(pid, &status, 0) != pid)
> + perr_and_exit("failed to wait for the tracee %d", pid);
> +}
> +
> +static void ptrace_restart_syscall(int opt, int *result)
> +{
> + int status;
> + int p[2], fd_zero;
> + pid_t pid;
> +
> + struct user_regs_struct regs;
> + struct iovec iov = {
> + .iov_base = ®s,
> + .iov_len = sizeof(regs),
> + };
> +
> + if (pipe(p))
> + perr_and_exit("failed to create a pipe");
> +
> + fd_zero = open("/dev/zero", O_RDONLY);
> + if (fd_zero < 0)
> + perr_and_exit("failed to open /dev/zero");
> +
> + pid = fork();
> + if (pid == 0) {
> + char c;
> +
> + /* Mark oneself being traced */
> + if (ptrace(PTRACE_TRACEME, 0, 0, 0))
> + perr_and_exit("failed to request for tracer to trace me");
> +
> + kill(getpid(), SIGSTOP);
> +
> + if (read(p[0], &c, 1) != 1)
> + exit(1);
> +
> + exit(0);
> + } else if (pid < 0)
> + exit(1);
> +
> + if (waitpid(pid, &status, 0) != pid)
> + perr_and_exit("failed to wait for the tracee %d\n", pid);
> +
> + /* Resume the tracee until the next syscall */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Deliver a signal to interrupt the syscall */
> + kill(pid, SIGUSR1);
> +
> + /* The tracee stops at syscall exit */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Check tracee orig_a0 before syscall restart */
> + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))
> + perr_and_exit("failed to get tracee registers");
> + if (regs.orig_a0 != p[0])
> + perr_and_exit("unexpected a0");
> +
> + /* Modify a0/orig_a0 for the restarted syscall */
> + switch (opt) {
> + case MODIFY_A0:
> + regs.a0 = fd_zero;
> + break;
> + case MODIFY_ORIG_A0:
> + regs.orig_a0 = fd_zero;
> + break;
> + }
> +
> + if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov))
> + perr_and_exit("failed to set tracee registers");
> +
> + /* Ignore SIGUSR1 signal */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Stop at the entry point of the restarted syscall */
> + resume_and_wait_tracee(pid, PTRACE_SYSCALL);
> +
> + /* Now, check regs.a0 of the restarted syscall */
> + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov))
> + perr_and_exit("failed to get tracee registers");
> + *result = regs.a0;
> +
> + /* Resume the tracee */
> + ptrace(PTRACE_CONT, pid, 0, 0);
> + if (waitpid(pid, &status, 0) != pid)
> + perr_and_exit("failed to wait for the tracee");
> +}
> +
> +TEST(ptrace_modify_a0)
> +{
> + int result;
> +
> + ptrace_restart_syscall(MODIFY_A0, &result);
> +
> + /* The tracer's modification of a0 cannot affect the restarted tracee */
> + EXPECT_NE(ORIG_A0_AFTER_MODIFIED, result);
> +}
> +
> +TEST(ptrace_modify_orig_a0)
> +{
> + int result;
> +
> + ptrace_restart_syscall(MODIFY_ORIG_A0, &result);
> +
> + /* The tracer must modify orig_a0 to actually change the tracee's a0 */
> + EXPECT_EQ(ORIG_A0_AFTER_MODIFIED, result);
How does the value end up being 5?
- Charlie
> +}
> +
> +TEST_HARNESS_MAIN
> --
> 2.34.1
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
next prev parent reply other threads:[~2024-06-20 2:55 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-19 2:00 [RFC PATCH 0/2] riscv: Expose orig_a0 to userspace for ptrace to set the actual a0 zhouquan
2024-06-19 2:00 ` zhouquan
2024-06-19 2:01 ` [RFC PATCH 1/2] riscv: Expose orig_a0 in the user_regs_struct structure zhouquan
2024-06-19 2:01 ` zhouquan
2024-06-20 1:05 ` Charlie Jenkins
2024-06-20 1:05 ` Charlie Jenkins
2024-06-20 2:34 ` Quan Zhou
2024-06-20 2:34 ` Quan Zhou
2024-06-19 2:01 ` [RFC PATCH 2/2] riscv: selftests: Add a ptrace test to check a0 of restarted syscall zhouquan
2024-06-19 2:01 ` zhouquan
2024-06-20 2:55 ` Charlie Jenkins [this message]
2024-06-20 2:55 ` Charlie Jenkins
2024-06-21 6:29 ` Quan Zhou
2024-06-21 6:29 ` Quan Zhou
2024-06-21 20:20 ` Charlie Jenkins
2024-06-21 20:20 ` Charlie Jenkins
2024-06-24 3:24 ` Quan Zhou
2024-06-24 3:24 ` Quan Zhou
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZnOaBeNnNpvrE5ss@ghost \
--to=charlie@rivosinc.com \
--cc=andy.chiu@sifive.com \
--cc=aou@eecs.berkeley.edu \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=oleg@redhat.com \
--cc=palmer@dabbelt.com \
--cc=paul.walmsley@sifive.com \
--cc=shuah@kernel.org \
--cc=zhouquan@iscas.ac.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.