* [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
* [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 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
* 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 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
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