cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pidfd_wait.c (5431B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2
      3#define _GNU_SOURCE
      4#include <errno.h>
      5#include <linux/sched.h>
      6#include <linux/types.h>
      7#include <signal.h>
      8#include <stdint.h>
      9#include <stdio.h>
     10#include <stdlib.h>
     11#include <sched.h>
     12#include <string.h>
     13#include <sys/resource.h>
     14#include <sys/time.h>
     15#include <sys/types.h>
     16#include <sys/wait.h>
     17#include <unistd.h>
     18
     19#include "pidfd.h"
     20#include "../kselftest_harness.h"
     21
     22#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
     23
     24/* Attempt to de-conflict with the selftests tree. */
     25#ifndef SKIP
     26#define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
     27#endif
     28
     29static pid_t sys_clone3(struct clone_args *args)
     30{
     31	return syscall(__NR_clone3, args, sizeof(struct clone_args));
     32}
     33
     34static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
     35		      struct rusage *ru)
     36{
     37	return syscall(__NR_waitid, which, pid, info, options, ru);
     38}
     39
     40TEST(wait_simple)
     41{
     42	int pidfd = -1;
     43	pid_t parent_tid = -1;
     44	struct clone_args args = {
     45		.parent_tid = ptr_to_u64(&parent_tid),
     46		.pidfd = ptr_to_u64(&pidfd),
     47		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
     48		.exit_signal = SIGCHLD,
     49	};
     50	pid_t pid;
     51	siginfo_t info = {
     52		.si_signo = 0,
     53	};
     54
     55	pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
     56	ASSERT_GE(pidfd, 0);
     57
     58	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
     59	ASSERT_NE(pid, 0);
     60	EXPECT_EQ(close(pidfd), 0);
     61	pidfd = -1;
     62
     63	pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
     64	ASSERT_GE(pidfd, 0);
     65
     66	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
     67	ASSERT_NE(pid, 0);
     68	EXPECT_EQ(close(pidfd), 0);
     69	pidfd = -1;
     70
     71	pid = sys_clone3(&args);
     72	ASSERT_GE(pid, 0);
     73
     74	if (pid == 0)
     75		exit(EXIT_SUCCESS);
     76
     77	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
     78	ASSERT_GE(pid, 0);
     79	ASSERT_EQ(WIFEXITED(info.si_status), true);
     80	ASSERT_EQ(WEXITSTATUS(info.si_status), 0);
     81	EXPECT_EQ(close(pidfd), 0);
     82
     83	ASSERT_EQ(info.si_signo, SIGCHLD);
     84	ASSERT_EQ(info.si_code, CLD_EXITED);
     85	ASSERT_EQ(info.si_pid, parent_tid);
     86}
     87
     88TEST(wait_states)
     89{
     90	int pidfd = -1;
     91	pid_t parent_tid = -1;
     92	struct clone_args args = {
     93		.parent_tid = ptr_to_u64(&parent_tid),
     94		.pidfd = ptr_to_u64(&pidfd),
     95		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
     96		.exit_signal = SIGCHLD,
     97	};
     98	pid_t pid;
     99	siginfo_t info = {
    100		.si_signo = 0,
    101	};
    102
    103	pid = sys_clone3(&args);
    104	ASSERT_GE(pid, 0);
    105
    106	if (pid == 0) {
    107		kill(getpid(), SIGSTOP);
    108		kill(getpid(), SIGSTOP);
    109		exit(EXIT_SUCCESS);
    110	}
    111
    112	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
    113	ASSERT_EQ(info.si_signo, SIGCHLD);
    114	ASSERT_EQ(info.si_code, CLD_STOPPED);
    115	ASSERT_EQ(info.si_pid, parent_tid);
    116
    117	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
    118
    119	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0);
    120	ASSERT_EQ(info.si_signo, SIGCHLD);
    121	ASSERT_EQ(info.si_code, CLD_CONTINUED);
    122	ASSERT_EQ(info.si_pid, parent_tid);
    123
    124	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0);
    125	ASSERT_EQ(info.si_signo, SIGCHLD);
    126	ASSERT_EQ(info.si_code, CLD_STOPPED);
    127	ASSERT_EQ(info.si_pid, parent_tid);
    128
    129	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
    130
    131	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
    132	ASSERT_EQ(info.si_signo, SIGCHLD);
    133	ASSERT_EQ(info.si_code, CLD_KILLED);
    134	ASSERT_EQ(info.si_pid, parent_tid);
    135
    136	EXPECT_EQ(close(pidfd), 0);
    137}
    138
    139TEST(wait_nonblock)
    140{
    141	int pidfd, status = 0;
    142	unsigned int flags = 0;
    143	pid_t parent_tid = -1;
    144	struct clone_args args = {
    145		.parent_tid = ptr_to_u64(&parent_tid),
    146		.flags = CLONE_PARENT_SETTID,
    147		.exit_signal = SIGCHLD,
    148	};
    149	int ret;
    150	pid_t pid;
    151	siginfo_t info = {
    152		.si_signo = 0,
    153	};
    154
    155	/*
    156	 * Callers need to see ECHILD with non-blocking pidfds when no child
    157	 * processes exists.
    158	 */
    159	pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
    160	EXPECT_GE(pidfd, 0) {
    161		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
    162		ASSERT_EQ(errno, EINVAL);
    163		SKIP(return, "Skipping PIDFD_NONBLOCK test");
    164	}
    165
    166	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
    167	ASSERT_LT(ret, 0);
    168	ASSERT_EQ(errno, ECHILD);
    169	EXPECT_EQ(close(pidfd), 0);
    170
    171	pid = sys_clone3(&args);
    172	ASSERT_GE(pid, 0);
    173
    174	if (pid == 0) {
    175		kill(getpid(), SIGSTOP);
    176		exit(EXIT_SUCCESS);
    177	}
    178
    179	pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
    180	EXPECT_GE(pidfd, 0) {
    181		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
    182		ASSERT_EQ(errno, EINVAL);
    183		SKIP(return, "Skipping PIDFD_NONBLOCK test");
    184	}
    185
    186	flags = fcntl(pidfd, F_GETFL, 0);
    187	ASSERT_GT(flags, 0);
    188	ASSERT_GT((flags & O_NONBLOCK), 0);
    189
    190	/*
    191	 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
    192	 * child processes exist but none have exited.
    193	 */
    194	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
    195	ASSERT_LT(ret, 0);
    196	ASSERT_EQ(errno, EAGAIN);
    197
    198	/*
    199	 * Callers need to continue seeing 0 with non-blocking pidfd and
    200	 * WNOHANG raised explicitly when child processes exist but none have
    201	 * exited.
    202	 */
    203	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
    204	ASSERT_EQ(ret, 0);
    205
    206	ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
    207
    208	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
    209	ASSERT_EQ(info.si_signo, SIGCHLD);
    210	ASSERT_EQ(info.si_code, CLD_STOPPED);
    211	ASSERT_EQ(info.si_pid, parent_tid);
    212
    213	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
    214
    215	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
    216	ASSERT_EQ(info.si_signo, SIGCHLD);
    217	ASSERT_EQ(info.si_code, CLD_EXITED);
    218	ASSERT_EQ(info.si_pid, parent_tid);
    219
    220	EXPECT_EQ(close(pidfd), 0);
    221}
    222
    223TEST_HARNESS_MAIN