* [LTP] [PATCH v1 0/2] factory
@ 2023-09-25 11:04 Wei Gao via ltp
2023-09-25 11:04 ` [LTP] [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check Wei Gao via ltp
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Wei Gao via ltp @ 2023-09-25 11:04 UTC (permalink / raw)
To: wegao, ltp
Wei Gao (2):
seccomp01.c: Add SECCOMP_RET_USER_NOTIF check
d
configure.ac | 1 +
include/lapi/seccomp.h | 7 +
runtest/syscalls | 2 +
testcases/kernel/syscalls/ptrace/ptrace05.c | 147 ++----
testcases/kernel/syscalls/ptrace/ptrace06.c | 306 +++++++-----
testcases/kernel/syscalls/seccomp/.gitignore | 1 +
testcases/kernel/syscalls/seccomp/Makefile | 8 +
testcases/kernel/syscalls/seccomp/seccomp01.c | 456 ++++++++++++++++++
8 files changed, 689 insertions(+), 239 deletions(-)
create mode 100644 testcases/kernel/syscalls/seccomp/.gitignore
create mode 100644 testcases/kernel/syscalls/seccomp/Makefile
create mode 100644 testcases/kernel/syscalls/seccomp/seccomp01.c
--
2.35.3
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 6+ messages in thread* [LTP] [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check 2023-09-25 11:04 [LTP] [PATCH v1 0/2] factory Wei Gao via ltp @ 2023-09-25 11:04 ` Wei Gao via ltp 2023-09-25 11:36 ` Wei Gao via ltp 2023-09-25 11:04 ` [LTP] [PATCH v1 2/2] d Wei Gao via ltp 2023-09-25 11:31 ` [LTP] [PATCH v1 0/2] factory Wei Gao via ltp 2 siblings, 1 reply; 6+ messages in thread From: Wei Gao via ltp @ 2023-09-25 11:04 UTC (permalink / raw) To: wegao, ltp This case will report EINVAL error when execute SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_RECV, req) such as 5.6.19, so i put current case's .min_kver = "5.7.19" NOTE: If your old kernel compile env is ubuntu 22.04 LTS, better use old gcc-8 and also apply patch base following link: https://www.spinics.net/lists/kernel/msg3797871.html Signed-off-by: Wei Gao <wegao@suse.com> --- configure.ac | 1 + include/lapi/seccomp.h | 7 + runtest/syscalls | 2 + testcases/kernel/syscalls/seccomp/.gitignore | 1 + testcases/kernel/syscalls/seccomp/Makefile | 8 + testcases/kernel/syscalls/seccomp/seccomp01.c | 456 ++++++++++++++++++ 6 files changed, 475 insertions(+) create mode 100644 testcases/kernel/syscalls/seccomp/.gitignore create mode 100644 testcases/kernel/syscalls/seccomp/Makefile create mode 100644 testcases/kernel/syscalls/seccomp/seccomp01.c diff --git a/configure.ac b/configure.ac index 662c4c058..6cea35cb4 100644 --- a/configure.ac +++ b/configure.ac @@ -138,6 +138,7 @@ AC_CHECK_FUNCS_ONCE([ \ renameat \ renameat2 \ sched_getcpu \ + seccomp \ sendmmsg \ sethostid \ setns \ diff --git a/include/lapi/seccomp.h b/include/lapi/seccomp.h index 29819ba6f..cfb3da55d 100644 --- a/include/lapi/seccomp.h +++ b/include/lapi/seccomp.h @@ -37,4 +37,11 @@ struct seccomp_data { }; #endif /* HAVE_LINUX_SECCOMP_H*/ + +# ifndef HAVE_SECCOMP +int seccomp(unsigned int operation, unsigned int flags, void *args) +{ + return syscall(__NR_seccomp, operation, flags, args); +} +# endif /* HAVE_SECCOMP */ #endif /* LAPI_SECCOMP_H__ */ diff --git a/runtest/syscalls b/runtest/syscalls index 4f1ee1f34..544610d63 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -1242,6 +1242,8 @@ select02 select02 select03 select03 select04 select04 +seccomp01 seccomp01 + semctl01 semctl01 semctl02 semctl02 semctl03 semctl03 diff --git a/testcases/kernel/syscalls/seccomp/.gitignore b/testcases/kernel/syscalls/seccomp/.gitignore new file mode 100644 index 000000000..9196906cf --- /dev/null +++ b/testcases/kernel/syscalls/seccomp/.gitignore @@ -0,0 +1 @@ +seccomp01 diff --git a/testcases/kernel/syscalls/seccomp/Makefile b/testcases/kernel/syscalls/seccomp/Makefile new file mode 100644 index 000000000..49238eee0 --- /dev/null +++ b/testcases/kernel/syscalls/seccomp/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2023 Wei Gao <wegao@suse.com> + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/seccomp/seccomp01.c b/testcases/kernel/syscalls/seccomp/seccomp01.c new file mode 100644 index 000000000..bf23fe8f7 --- /dev/null +++ b/testcases/kernel/syscalls/seccomp/seccomp01.c @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Michael Kerrisk <mtk.manpages@gmail.com> + * Copyright (c) 2023 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] + * + * Verify seccomp and seccomp_user_notif + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/prctl.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <linux/audit.h> +#include <sys/syscall.h> +#include <sys/stat.h> +#include <linux/filter.h> +#include <linux/seccomp.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "tst_test.h" +#include "lapi/seccomp.h" + +#define TMP_PREFIX_DIR "/tmp/ltp_test" +#define CWD_DIR "./abc" +#define OTHER_DIR "/aa" + +static struct tcase { + char *dir; + int expect_ret; + char *desc; +} tcases[] = { + {TMP_PREFIX_DIR, strlen(TMP_PREFIX_DIR), "pathname begins with the prefix /tmp/"}, + {CWD_DIR, 0, "pathname begins with ./"}, + {OTHER_DIR, -1, "pathname begins with /abc"}, +}; + +static int sendfd(int sockfd, int fd) +{ + struct msghdr msgh; + struct iovec iov; + int data; + struct cmsghdr *cmsgp; + + /* Allocate a char array of suitable size to hold the ancillary data. + * However, since this buffer is in reality a 'struct cmsghdr', use a + * union to ensure that it is suitable aligned. + */ + union { + char buf[CMSG_SPACE(sizeof(int))]; + /* Space large enough to hold an 'int' */ + struct cmsghdr align; + } controlMsg; + + /* The 'msg_name' field can be used to specify the address of the + * destination socket when sending a datagram. However, we do not + * need to use this field because 'sockfd' is a connected socket. + */ + + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + /* On Linux, we must transmit at least one byte of real data in + * order to send ancillary data. We transmit an arbitrary integer + * whose value is ignored by recvfd(). + */ + + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + iov.iov_base = &data; + iov.iov_len = sizeof(int); + data = 12345; + + /* Set 'msghdr' fields that describe ancillary data */ + + msgh.msg_control = controlMsg.buf; + msgh.msg_controllen = sizeof(controlMsg.buf); + + /* Set up ancillary data describing file descriptor to send */ + + cmsgp = CMSG_FIRSTHDR(&msgh); + cmsgp->cmsg_level = SOL_SOCKET; + cmsgp->cmsg_type = SCM_RIGHTS; + cmsgp->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsgp), &fd, sizeof(int)); + + SAFE_SENDMSG(sizeof(int), sockfd, &msgh, 0); + + return 0; +} + +static int recvfd(int sockfd) +{ + struct msghdr msgh; + struct iovec iov; + int data, fd; + ssize_t nr; + + /* Allocate a char buffer for the ancillary data. See the comments + * in sendfd() + */ + union { + char buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr align; + } controlMsg; + struct cmsghdr *cmsgp; + + /* The 'msg_name' field can be used to obtain the address of the + * sending socket. However, we do not need this information. + */ + + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + /* Specify buffer for receiving real data */ + + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + iov.iov_base = &data; /* Real data is an 'int' */ + iov.iov_len = sizeof(int); + + /* Set 'msghdr' fields that describe ancillary data */ + + msgh.msg_control = controlMsg.buf; + msgh.msg_controllen = sizeof(controlMsg.buf); + + /* Receive real plus ancillary data; real data is ignored */ + + nr = SAFE_RECVMSG(sizeof(int), sockfd, &msgh, 0); + + if (nr == -1) + return -1; + + cmsgp = CMSG_FIRSTHDR(&msgh); + + /* Check the validity of the 'cmsghdr' */ + + if (cmsgp == NULL || + cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) || + cmsgp->cmsg_level != SOL_SOCKET || + cmsgp->cmsg_type != SCM_RIGHTS) { + errno = EINVAL; + return -1; + } + + /* Return the received file descriptor to our caller */ + + memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int)); + return fd; +} + +/* The following is the x86-64-specific BPF boilerplate code for checking + * that the BPF program is running on the right architecture + ABI. At + * completion of these instructions, the accumulator contains the system + * call number. + */ + +/* For the x32 ABI, all system call numbers have bit 30 set */ + +#define X32_SYSCALL_BIT 0x40000000 + +#define X86_64_CHECK_ARCH_AND_LOAD_SYSCALL_NR \ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \ + (offsetof(struct seccomp_data, arch))), \ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 0, 2), \ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \ + (offsetof(struct seccomp_data, nr))), \ + BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, X32_SYSCALL_BIT, 0, 1), \ + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS) + +/* installNotifyFilter() installs a seccomp filter that generates + * user-space notifications (SECCOMP_RET_USER_NOTIF) when the process + * calls mkdir(2); the filter allows all other system calls. + * + * The function return value is a file descriptor from which the + * user-space notifications can be fetched. + */ + +static int installNotifyFilter(void) +{ + struct sock_filter filter[] = { + X86_64_CHECK_ARCH_AND_LOAD_SYSCALL_NR, + + /* mkdir() triggers notification to user-space supervisor */ + + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mkdir, 0, 1), + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF), + + /* Every other system call is allowed */ + + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + }; + + struct sock_fprog prog = { + .len = ARRAY_SIZE(filter), + .filter = filter, + }; + + /* Install the filter with the SECCOMP_FILTER_FLAG_NEW_LISTENER flag; + * as a result, seccomp() returns a notification file descriptor. + */ + + TST_EXP_POSITIVE(seccomp(SECCOMP_SET_MODE_FILTER, + SECCOMP_FILTER_FLAG_NEW_LISTENER, &prog)); + return TST_RET; + +} + +/* Close a pair of sockets created by socketpair() */ + +static void closeSocketPair(int sockPair[2]) +{ + SAFE_CLOSE(sockPair[0]); + SAFE_CLOSE(sockPair[1]); +} + +/* Implementation of the target process; create a child process that: + * + * (1) installs a seccomp filter with the + * SECCOMP_FILTER_FLAG_NEW_LISTENER flag; + * (2) writes the seccomp notification file descriptor returned from + * the previous step onto the UNIX domain socket, 'sockPair[0]'; + * (3) calls mkdir(2) for each element of 'argv'. + + * The function return value in the parent is the PID of the child + * process; the child does not return from this function. + */ + +static pid_t targetProcess(int sockPair[2], struct tcase *tc) +{ + + pid_t targetPid = SAFE_FORK(); + + if (targetPid > 0) /* In parent, return PID of child */ + return targetPid; + + /* Child falls through to here */ + + tst_res(TINFO, "T: PID = %ld", (long) getpid()); + + /* Install seccomp filter(s) */ + + TST_EXP_PASS(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); + + int notifyFd = installNotifyFilter(); + + /* Pass the notification file descriptor to the tracing process over + * a UNIX domain socket + */ + + TST_EXP_PASS(sendfd(sockPair[0], notifyFd)); + + /* Notification and socket FDs are no longer needed in target */ + + SAFE_CLOSE(notifyFd); + + closeSocketPair(sockPair); + + tst_res(TINFO, "T: about to mkdir(\"%s\")", tc->dir); + + TST_CHECKPOINT_WAIT(0); + + TEST(mkdir(tc->dir, 0700)); + + tst_res(TINFO, "T: SUCCESS: mkdir(2) returned %ld", TST_RET); + if (TST_RET == tc->expect_ret) + tst_res(TPASS, "Case %s PASS", tc->desc); + else + tst_brk(TBROK | TTERRNO, "Case %s Failed, expect %d but return %ld", + tc->desc, tc->expect_ret, TST_RET); + + exit(EXIT_SUCCESS); +} + + +/* Access the memory of the target process in order to discover the + * pathname that was given to mkdir() + */ + +static void getTargetPathname(struct seccomp_notif *req, int notifyFd, + char *path) +{ + char procMemPath[PATH_MAX]; + + snprintf(procMemPath, sizeof(procMemPath), "/proc/%d/mem", req->pid); + + int procMemFd = SAFE_OPEN(procMemPath, O_RDONLY); + + /* Check that the process whose info we are accessing is still alive. + * If the SECCOMP_IOCTL_NOTIF_ID_VALID operation (performed + * in checkNotificationIdIsValid()) succeeds, we know that the + * /proc/PID/mem file descriptor that we opened corresponds to the + * process for which we received a notification. If that process + * subsequently terminates, then read() on that file descriptor + * will return 0 (EOF). + */ + + SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_ID_VALID, &req->id); + + /* Seek to the location containing the pathname argument (i.e., the + * first argument) of the mkdir(2) call and read that pathname + */ + + SAFE_LSEEK(procMemFd, req->data.args[0], SEEK_SET); + + SAFE_READ(1, procMemFd, path, PATH_MAX); + + SAFE_CLOSE(procMemFd); +} + +/* Handle notifications that arrive via the SECCOMP_RET_USER_NOTIF file + * descriptor, 'notifyFd'. + */ + +static void handleNotifications(int notifyFd) +{ + struct seccomp_notif_sizes sizes; + char path[PATH_MAX]; + + TST_EXP_POSITIVE(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes)); + + struct seccomp_notif *req = SAFE_MALLOC(sizes.seccomp_notif); + + struct seccomp_notif_resp *resp = SAFE_MALLOC(sizes.seccomp_notif_resp); + + memset(req, 0, sizes.seccomp_notif); + + TST_CHECKPOINT_WAKE(0); + + SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_RECV, req); + + tst_res(TINFO, "S: got notification (ID %#llx) for PID %d", + req->id, req->pid); + + /* The only system call that can generate a notification event + * is mkdir(2). Nevertheless, we check that the notified system + * call is indeed mkdir() as kind of future-proofing of this + * code in case the seccomp filter is later modified to + * generate notifications for other system calls. + */ + + if (req->data.nr != __NR_mkdir) + tst_brk(TBROK, "notification contained unexpected system call number"); + + getTargetPathname(req, notifyFd, path); + + /* Prepopulate some fields of the response */ + + resp->id = req->id; /* Response includes notification ID */ + resp->flags = 0; + resp->val = 0; + + /* If the directory is in /tmp, then create it on behalf of + * the supervisor; if the pathname starts with '.', tell the + * kernel to let the target process execute the mkdir(); + * otherwise, give an error for a directory pathname in + * any other location. + */ + + if (strncmp(path, "/tmp/", strlen("/tmp/")) == 0) { + tst_res(TINFO, "S: executing: mkdir(\"%s\", %#llo)", + path, req->data.args[1]); + + if (mkdir(path, req->data.args[1]) == 0) { + resp->error = 0; /* "Success" */ + resp->val = strlen(path); /* Used as return value of + * mkdir() in target + */ + tst_res(TINFO, "S: success! spoofed return = %lld", + resp->val); + } else { + + /* If mkdir() failed in the supervisor, pass the error + * back to the target + */ + + resp->error = -errno; + tst_res(TINFO, "S: failure! (errno = %d; %s)", errno, + strerror(errno)); + } + } else if (strncmp(path, "./", strlen("./")) == 0) { + resp->error = resp->val = 0; + resp->flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE; + tst_res(TINFO, "S: target can execute system call"); + } else { + resp->error = -EOPNOTSUPP; + tst_res(TINFO, "S: spoofing error response (%s)", + strerror(-resp->error)); + } + + /* Send a response to the notification */ + + tst_res(TINFO, "S: sending response " + "(flags = %#x; val = %lld; error = %d)", + resp->flags, resp->val, resp->error); + + SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_SEND, resp); + +} + +/* Implementation of the supervisor process: + * + * (1) obtains the notification file descriptor from 'sockPair[1]' + * (2) handles notifications that arrive on that file descriptor. + */ + +static void supervisor(int sockPair[2]) +{ + int notifyFd = TST_EXP_POSITIVE(recvfd(sockPair[1])); + + closeSocketPair(sockPair); /* We no longer need the socket pair */ + + handleNotifications(notifyFd); +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int sockPair[2]; + + tst_res(TINFO, "Test case %s start", tc->desc); + + SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sockPair); + + int pid = targetProcess(sockPair, tc); + + supervisor(sockPair); + + SAFE_WAITPID(pid, NULL, 0); + + if (!access(tc->dir, F_OK)) + SAFE_RMDIR(tc->dir); +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = run, + .needs_tmpdir = 1, + .forks_child = 1, + .min_kver = "5.7.19", + .needs_checkpoints = 1 +}; -- 2.35.3 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [LTP] [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check 2023-09-25 11:04 ` [LTP] [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check Wei Gao via ltp @ 2023-09-25 11:36 ` Wei Gao via ltp 0 siblings, 0 replies; 6+ messages in thread From: Wei Gao via ltp @ 2023-09-25 11:36 UTC (permalink / raw) To: Wei Gao, ltp@lists.linux.it Sorry for the garbage email, please SKIP this email. -----Original Message----- From: Wei Gao <wegao@suse.com> Sent: Monday, September 25, 2023 7:04 PM To: Wei Gao <wegao@suse.com>; ltp@lists.linux.it Subject: [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check This case will report EINVAL error when execute SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_RECV, req) such as 5.6.19, so i put current case's .min_kver = "5.7.19" NOTE: If your old kernel compile env is ubuntu 22.04 LTS, better use old gcc-8 and also apply patch base following link: https://www.spinics.net/lists/kernel/msg3797871.html Signed-off-by: Wei Gao <wegao@suse.com> --- configure.ac | 1 + include/lapi/seccomp.h | 7 + runtest/syscalls | 2 + testcases/kernel/syscalls/seccomp/.gitignore | 1 + testcases/kernel/syscalls/seccomp/Makefile | 8 + testcases/kernel/syscalls/seccomp/seccomp01.c | 456 ++++++++++++++++++ 6 files changed, 475 insertions(+) create mode 100644 testcases/kernel/syscalls/seccomp/.gitignore create mode 100644 testcases/kernel/syscalls/seccomp/Makefile create mode 100644 testcases/kernel/syscalls/seccomp/seccomp01.c diff --git a/configure.ac b/configure.ac index 662c4c058..6cea35cb4 100644 --- a/configure.ac +++ b/configure.ac @@ -138,6 +138,7 @@ AC_CHECK_FUNCS_ONCE([ \ renameat \ renameat2 \ sched_getcpu \ + seccomp \ sendmmsg \ sethostid \ setns \ diff --git a/include/lapi/seccomp.h b/include/lapi/seccomp.h index 29819ba6f..cfb3da55d 100644 --- a/include/lapi/seccomp.h +++ b/include/lapi/seccomp.h @@ -37,4 +37,11 @@ struct seccomp_data { }; #endif /* HAVE_LINUX_SECCOMP_H*/ + +# ifndef HAVE_SECCOMP +int seccomp(unsigned int operation, unsigned int flags, void *args) { + return syscall(__NR_seccomp, operation, flags, args); } # endif /* +HAVE_SECCOMP */ #endif /* LAPI_SECCOMP_H__ */ diff --git a/runtest/syscalls b/runtest/syscalls index 4f1ee1f34..544610d63 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -1242,6 +1242,8 @@ select02 select02 select03 select03 select04 select04 +seccomp01 seccomp01 + semctl01 semctl01 semctl02 semctl02 semctl03 semctl03 diff --git a/testcases/kernel/syscalls/seccomp/.gitignore b/testcases/kernel/syscalls/seccomp/.gitignore new file mode 100644 index 000000000..9196906cf --- /dev/null +++ b/testcases/kernel/syscalls/seccomp/.gitignore @@ -0,0 +1 @@ +seccomp01 diff --git a/testcases/kernel/syscalls/seccomp/Makefile b/testcases/kernel/syscalls/seccomp/Makefile new file mode 100644 index 000000000..49238eee0 --- /dev/null +++ b/testcases/kernel/syscalls/seccomp/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2023 Wei Gao +<wegao@suse.com> + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/seccomp/seccomp01.c b/testcases/kernel/syscalls/seccomp/seccomp01.c new file mode 100644 index 000000000..bf23fe8f7 --- /dev/null +++ b/testcases/kernel/syscalls/seccomp/seccomp01.c @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Michael Kerrisk <mtk.manpages@gmail.com> + * Copyright (c) 2023 Wei Gao <wegao@suse.com> */ + +/*\ + * [Description] + * + * Verify seccomp and seccomp_user_notif */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/prctl.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <linux/audit.h> +#include <sys/syscall.h> +#include <sys/stat.h> +#include <linux/filter.h> +#include <linux/seccomp.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "tst_test.h" +#include "lapi/seccomp.h" + +#define TMP_PREFIX_DIR "/tmp/ltp_test" +#define CWD_DIR "./abc" +#define OTHER_DIR "/aa" + +static struct tcase { + char *dir; + int expect_ret; + char *desc; +} tcases[] = { + {TMP_PREFIX_DIR, strlen(TMP_PREFIX_DIR), "pathname begins with the prefix /tmp/"}, + {CWD_DIR, 0, "pathname begins with ./"}, + {OTHER_DIR, -1, "pathname begins with /abc"}, }; + +static int sendfd(int sockfd, int fd) +{ + struct msghdr msgh; + struct iovec iov; + int data; + struct cmsghdr *cmsgp; + + /* Allocate a char array of suitable size to hold the ancillary data. + * However, since this buffer is in reality a 'struct cmsghdr', use a + * union to ensure that it is suitable aligned. + */ + union { + char buf[CMSG_SPACE(sizeof(int))]; + /* Space large enough to hold an 'int' */ + struct cmsghdr align; + } controlMsg; + + /* The 'msg_name' field can be used to specify the address of the + * destination socket when sending a datagram. However, we do not + * need to use this field because 'sockfd' is a connected socket. + */ + + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + /* On Linux, we must transmit at least one byte of real data in + * order to send ancillary data. We transmit an arbitrary integer + * whose value is ignored by recvfd(). + */ + + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + iov.iov_base = &data; + iov.iov_len = sizeof(int); + data = 12345; + + /* Set 'msghdr' fields that describe ancillary data */ + + msgh.msg_control = controlMsg.buf; + msgh.msg_controllen = sizeof(controlMsg.buf); + + /* Set up ancillary data describing file descriptor to send */ + + cmsgp = CMSG_FIRSTHDR(&msgh); + cmsgp->cmsg_level = SOL_SOCKET; + cmsgp->cmsg_type = SCM_RIGHTS; + cmsgp->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsgp), &fd, sizeof(int)); + + SAFE_SENDMSG(sizeof(int), sockfd, &msgh, 0); + + return 0; +} + +static int recvfd(int sockfd) +{ + struct msghdr msgh; + struct iovec iov; + int data, fd; + ssize_t nr; + + /* Allocate a char buffer for the ancillary data. See the comments + * in sendfd() + */ + union { + char buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr align; + } controlMsg; + struct cmsghdr *cmsgp; + + /* The 'msg_name' field can be used to obtain the address of the + * sending socket. However, we do not need this information. + */ + + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + /* Specify buffer for receiving real data */ + + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + iov.iov_base = &data; /* Real data is an 'int' */ + iov.iov_len = sizeof(int); + + /* Set 'msghdr' fields that describe ancillary data */ + + msgh.msg_control = controlMsg.buf; + msgh.msg_controllen = sizeof(controlMsg.buf); + + /* Receive real plus ancillary data; real data is ignored */ + + nr = SAFE_RECVMSG(sizeof(int), sockfd, &msgh, 0); + + if (nr == -1) + return -1; + + cmsgp = CMSG_FIRSTHDR(&msgh); + + /* Check the validity of the 'cmsghdr' */ + + if (cmsgp == NULL || + cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) || + cmsgp->cmsg_level != SOL_SOCKET || + cmsgp->cmsg_type != SCM_RIGHTS) { + errno = EINVAL; + return -1; + } + + /* Return the received file descriptor to our caller */ + + memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int)); + return fd; +} + +/* The following is the x86-64-specific BPF boilerplate code for +checking + * that the BPF program is running on the right architecture + ABI. At + * completion of these instructions, the accumulator contains the +system + * call number. + */ + +/* For the x32 ABI, all system call numbers have bit 30 set */ + +#define X32_SYSCALL_BIT 0x40000000 + +#define X86_64_CHECK_ARCH_AND_LOAD_SYSCALL_NR \ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \ + (offsetof(struct seccomp_data, arch))), \ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 0, 2), \ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \ + (offsetof(struct seccomp_data, nr))), \ + BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, X32_SYSCALL_BIT, 0, 1), \ + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS) + +/* installNotifyFilter() installs a seccomp filter that generates + * user-space notifications (SECCOMP_RET_USER_NOTIF) when the process + * calls mkdir(2); the filter allows all other system calls. + * + * The function return value is a file descriptor from which the + * user-space notifications can be fetched. + */ + +static int installNotifyFilter(void) +{ + struct sock_filter filter[] = { + X86_64_CHECK_ARCH_AND_LOAD_SYSCALL_NR, + + /* mkdir() triggers notification to user-space supervisor */ + + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mkdir, 0, 1), + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF), + + /* Every other system call is allowed */ + + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + }; + + struct sock_fprog prog = { + .len = ARRAY_SIZE(filter), + .filter = filter, + }; + + /* Install the filter with the SECCOMP_FILTER_FLAG_NEW_LISTENER flag; + * as a result, seccomp() returns a notification file descriptor. + */ + + TST_EXP_POSITIVE(seccomp(SECCOMP_SET_MODE_FILTER, + SECCOMP_FILTER_FLAG_NEW_LISTENER, &prog)); + return TST_RET; + +} + +/* Close a pair of sockets created by socketpair() */ + +static void closeSocketPair(int sockPair[2]) { + SAFE_CLOSE(sockPair[0]); + SAFE_CLOSE(sockPair[1]); +} + +/* Implementation of the target process; create a child process that: + * + * (1) installs a seccomp filter with the + * SECCOMP_FILTER_FLAG_NEW_LISTENER flag; + * (2) writes the seccomp notification file descriptor returned from + * the previous step onto the UNIX domain socket, 'sockPair[0]'; + * (3) calls mkdir(2) for each element of 'argv'. + + * The function return value in the parent is the PID of the child + * process; the child does not return from this function. + */ + +static pid_t targetProcess(int sockPair[2], struct tcase *tc) { + + pid_t targetPid = SAFE_FORK(); + + if (targetPid > 0) /* In parent, return PID of child */ + return targetPid; + + /* Child falls through to here */ + + tst_res(TINFO, "T: PID = %ld", (long) getpid()); + + /* Install seccomp filter(s) */ + + TST_EXP_PASS(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); + + int notifyFd = installNotifyFilter(); + + /* Pass the notification file descriptor to the tracing process over + * a UNIX domain socket + */ + + TST_EXP_PASS(sendfd(sockPair[0], notifyFd)); + + /* Notification and socket FDs are no longer needed in target */ + + SAFE_CLOSE(notifyFd); + + closeSocketPair(sockPair); + + tst_res(TINFO, "T: about to mkdir(\"%s\")", tc->dir); + + TST_CHECKPOINT_WAIT(0); + + TEST(mkdir(tc->dir, 0700)); + + tst_res(TINFO, "T: SUCCESS: mkdir(2) returned %ld", TST_RET); + if (TST_RET == tc->expect_ret) + tst_res(TPASS, "Case %s PASS", tc->desc); + else + tst_brk(TBROK | TTERRNO, "Case %s Failed, expect %d but return %ld", + tc->desc, tc->expect_ret, TST_RET); + + exit(EXIT_SUCCESS); +} + + +/* Access the memory of the target process in order to discover the + * pathname that was given to mkdir() + */ + +static void getTargetPathname(struct seccomp_notif *req, int notifyFd, + char *path) +{ + char procMemPath[PATH_MAX]; + + snprintf(procMemPath, sizeof(procMemPath), "/proc/%d/mem", req->pid); + + int procMemFd = SAFE_OPEN(procMemPath, O_RDONLY); + + /* Check that the process whose info we are accessing is still alive. + * If the SECCOMP_IOCTL_NOTIF_ID_VALID operation (performed + * in checkNotificationIdIsValid()) succeeds, we know that the + * /proc/PID/mem file descriptor that we opened corresponds to the + * process for which we received a notification. If that process + * subsequently terminates, then read() on that file descriptor + * will return 0 (EOF). + */ + + SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_ID_VALID, &req->id); + + /* Seek to the location containing the pathname argument (i.e., the + * first argument) of the mkdir(2) call and read that pathname + */ + + SAFE_LSEEK(procMemFd, req->data.args[0], SEEK_SET); + + SAFE_READ(1, procMemFd, path, PATH_MAX); + + SAFE_CLOSE(procMemFd); +} + +/* Handle notifications that arrive via the SECCOMP_RET_USER_NOTIF file + * descriptor, 'notifyFd'. + */ + +static void handleNotifications(int notifyFd) { + struct seccomp_notif_sizes sizes; + char path[PATH_MAX]; + + TST_EXP_POSITIVE(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes)); + + struct seccomp_notif *req = SAFE_MALLOC(sizes.seccomp_notif); + + struct seccomp_notif_resp *resp = +SAFE_MALLOC(sizes.seccomp_notif_resp); + + memset(req, 0, sizes.seccomp_notif); + + TST_CHECKPOINT_WAKE(0); + + SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_RECV, req); + + tst_res(TINFO, "S: got notification (ID %#llx) for PID %d", + req->id, req->pid); + + /* The only system call that can generate a notification event + * is mkdir(2). Nevertheless, we check that the notified system + * call is indeed mkdir() as kind of future-proofing of this + * code in case the seccomp filter is later modified to + * generate notifications for other system calls. + */ + + if (req->data.nr != __NR_mkdir) + tst_brk(TBROK, "notification contained unexpected system call +number"); + + getTargetPathname(req, notifyFd, path); + + /* Prepopulate some fields of the response */ + + resp->id = req->id; /* Response includes notification ID */ + resp->flags = 0; + resp->val = 0; + + /* If the directory is in /tmp, then create it on behalf of + * the supervisor; if the pathname starts with '.', tell the + * kernel to let the target process execute the mkdir(); + * otherwise, give an error for a directory pathname in + * any other location. + */ + + if (strncmp(path, "/tmp/", strlen("/tmp/")) == 0) { + tst_res(TINFO, "S: executing: mkdir(\"%s\", %#llo)", + path, req->data.args[1]); + + if (mkdir(path, req->data.args[1]) == 0) { + resp->error = 0; /* "Success" */ + resp->val = strlen(path); /* Used as return value of + * mkdir() in target + */ + tst_res(TINFO, "S: success! spoofed return = %lld", + resp->val); + } else { + + /* If mkdir() failed in the supervisor, pass the error + * back to the target + */ + + resp->error = -errno; + tst_res(TINFO, "S: failure! (errno = %d; %s)", errno, + strerror(errno)); + } + } else if (strncmp(path, "./", strlen("./")) == 0) { + resp->error = resp->val = 0; + resp->flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE; + tst_res(TINFO, "S: target can execute system call"); + } else { + resp->error = -EOPNOTSUPP; + tst_res(TINFO, "S: spoofing error response (%s)", + strerror(-resp->error)); + } + + /* Send a response to the notification */ + + tst_res(TINFO, "S: sending response " + "(flags = %#x; val = %lld; error = %d)", + resp->flags, resp->val, resp->error); + + SAFE_IOCTL(notifyFd, SECCOMP_IOCTL_NOTIF_SEND, resp); + +} + +/* Implementation of the supervisor process: + * + * (1) obtains the notification file descriptor from 'sockPair[1]' + * (2) handles notifications that arrive on that file descriptor. + */ + +static void supervisor(int sockPair[2]) { + int notifyFd = TST_EXP_POSITIVE(recvfd(sockPair[1])); + + closeSocketPair(sockPair); /* We no longer need the socket pair */ + + handleNotifications(notifyFd); +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int sockPair[2]; + + tst_res(TINFO, "Test case %s start", tc->desc); + + SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sockPair); + + int pid = targetProcess(sockPair, tc); + + supervisor(sockPair); + + SAFE_WAITPID(pid, NULL, 0); + + if (!access(tc->dir, F_OK)) + SAFE_RMDIR(tc->dir); +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = run, + .needs_tmpdir = 1, + .forks_child = 1, + .min_kver = "5.7.19", + .needs_checkpoints = 1 +}; -- 2.35.3 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [LTP] [PATCH v1 2/2] d 2023-09-25 11:04 [LTP] [PATCH v1 0/2] factory Wei Gao via ltp 2023-09-25 11:04 ` [LTP] [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check Wei Gao via ltp @ 2023-09-25 11:04 ` Wei Gao via ltp 2023-09-25 11:36 ` Wei Gao via ltp 2023-09-25 11:31 ` [LTP] [PATCH v1 0/2] factory Wei Gao via ltp 2 siblings, 1 reply; 6+ messages in thread From: Wei Gao via ltp @ 2023-09-25 11:04 UTC (permalink / raw) To: wegao, ltp Signed-off-by: Wei Gao <wegao@suse.com> --- testcases/kernel/syscalls/ptrace/ptrace05.c | 147 +++------- testcases/kernel/syscalls/ptrace/ptrace06.c | 306 +++++++++++--------- 2 files changed, 214 insertions(+), 239 deletions(-) diff --git a/testcases/kernel/syscalls/ptrace/ptrace05.c b/testcases/kernel/syscalls/ptrace/ptrace05.c index 54cfa4d7b..4904b959c 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace05.c +++ b/testcases/kernel/syscalls/ptrace/ptrace05.c @@ -1,122 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - ****************************************************************************** - * - * ptrace05 - an app which ptraces itself as per arbitrarily specified signals, - * over a user specified range. - * - * Copyright (C) 2009, Ngie Cooper - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2009, Ngie Cooper + * Copyright (c) 2023 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * ptrace05 - an app which ptraces itself as per arbitrarily specified signals * - ****************************************************************************** */ -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> -#include <errno.h> -#include <libgen.h> -#include <math.h> #include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - #include <config.h> #include "ptrace.h" -#include "test.h" #include "lapi/signal.h" +#include "tst_test.h" -char *TCID = "ptrace05"; -int TST_TOTAL = 0; - -int usage(const char *); - -int usage(const char *argv0) -{ - fprintf(stderr, "usage: %s [start-signum] [end-signum]\n", argv0); - return 1; -} - -int main(int argc, char **argv) +static void run(void) { - int end_signum = -1; - int signum; - int start_signum = -1; + int end_signum = SIGRTMAX; + int signum = 0; + int start_signum = 0; int status; pid_t child; - tst_parse_opts(argc, argv, NULL, NULL); - - if (start_signum == -1) { - start_signum = 0; - } - if (end_signum == -1) { - end_signum = SIGRTMAX; - } - for (signum = start_signum; signum <= end_signum; signum++) { - if (signum >= __SIGRTMIN && signum < SIGRTMIN) - continue; - - switch (child = fork()) { + switch (child = SAFE_FORK()) { case -1: - tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); + tst_brk(TBROK | TERRNO, "fork() failed"); case 0: - if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != -1) { - tst_resm(TINFO, "[child] Sending kill(.., %d)", - signum); - if (kill(getpid(), signum) < 0) { - tst_resm(TINFO | TERRNO, - "[child] kill(.., %d) failed.", - signum); - } + TEST(ptrace(PTRACE_TRACEME, 0, NULL, NULL)); + if (TST_RET != -1) { + tst_res(TINFO, "[child] Sending kill(.., %d)", + signum); + SAFE_KILL(getpid(), signum); } else { - - /* - * This won't increment the TST_COUNT var. - * properly, but it'll show up as a failure - * nonetheless. - */ - tst_resm(TFAIL | TERRNO, + tst_brk(TFAIL | TERRNO, "Failed to ptrace(PTRACE_TRACEME, ...) " "properly"); - } - /* Shouldn't get here if signum == 0. */ - exit((signum == 0 ? 0 : 2)); + + exit(0); break; default: - waitpid(child, &status, 0); + SAFE_WAITPID(child, &status, 0); switch (signum) { case 0: if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - tst_resm(TPASS, + tst_res(TPASS, "kill(.., 0) exited " "with 0, as expected."); } else { - tst_resm(TFAIL, + tst_brk(TFAIL | TERRNO, "kill(.., 0) didn't exit " "with 0."); } @@ -125,20 +70,20 @@ int main(int argc, char **argv) if (WIFSIGNALED(status)) { /* SIGKILL must be uncatchable. */ if (WTERMSIG(status) == SIGKILL) { - tst_resm(TPASS, + tst_res(TPASS, "Killed with SIGKILL, " "as expected."); } else { - tst_resm(TPASS, + tst_brk(TFAIL | TERRNO, "Didn't die with " "SIGKILL (?!) "); } } else if (WIFEXITED(status)) { - tst_resm(TFAIL, + tst_brk(TFAIL | TERRNO, "Exited unexpectedly instead " "of dying with SIGKILL."); } else if (WIFSTOPPED(status)) { - tst_resm(TFAIL, + tst_brk(TFAIL | TERRNO, "Stopped instead of dying " "with SIGKILL."); } @@ -146,35 +91,21 @@ int main(int argc, char **argv) /* All other processes should be stopped. */ default: if (WIFSTOPPED(status)) { - tst_resm(TPASS, "Stopped as expected"); + tst_res(TPASS, "Stopped as expected"); } else { - tst_resm(TFAIL, "Didn't stop as " + tst_brk(TFAIL | TERRNO, "Didn't stop as " "expected."); - if (kill(child, 0)) { - tst_resm(TINFO, - "Is still alive!?"); - } else if (WIFEXITED(status)) { - tst_resm(TINFO, - "Exited normally"); - } else if (WIFSIGNALED(status)) { - tst_resm(TINFO, - "Was signaled with " - "signum=%d", - WTERMSIG(status)); - } - } - break; - } - } - /* Make sure the child dies a quick and painless death ... */ - kill(child, 9); + if (signum != 0 && signum != 9) + SAFE_PTRACE(PTRACE_CONT, child, NULL, NULL); } - - tst_exit(); - } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/ptrace/ptrace06.c b/testcases/kernel/syscalls/ptrace/ptrace06.c index c0cb3b9bd..5829faea4 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace06.c +++ b/testcases/kernel/syscalls/ptrace/ptrace06.c @@ -1,32 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2008 Analog Devices Inc. + * Copyright (c) 2023 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] + * * check out-of-bound/unaligned addresses given to * - {PEEK,POKE}{DATA,TEXT,USER} * - {GET,SET}{,FG}REGS * - {GET,SET}SIGINFO * - * Copyright (c) 2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later */ #define _GNU_SOURCE -#include <errno.h> -#include <stdbool.h> -#include <stdio.h> #include <stdlib.h> -#include <unistd.h> - #include <config.h> -#include "ptrace.h" -#include "test.h" -#include "spawn_ptrace_child.h" -#include "config.h" +#include "ptrace.h" +#include "tst_test.h" /* this should be sizeof(struct user), but that info is only found * in the kernel asm/user.h which is not exported to userspace. */ + #if defined(__i386__) #define SIZEOF_USER 284 #elif defined(__x86_64__) @@ -35,168 +34,213 @@ #define SIZEOF_USER 0x1000 /* just pick a big number */ #endif -char *TCID = "ptrace06"; - struct test_case_t { int request; long addr; long data; } test_cases[] = { { - PTRACE_PEEKDATA,.addr = 0}, { - PTRACE_PEEKDATA,.addr = 1}, { - PTRACE_PEEKDATA,.addr = 2}, { - PTRACE_PEEKDATA,.addr = 3}, { - PTRACE_PEEKDATA,.addr = -1}, { - PTRACE_PEEKDATA,.addr = -2}, { - PTRACE_PEEKDATA,.addr = -3}, { - PTRACE_PEEKDATA,.addr = -4}, { - PTRACE_PEEKTEXT,.addr = 0}, { - PTRACE_PEEKTEXT,.addr = 1}, { - PTRACE_PEEKTEXT,.addr = 2}, { - PTRACE_PEEKTEXT,.addr = 3}, { - PTRACE_PEEKTEXT,.addr = -1}, { - PTRACE_PEEKTEXT,.addr = -2}, { - PTRACE_PEEKTEXT,.addr = -3}, { - PTRACE_PEEKTEXT,.addr = -4}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 1}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 2}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 3}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 4}, { - PTRACE_PEEKUSER,.addr = -1}, { - PTRACE_PEEKUSER,.addr = -2}, { - PTRACE_PEEKUSER,.addr = -3}, { - PTRACE_PEEKUSER,.addr = -4}, { - PTRACE_POKEDATA,.addr = 0}, { - PTRACE_POKEDATA,.addr = 1}, { - PTRACE_POKEDATA,.addr = 2}, { - PTRACE_POKEDATA,.addr = 3}, { - PTRACE_POKEDATA,.addr = -1}, { - PTRACE_POKEDATA,.addr = -2}, { - PTRACE_POKEDATA,.addr = -3}, { - PTRACE_POKEDATA,.addr = -4}, { - PTRACE_POKETEXT,.addr = 0}, { - PTRACE_POKETEXT,.addr = 1}, { - PTRACE_POKETEXT,.addr = 2}, { - PTRACE_POKETEXT,.addr = 3}, { - PTRACE_POKETEXT,.addr = -1}, { - PTRACE_POKETEXT,.addr = -2}, { - PTRACE_POKETEXT,.addr = -3}, { - PTRACE_POKETEXT,.addr = -4}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 1}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 2}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 3}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 4}, { - PTRACE_POKEUSER,.addr = -1}, { - PTRACE_POKEUSER,.addr = -2}, { - PTRACE_POKEUSER,.addr = -3}, { - PTRACE_POKEUSER,.addr = -4}, + PTRACE_PEEKDATA, .addr = 0}, { + PTRACE_PEEKDATA, .addr = 1}, { + PTRACE_PEEKDATA, .addr = 2}, { + PTRACE_PEEKDATA, .addr = 3}, { + PTRACE_PEEKDATA, .addr = -1}, { + PTRACE_PEEKDATA, .addr = -2}, { + PTRACE_PEEKDATA, .addr = -3}, { + PTRACE_PEEKDATA, .addr = -4}, { + PTRACE_PEEKTEXT, .addr = 0}, { + PTRACE_PEEKTEXT, .addr = 1}, { + PTRACE_PEEKTEXT, .addr = 2}, { + PTRACE_PEEKTEXT, .addr = 3}, { + PTRACE_PEEKTEXT, .addr = -1}, { + PTRACE_PEEKTEXT, .addr = -2}, { + PTRACE_PEEKTEXT, .addr = -3}, { + PTRACE_PEEKTEXT, .addr = -4}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 1}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 2}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 3}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 4}, { + PTRACE_PEEKUSER, .addr = -1}, { + PTRACE_PEEKUSER, .addr = -2}, { + PTRACE_PEEKUSER, .addr = -3}, { + PTRACE_PEEKUSER, .addr = -4}, { + PTRACE_POKEDATA, .addr = 0}, { + PTRACE_POKEDATA, .addr = 1}, { + PTRACE_POKEDATA, .addr = 2}, { + PTRACE_POKEDATA, .addr = 3}, { + PTRACE_POKEDATA, .addr = -1}, { + PTRACE_POKEDATA, .addr = -2}, { + PTRACE_POKEDATA, .addr = -3}, { + PTRACE_POKEDATA, .addr = -4}, { + PTRACE_POKETEXT, .addr = 0}, { + PTRACE_POKETEXT, .addr = 1}, { + PTRACE_POKETEXT, .addr = 2}, { + PTRACE_POKETEXT, .addr = 3}, { + PTRACE_POKETEXT, .addr = -1}, { + PTRACE_POKETEXT, .addr = -2}, { + PTRACE_POKETEXT, .addr = -3}, { + PTRACE_POKETEXT, .addr = -4}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 1}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 2}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 3}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 4}, { + PTRACE_POKEUSER, .addr = -1}, { + PTRACE_POKEUSER, .addr = -2}, { + PTRACE_POKEUSER, .addr = -3}, { + PTRACE_POKEUSER, .addr = -4}, #ifdef PTRACE_GETREGS { - PTRACE_GETREGS,.data = 0}, { - PTRACE_GETREGS,.data = 1}, { - PTRACE_GETREGS,.data = 2}, { - PTRACE_GETREGS,.data = 3}, { - PTRACE_GETREGS,.data = -1}, { - PTRACE_GETREGS,.data = -2}, { - PTRACE_GETREGS,.data = -3}, { - PTRACE_GETREGS,.data = -4}, + PTRACE_GETREGS, .data = 0}, { + PTRACE_GETREGS, .data = 1}, { + PTRACE_GETREGS, .data = 2}, { + PTRACE_GETREGS, .data = 3}, { + PTRACE_GETREGS, .data = -1}, { + PTRACE_GETREGS, .data = -2}, { + PTRACE_GETREGS, .data = -3}, { + PTRACE_GETREGS, .data = -4}, #endif #ifdef PTRACE_GETFGREGS { - PTRACE_GETFGREGS,.data = 0}, { - PTRACE_GETFGREGS,.data = 1}, { - PTRACE_GETFGREGS,.data = 2}, { - PTRACE_GETFGREGS,.data = 3}, { - PTRACE_GETFGREGS,.data = -1}, { - PTRACE_GETFGREGS,.data = -2}, { - PTRACE_GETFGREGS,.data = -3}, { - PTRACE_GETFGREGS,.data = -4}, + PTRACE_GETFGREGS, .data = 0}, { + PTRACE_GETFGREGS, .data = 1}, { + PTRACE_GETFGREGS, .data = 2}, { + PTRACE_GETFGREGS, .data = 3}, { + PTRACE_GETFGREGS, .data = -1}, { + PTRACE_GETFGREGS, .data = -2}, { + PTRACE_GETFGREGS, .data = -3}, { + PTRACE_GETFGREGS, .data = -4}, #endif #ifdef PTRACE_SETREGS { - PTRACE_SETREGS,.data = 0}, { - PTRACE_SETREGS,.data = 1}, { - PTRACE_SETREGS,.data = 2}, { - PTRACE_SETREGS,.data = 3}, { - PTRACE_SETREGS,.data = -1}, { - PTRACE_SETREGS,.data = -2}, { - PTRACE_SETREGS,.data = -3}, { - PTRACE_SETREGS,.data = -4}, + PTRACE_SETREGS, .data = 0}, { + PTRACE_SETREGS, .data = 1}, { + PTRACE_SETREGS, .data = 2}, { + PTRACE_SETREGS, .data = 3}, { + PTRACE_SETREGS, .data = -1}, { + PTRACE_SETREGS, .data = -2}, { + PTRACE_SETREGS, .data = -3}, { + PTRACE_SETREGS, .data = -4}, #endif #ifdef PTRACE_SETFGREGS { - PTRACE_SETFGREGS,.data = 0}, { - PTRACE_SETFGREGS,.data = 1}, { - PTRACE_SETFGREGS,.data = 2}, { - PTRACE_SETFGREGS,.data = 3}, { - PTRACE_SETFGREGS,.data = -1}, { - PTRACE_SETFGREGS,.data = -2}, { - PTRACE_SETFGREGS,.data = -3}, { - PTRACE_SETFGREGS,.data = -4}, + PTRACE_SETFGREGS, .data = 0}, { + PTRACE_SETFGREGS, .data = 1}, { + PTRACE_SETFGREGS, .data = 2}, { + PTRACE_SETFGREGS, .data = 3}, { + PTRACE_SETFGREGS, .data = -1}, { + PTRACE_SETFGREGS, .data = -2}, { + PTRACE_SETFGREGS, .data = -3}, { + PTRACE_SETFGREGS, .data = -4}, #endif #if HAVE_DECL_PTRACE_GETSIGINFO { - PTRACE_GETSIGINFO,.data = 0}, { - PTRACE_GETSIGINFO,.data = 1}, { - PTRACE_GETSIGINFO,.data = 2}, { - PTRACE_GETSIGINFO,.data = 3}, { - PTRACE_GETSIGINFO,.data = -1}, { - PTRACE_GETSIGINFO,.data = -2}, { - PTRACE_GETSIGINFO,.data = -3}, { - PTRACE_GETSIGINFO,.data = -4}, + PTRACE_GETSIGINFO, .data = 0}, { + PTRACE_GETSIGINFO, .data = 1}, { + PTRACE_GETSIGINFO, .data = 2}, { + PTRACE_GETSIGINFO, .data = 3}, { + PTRACE_GETSIGINFO, .data = -1}, { + PTRACE_GETSIGINFO, .data = -2}, { + PTRACE_GETSIGINFO, .data = -3}, { + PTRACE_GETSIGINFO, .data = -4}, #endif #if HAVE_DECL_PTRACE_SETSIGINFO { - PTRACE_SETSIGINFO,.data = 0}, { - PTRACE_SETSIGINFO,.data = 1}, { - PTRACE_SETSIGINFO,.data = 2}, { - PTRACE_SETSIGINFO,.data = 3}, { - PTRACE_SETSIGINFO,.data = -1}, { - PTRACE_SETSIGINFO,.data = -2}, { - PTRACE_SETSIGINFO,.data = -3}, { - PTRACE_SETSIGINFO,.data = -4}, + PTRACE_SETSIGINFO, .data = 0}, { + PTRACE_SETSIGINFO, .data = 1}, { + PTRACE_SETSIGINFO, .data = 2}, { + PTRACE_SETSIGINFO, .data = 3}, { + PTRACE_SETSIGINFO, .data = -1}, { + PTRACE_SETSIGINFO, .data = -2}, { + PTRACE_SETSIGINFO, .data = -3}, { + PTRACE_SETSIGINFO, .data = -4}, +#endif +}; + +#define SPT(x) [PTRACE_##x] = #x, +static char *strings[] = { + SPT(TRACEME) + SPT(PEEKTEXT) + SPT(PEEKDATA) + SPT(PEEKUSER) + SPT(POKETEXT) + SPT(POKEDATA) + SPT(POKEUSER) +#ifdef PTRACE_GETREGS + SPT(GETREGS) +#endif +#ifdef PTRACE_SETREGS + SPT(SETREGS) +#endif +#ifdef PTRACE_GETSIGINFO + SPT(GETSIGINFO) +#endif +#ifdef PTRACE_SETSIGINFO + SPT(SETSIGINFO) +#endif +#ifdef PTRACE_GETFGREGS + SPT(GETFGREGS) +#endif +#ifdef PTRACE_SETFGREGS + SPT(SETFGREGS) #endif + SPT(KILL) + SPT(SINGLESTEP) }; -int TST_TOTAL = ARRAY_SIZE(test_cases); +static inline char *strptrace(int request) +{ + return strings[request]; +} + +static void child(void) +{ + SAFE_PTRACE(PTRACE_TRACEME, 0, NULL, NULL); + execl("/bin/echo", "/bin/echo", NULL); + exit(0); +} -int main(int argc, char *argv[]) +static void run(void) { size_t i; - long ret; - int saved_errno; + int pid; + int status; - tst_parse_opts(argc, argv, NULL, NULL); + pid = SAFE_FORK(); - make_a_baby(argc, argv); + if (!pid) + child(); + + SAFE_WAIT(&status); + + if (!WIFSTOPPED(status)) + tst_brk(TBROK, "child %d was not stopped", pid); for (i = 0; i < ARRAY_SIZE(test_cases); ++i) { struct test_case_t *tc = &test_cases[i]; - errno = 0; - ret = - ptrace(tc->request, pid, (void *)tc->addr, - (void *)tc->data); - saved_errno = errno; - if (ret != -1) - tst_resm(TFAIL, + TEST(ptrace(tc->request, pid, (void *)tc->addr, + (void *)tc->data)); + if (TST_RET != -1) + tst_brk(TFAIL | TERRNO, "ptrace(%s, ..., %li, %li) returned %li instead of -1", strptrace(tc->request), tc->addr, tc->data, - ret); - else if (saved_errno != EIO && saved_errno != EFAULT) - tst_resm(TFAIL, + TST_RET); + else if (TST_ERR != EIO && TST_ERR != EFAULT) + tst_brk(TFAIL | TERRNO, "ptrace(%s, ..., %li, %li) expected errno EIO or EFAULT; actual: %i (%s)", strptrace(tc->request), tc->addr, tc->data, - saved_errno, strerror(saved_errno)); + TST_ERR, strerror(TST_ERR)); else - tst_resm(TPASS, + tst_res(TPASS, "ptrace(%s, ..., %li, %li) failed as expected", strptrace(tc->request), tc->addr, tc->data); } - /* hopefully this worked */ - ptrace(PTRACE_KILL, pid, NULL, NULL); + SAFE_PTRACE(PTRACE_CONT, pid, NULL, NULL); - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; -- 2.35.3 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [LTP] [PATCH v1 2/2] d 2023-09-25 11:04 ` [LTP] [PATCH v1 2/2] d Wei Gao via ltp @ 2023-09-25 11:36 ` Wei Gao via ltp 0 siblings, 0 replies; 6+ messages in thread From: Wei Gao via ltp @ 2023-09-25 11:36 UTC (permalink / raw) To: Wei Gao, ltp@lists.linux.it Sorry for the garbage email, please SKIP this email. -----Original Message----- From: Wei Gao <wegao@suse.com> Sent: Monday, September 25, 2023 7:04 PM To: Wei Gao <wegao@suse.com>; ltp@lists.linux.it Subject: [PATCH v1 2/2] d Signed-off-by: Wei Gao <wegao@suse.com> --- testcases/kernel/syscalls/ptrace/ptrace05.c | 147 +++------- testcases/kernel/syscalls/ptrace/ptrace06.c | 306 +++++++++++--------- 2 files changed, 214 insertions(+), 239 deletions(-) diff --git a/testcases/kernel/syscalls/ptrace/ptrace05.c b/testcases/kernel/syscalls/ptrace/ptrace05.c index 54cfa4d7b..4904b959c 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace05.c +++ b/testcases/kernel/syscalls/ptrace/ptrace05.c @@ -1,122 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - ****************************************************************************** - * - * ptrace05 - an app which ptraces itself as per arbitrarily specified signals, - * over a user specified range. - * - * Copyright (C) 2009, Ngie Cooper - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2009, Ngie Cooper + * Copyright (c) 2023 Wei Gao <wegao@suse.com> */ + +/*\ + * [Description] * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * ptrace05 - an app which ptraces itself as per arbitrarily specified + signals * - ****************************************************************************** */ -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> -#include <errno.h> -#include <libgen.h> -#include <math.h> #include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - #include <config.h> #include "ptrace.h" -#include "test.h" #include "lapi/signal.h" +#include "tst_test.h" -char *TCID = "ptrace05"; -int TST_TOTAL = 0; - -int usage(const char *); - -int usage(const char *argv0) -{ - fprintf(stderr, "usage: %s [start-signum] [end-signum]\n", argv0); - return 1; -} - -int main(int argc, char **argv) +static void run(void) { - int end_signum = -1; - int signum; - int start_signum = -1; + int end_signum = SIGRTMAX; + int signum = 0; + int start_signum = 0; int status; pid_t child; - tst_parse_opts(argc, argv, NULL, NULL); - - if (start_signum == -1) { - start_signum = 0; - } - if (end_signum == -1) { - end_signum = SIGRTMAX; - } - for (signum = start_signum; signum <= end_signum; signum++) { - if (signum >= __SIGRTMIN && signum < SIGRTMIN) - continue; - - switch (child = fork()) { + switch (child = SAFE_FORK()) { case -1: - tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); + tst_brk(TBROK | TERRNO, "fork() failed"); case 0: - if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != -1) { - tst_resm(TINFO, "[child] Sending kill(.., %d)", - signum); - if (kill(getpid(), signum) < 0) { - tst_resm(TINFO | TERRNO, - "[child] kill(.., %d) failed.", - signum); - } + TEST(ptrace(PTRACE_TRACEME, 0, NULL, NULL)); + if (TST_RET != -1) { + tst_res(TINFO, "[child] Sending kill(.., %d)", + signum); + SAFE_KILL(getpid(), signum); } else { - - /* - * This won't increment the TST_COUNT var. - * properly, but it'll show up as a failure - * nonetheless. - */ - tst_resm(TFAIL | TERRNO, + tst_brk(TFAIL | TERRNO, "Failed to ptrace(PTRACE_TRACEME, ...) " "properly"); - } - /* Shouldn't get here if signum == 0. */ - exit((signum == 0 ? 0 : 2)); + + exit(0); break; default: - waitpid(child, &status, 0); + SAFE_WAITPID(child, &status, 0); switch (signum) { case 0: if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - tst_resm(TPASS, + tst_res(TPASS, "kill(.., 0) exited " "with 0, as expected."); } else { - tst_resm(TFAIL, + tst_brk(TFAIL | TERRNO, "kill(.., 0) didn't exit " "with 0."); } @@ -125,20 +70,20 @@ int main(int argc, char **argv) if (WIFSIGNALED(status)) { /* SIGKILL must be uncatchable. */ if (WTERMSIG(status) == SIGKILL) { - tst_resm(TPASS, + tst_res(TPASS, "Killed with SIGKILL, " "as expected."); } else { - tst_resm(TPASS, + tst_brk(TFAIL | TERRNO, "Didn't die with " "SIGKILL (?!) "); } } else if (WIFEXITED(status)) { - tst_resm(TFAIL, + tst_brk(TFAIL | TERRNO, "Exited unexpectedly instead " "of dying with SIGKILL."); } else if (WIFSTOPPED(status)) { - tst_resm(TFAIL, + tst_brk(TFAIL | TERRNO, "Stopped instead of dying " "with SIGKILL."); } @@ -146,35 +91,21 @@ int main(int argc, char **argv) /* All other processes should be stopped. */ default: if (WIFSTOPPED(status)) { - tst_resm(TPASS, "Stopped as expected"); + tst_res(TPASS, "Stopped as expected"); } else { - tst_resm(TFAIL, "Didn't stop as " + tst_brk(TFAIL | TERRNO, "Didn't stop as " "expected."); - if (kill(child, 0)) { - tst_resm(TINFO, - "Is still alive!?"); - } else if (WIFEXITED(status)) { - tst_resm(TINFO, - "Exited normally"); - } else if (WIFSIGNALED(status)) { - tst_resm(TINFO, - "Was signaled with " - "signum=%d", - WTERMSIG(status)); - } - } - break; - } - } - /* Make sure the child dies a quick and painless death ... */ - kill(child, 9); + if (signum != 0 && signum != 9) + SAFE_PTRACE(PTRACE_CONT, child, NULL, NULL); } - - tst_exit(); - } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/ptrace/ptrace06.c b/testcases/kernel/syscalls/ptrace/ptrace06.c index c0cb3b9bd..5829faea4 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace06.c +++ b/testcases/kernel/syscalls/ptrace/ptrace06.c @@ -1,32 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2008 Analog Devices Inc. + * Copyright (c) 2023 Wei Gao <wegao@suse.com> */ + +/*\ + * [Description] + * * check out-of-bound/unaligned addresses given to * - {PEEK,POKE}{DATA,TEXT,USER} * - {GET,SET}{,FG}REGS * - {GET,SET}SIGINFO * - * Copyright (c) 2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later */ #define _GNU_SOURCE -#include <errno.h> -#include <stdbool.h> -#include <stdio.h> #include <stdlib.h> -#include <unistd.h> - #include <config.h> -#include "ptrace.h" -#include "test.h" -#include "spawn_ptrace_child.h" -#include "config.h" +#include "ptrace.h" +#include "tst_test.h" /* this should be sizeof(struct user), but that info is only found * in the kernel asm/user.h which is not exported to userspace. */ + #if defined(__i386__) #define SIZEOF_USER 284 #elif defined(__x86_64__) @@ -35,168 +34,213 @@ #define SIZEOF_USER 0x1000 /* just pick a big number */ #endif -char *TCID = "ptrace06"; - struct test_case_t { int request; long addr; long data; } test_cases[] = { { - PTRACE_PEEKDATA,.addr = 0}, { - PTRACE_PEEKDATA,.addr = 1}, { - PTRACE_PEEKDATA,.addr = 2}, { - PTRACE_PEEKDATA,.addr = 3}, { - PTRACE_PEEKDATA,.addr = -1}, { - PTRACE_PEEKDATA,.addr = -2}, { - PTRACE_PEEKDATA,.addr = -3}, { - PTRACE_PEEKDATA,.addr = -4}, { - PTRACE_PEEKTEXT,.addr = 0}, { - PTRACE_PEEKTEXT,.addr = 1}, { - PTRACE_PEEKTEXT,.addr = 2}, { - PTRACE_PEEKTEXT,.addr = 3}, { - PTRACE_PEEKTEXT,.addr = -1}, { - PTRACE_PEEKTEXT,.addr = -2}, { - PTRACE_PEEKTEXT,.addr = -3}, { - PTRACE_PEEKTEXT,.addr = -4}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 1}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 2}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 3}, { - PTRACE_PEEKUSER,.addr = SIZEOF_USER + 4}, { - PTRACE_PEEKUSER,.addr = -1}, { - PTRACE_PEEKUSER,.addr = -2}, { - PTRACE_PEEKUSER,.addr = -3}, { - PTRACE_PEEKUSER,.addr = -4}, { - PTRACE_POKEDATA,.addr = 0}, { - PTRACE_POKEDATA,.addr = 1}, { - PTRACE_POKEDATA,.addr = 2}, { - PTRACE_POKEDATA,.addr = 3}, { - PTRACE_POKEDATA,.addr = -1}, { - PTRACE_POKEDATA,.addr = -2}, { - PTRACE_POKEDATA,.addr = -3}, { - PTRACE_POKEDATA,.addr = -4}, { - PTRACE_POKETEXT,.addr = 0}, { - PTRACE_POKETEXT,.addr = 1}, { - PTRACE_POKETEXT,.addr = 2}, { - PTRACE_POKETEXT,.addr = 3}, { - PTRACE_POKETEXT,.addr = -1}, { - PTRACE_POKETEXT,.addr = -2}, { - PTRACE_POKETEXT,.addr = -3}, { - PTRACE_POKETEXT,.addr = -4}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 1}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 2}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 3}, { - PTRACE_POKEUSER,.addr = SIZEOF_USER + 4}, { - PTRACE_POKEUSER,.addr = -1}, { - PTRACE_POKEUSER,.addr = -2}, { - PTRACE_POKEUSER,.addr = -3}, { - PTRACE_POKEUSER,.addr = -4}, + PTRACE_PEEKDATA, .addr = 0}, { + PTRACE_PEEKDATA, .addr = 1}, { + PTRACE_PEEKDATA, .addr = 2}, { + PTRACE_PEEKDATA, .addr = 3}, { + PTRACE_PEEKDATA, .addr = -1}, { + PTRACE_PEEKDATA, .addr = -2}, { + PTRACE_PEEKDATA, .addr = -3}, { + PTRACE_PEEKDATA, .addr = -4}, { + PTRACE_PEEKTEXT, .addr = 0}, { + PTRACE_PEEKTEXT, .addr = 1}, { + PTRACE_PEEKTEXT, .addr = 2}, { + PTRACE_PEEKTEXT, .addr = 3}, { + PTRACE_PEEKTEXT, .addr = -1}, { + PTRACE_PEEKTEXT, .addr = -2}, { + PTRACE_PEEKTEXT, .addr = -3}, { + PTRACE_PEEKTEXT, .addr = -4}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 1}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 2}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 3}, { + PTRACE_PEEKUSER, .addr = SIZEOF_USER + 4}, { + PTRACE_PEEKUSER, .addr = -1}, { + PTRACE_PEEKUSER, .addr = -2}, { + PTRACE_PEEKUSER, .addr = -3}, { + PTRACE_PEEKUSER, .addr = -4}, { + PTRACE_POKEDATA, .addr = 0}, { + PTRACE_POKEDATA, .addr = 1}, { + PTRACE_POKEDATA, .addr = 2}, { + PTRACE_POKEDATA, .addr = 3}, { + PTRACE_POKEDATA, .addr = -1}, { + PTRACE_POKEDATA, .addr = -2}, { + PTRACE_POKEDATA, .addr = -3}, { + PTRACE_POKEDATA, .addr = -4}, { + PTRACE_POKETEXT, .addr = 0}, { + PTRACE_POKETEXT, .addr = 1}, { + PTRACE_POKETEXT, .addr = 2}, { + PTRACE_POKETEXT, .addr = 3}, { + PTRACE_POKETEXT, .addr = -1}, { + PTRACE_POKETEXT, .addr = -2}, { + PTRACE_POKETEXT, .addr = -3}, { + PTRACE_POKETEXT, .addr = -4}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 1}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 2}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 3}, { + PTRACE_POKEUSER, .addr = SIZEOF_USER + 4}, { + PTRACE_POKEUSER, .addr = -1}, { + PTRACE_POKEUSER, .addr = -2}, { + PTRACE_POKEUSER, .addr = -3}, { + PTRACE_POKEUSER, .addr = -4}, #ifdef PTRACE_GETREGS { - PTRACE_GETREGS,.data = 0}, { - PTRACE_GETREGS,.data = 1}, { - PTRACE_GETREGS,.data = 2}, { - PTRACE_GETREGS,.data = 3}, { - PTRACE_GETREGS,.data = -1}, { - PTRACE_GETREGS,.data = -2}, { - PTRACE_GETREGS,.data = -3}, { - PTRACE_GETREGS,.data = -4}, + PTRACE_GETREGS, .data = 0}, { + PTRACE_GETREGS, .data = 1}, { + PTRACE_GETREGS, .data = 2}, { + PTRACE_GETREGS, .data = 3}, { + PTRACE_GETREGS, .data = -1}, { + PTRACE_GETREGS, .data = -2}, { + PTRACE_GETREGS, .data = -3}, { + PTRACE_GETREGS, .data = -4}, #endif #ifdef PTRACE_GETFGREGS { - PTRACE_GETFGREGS,.data = 0}, { - PTRACE_GETFGREGS,.data = 1}, { - PTRACE_GETFGREGS,.data = 2}, { - PTRACE_GETFGREGS,.data = 3}, { - PTRACE_GETFGREGS,.data = -1}, { - PTRACE_GETFGREGS,.data = -2}, { - PTRACE_GETFGREGS,.data = -3}, { - PTRACE_GETFGREGS,.data = -4}, + PTRACE_GETFGREGS, .data = 0}, { + PTRACE_GETFGREGS, .data = 1}, { + PTRACE_GETFGREGS, .data = 2}, { + PTRACE_GETFGREGS, .data = 3}, { + PTRACE_GETFGREGS, .data = -1}, { + PTRACE_GETFGREGS, .data = -2}, { + PTRACE_GETFGREGS, .data = -3}, { + PTRACE_GETFGREGS, .data = -4}, #endif #ifdef PTRACE_SETREGS { - PTRACE_SETREGS,.data = 0}, { - PTRACE_SETREGS,.data = 1}, { - PTRACE_SETREGS,.data = 2}, { - PTRACE_SETREGS,.data = 3}, { - PTRACE_SETREGS,.data = -1}, { - PTRACE_SETREGS,.data = -2}, { - PTRACE_SETREGS,.data = -3}, { - PTRACE_SETREGS,.data = -4}, + PTRACE_SETREGS, .data = 0}, { + PTRACE_SETREGS, .data = 1}, { + PTRACE_SETREGS, .data = 2}, { + PTRACE_SETREGS, .data = 3}, { + PTRACE_SETREGS, .data = -1}, { + PTRACE_SETREGS, .data = -2}, { + PTRACE_SETREGS, .data = -3}, { + PTRACE_SETREGS, .data = -4}, #endif #ifdef PTRACE_SETFGREGS { - PTRACE_SETFGREGS,.data = 0}, { - PTRACE_SETFGREGS,.data = 1}, { - PTRACE_SETFGREGS,.data = 2}, { - PTRACE_SETFGREGS,.data = 3}, { - PTRACE_SETFGREGS,.data = -1}, { - PTRACE_SETFGREGS,.data = -2}, { - PTRACE_SETFGREGS,.data = -3}, { - PTRACE_SETFGREGS,.data = -4}, + PTRACE_SETFGREGS, .data = 0}, { + PTRACE_SETFGREGS, .data = 1}, { + PTRACE_SETFGREGS, .data = 2}, { + PTRACE_SETFGREGS, .data = 3}, { + PTRACE_SETFGREGS, .data = -1}, { + PTRACE_SETFGREGS, .data = -2}, { + PTRACE_SETFGREGS, .data = -3}, { + PTRACE_SETFGREGS, .data = -4}, #endif #if HAVE_DECL_PTRACE_GETSIGINFO { - PTRACE_GETSIGINFO,.data = 0}, { - PTRACE_GETSIGINFO,.data = 1}, { - PTRACE_GETSIGINFO,.data = 2}, { - PTRACE_GETSIGINFO,.data = 3}, { - PTRACE_GETSIGINFO,.data = -1}, { - PTRACE_GETSIGINFO,.data = -2}, { - PTRACE_GETSIGINFO,.data = -3}, { - PTRACE_GETSIGINFO,.data = -4}, + PTRACE_GETSIGINFO, .data = 0}, { + PTRACE_GETSIGINFO, .data = 1}, { + PTRACE_GETSIGINFO, .data = 2}, { + PTRACE_GETSIGINFO, .data = 3}, { + PTRACE_GETSIGINFO, .data = -1}, { + PTRACE_GETSIGINFO, .data = -2}, { + PTRACE_GETSIGINFO, .data = -3}, { + PTRACE_GETSIGINFO, .data = -4}, #endif #if HAVE_DECL_PTRACE_SETSIGINFO { - PTRACE_SETSIGINFO,.data = 0}, { - PTRACE_SETSIGINFO,.data = 1}, { - PTRACE_SETSIGINFO,.data = 2}, { - PTRACE_SETSIGINFO,.data = 3}, { - PTRACE_SETSIGINFO,.data = -1}, { - PTRACE_SETSIGINFO,.data = -2}, { - PTRACE_SETSIGINFO,.data = -3}, { - PTRACE_SETSIGINFO,.data = -4}, + PTRACE_SETSIGINFO, .data = 0}, { + PTRACE_SETSIGINFO, .data = 1}, { + PTRACE_SETSIGINFO, .data = 2}, { + PTRACE_SETSIGINFO, .data = 3}, { + PTRACE_SETSIGINFO, .data = -1}, { + PTRACE_SETSIGINFO, .data = -2}, { + PTRACE_SETSIGINFO, .data = -3}, { + PTRACE_SETSIGINFO, .data = -4}, +#endif +}; + +#define SPT(x) [PTRACE_##x] = #x, +static char *strings[] = { + SPT(TRACEME) + SPT(PEEKTEXT) + SPT(PEEKDATA) + SPT(PEEKUSER) + SPT(POKETEXT) + SPT(POKEDATA) + SPT(POKEUSER) +#ifdef PTRACE_GETREGS + SPT(GETREGS) +#endif +#ifdef PTRACE_SETREGS + SPT(SETREGS) +#endif +#ifdef PTRACE_GETSIGINFO + SPT(GETSIGINFO) +#endif +#ifdef PTRACE_SETSIGINFO + SPT(SETSIGINFO) +#endif +#ifdef PTRACE_GETFGREGS + SPT(GETFGREGS) +#endif +#ifdef PTRACE_SETFGREGS + SPT(SETFGREGS) #endif + SPT(KILL) + SPT(SINGLESTEP) }; -int TST_TOTAL = ARRAY_SIZE(test_cases); +static inline char *strptrace(int request) { + return strings[request]; +} + +static void child(void) +{ + SAFE_PTRACE(PTRACE_TRACEME, 0, NULL, NULL); + execl("/bin/echo", "/bin/echo", NULL); + exit(0); +} -int main(int argc, char *argv[]) +static void run(void) { size_t i; - long ret; - int saved_errno; + int pid; + int status; - tst_parse_opts(argc, argv, NULL, NULL); + pid = SAFE_FORK(); - make_a_baby(argc, argv); + if (!pid) + child(); + + SAFE_WAIT(&status); + + if (!WIFSTOPPED(status)) + tst_brk(TBROK, "child %d was not stopped", pid); for (i = 0; i < ARRAY_SIZE(test_cases); ++i) { struct test_case_t *tc = &test_cases[i]; - errno = 0; - ret = - ptrace(tc->request, pid, (void *)tc->addr, - (void *)tc->data); - saved_errno = errno; - if (ret != -1) - tst_resm(TFAIL, + TEST(ptrace(tc->request, pid, (void *)tc->addr, + (void *)tc->data)); + if (TST_RET != -1) + tst_brk(TFAIL | TERRNO, "ptrace(%s, ..., %li, %li) returned %li instead of -1", strptrace(tc->request), tc->addr, tc->data, - ret); - else if (saved_errno != EIO && saved_errno != EFAULT) - tst_resm(TFAIL, + TST_RET); + else if (TST_ERR != EIO && TST_ERR != EFAULT) + tst_brk(TFAIL | TERRNO, "ptrace(%s, ..., %li, %li) expected errno EIO or EFAULT; actual: %i (%s)", strptrace(tc->request), tc->addr, tc->data, - saved_errno, strerror(saved_errno)); + TST_ERR, strerror(TST_ERR)); else - tst_resm(TPASS, + tst_res(TPASS, "ptrace(%s, ..., %li, %li) failed as expected", strptrace(tc->request), tc->addr, tc->data); } - /* hopefully this worked */ - ptrace(PTRACE_KILL, pid, NULL, NULL); + SAFE_PTRACE(PTRACE_CONT, pid, NULL, NULL); - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; -- 2.35.3 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [LTP] [PATCH v1 0/2] factory 2023-09-25 11:04 [LTP] [PATCH v1 0/2] factory Wei Gao via ltp 2023-09-25 11:04 ` [LTP] [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check Wei Gao via ltp 2023-09-25 11:04 ` [LTP] [PATCH v1 2/2] d Wei Gao via ltp @ 2023-09-25 11:31 ` Wei Gao via ltp 2 siblings, 0 replies; 6+ messages in thread From: Wei Gao via ltp @ 2023-09-25 11:31 UTC (permalink / raw) To: ltp On Mon, Sep 25, 2023 at 07:04:20AM -0400, Wei Gao wrote: > Wei Gao (2): > seccomp01.c: Add SECCOMP_RET_USER_NOTIF check > d > > configure.ac | 1 + > include/lapi/seccomp.h | 7 + > runtest/syscalls | 2 + > testcases/kernel/syscalls/ptrace/ptrace05.c | 147 ++---- > testcases/kernel/syscalls/ptrace/ptrace06.c | 306 +++++++----- > testcases/kernel/syscalls/seccomp/.gitignore | 1 + > testcases/kernel/syscalls/seccomp/Makefile | 8 + > testcases/kernel/syscalls/seccomp/seccomp01.c | 456 ++++++++++++++++++ > 8 files changed, 689 insertions(+), 239 deletions(-) > create mode 100644 testcases/kernel/syscalls/seccomp/.gitignore > create mode 100644 testcases/kernel/syscalls/seccomp/Makefile > create mode 100644 testcases/kernel/syscalls/seccomp/seccomp01.c > > -- > 2.35.3 > Sorry for the garbage email, please skip this serial email -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-09-25 11:36 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-09-25 11:04 [LTP] [PATCH v1 0/2] factory Wei Gao via ltp 2023-09-25 11:04 ` [LTP] [PATCH v1 1/2] seccomp01.c: Add SECCOMP_RET_USER_NOTIF check Wei Gao via ltp 2023-09-25 11:36 ` Wei Gao via ltp 2023-09-25 11:04 ` [LTP] [PATCH v1 2/2] d Wei Gao via ltp 2023-09-25 11:36 ` Wei Gao via ltp 2023-09-25 11:31 ` [LTP] [PATCH v1 0/2] factory Wei Gao via ltp
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox