aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/entry/syscalls/syscall_32.tbl1
-rw-r--r--arch/x86/entry/syscalls/syscall_64.tbl1
-rw-r--r--fs/proc/base.c9
-rw-r--r--include/linux/proc_fs.h6
-rw-r--r--include/linux/syscalls.h3
-rw-r--r--include/uapi/asm-generic/unistd.h2
-rw-r--r--kernel/signal.c133
-rw-r--r--kernel/sys_ni.c1
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/pidfd/Makefile6
-rw-r--r--tools/testing/selftests/pidfd/pidfd_test.c381
11 files changed, 538 insertions, 6 deletions
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 8da78595d69d..1f9607ed087c 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -429,6 +429,7 @@
429421 i386 rt_sigtimedwait_time64 sys_rt_sigtimedwait __ia32_compat_sys_rt_sigtimedwait_time64 429421 i386 rt_sigtimedwait_time64 sys_rt_sigtimedwait __ia32_compat_sys_rt_sigtimedwait_time64
430422 i386 futex_time64 sys_futex __ia32_sys_futex 430422 i386 futex_time64 sys_futex __ia32_sys_futex
431423 i386 sched_rr_get_interval_time64 sys_sched_rr_get_interval __ia32_sys_sched_rr_get_interval 431423 i386 sched_rr_get_interval_time64 sys_sched_rr_get_interval __ia32_sys_sched_rr_get_interval
432424 i386 pidfd_send_signal sys_pidfd_send_signal __ia32_sys_pidfd_send_signal
432425 i386 io_uring_setup sys_io_uring_setup __ia32_sys_io_uring_setup 433425 i386 io_uring_setup sys_io_uring_setup __ia32_sys_io_uring_setup
433426 i386 io_uring_enter sys_io_uring_enter __ia32_sys_io_uring_enter 434426 i386 io_uring_enter sys_io_uring_enter __ia32_sys_io_uring_enter
434427 i386 io_uring_register sys_io_uring_register __ia32_sys_io_uring_register 435427 i386 io_uring_register sys_io_uring_register __ia32_sys_io_uring_register
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index c768447f97ec..92ee0b4378d4 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -345,6 +345,7 @@
345334 common rseq __x64_sys_rseq 345334 common rseq __x64_sys_rseq
346# don't use numbers 387 through 423, add new calls after the last 346# don't use numbers 387 through 423, add new calls after the last
347# 'common' entry 347# 'common' entry
348424 common pidfd_send_signal __x64_sys_pidfd_send_signal
348425 common io_uring_setup __x64_sys_io_uring_setup 349425 common io_uring_setup __x64_sys_io_uring_setup
349426 common io_uring_enter __x64_sys_io_uring_enter 350426 common io_uring_enter __x64_sys_io_uring_enter
350427 common io_uring_register __x64_sys_io_uring_register 351427 common io_uring_register __x64_sys_io_uring_register
diff --git a/fs/proc/base.c b/fs/proc/base.c
index f5ebdd87afb2..ddef482f1334 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3074,6 +3074,15 @@ static const struct file_operations proc_tgid_base_operations = {
3074 .llseek = generic_file_llseek, 3074 .llseek = generic_file_llseek,
3075}; 3075};
3076 3076
3077struct pid *tgid_pidfd_to_pid(const struct file *file)
3078{
3079 if (!d_is_dir(file->f_path.dentry) ||
3080 (file->f_op != &proc_tgid_base_operations))
3081 return ERR_PTR(-EBADF);
3082
3083 return proc_pid(file_inode(file));
3084}
3085
3077static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 3086static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
3078{ 3087{
3079 return proc_pident_lookup(dir, dentry, 3088 return proc_pident_lookup(dir, dentry,
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index d0e1f1522a78..52a283ba0465 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -73,6 +73,7 @@ struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mo
73 int (*show)(struct seq_file *, void *), 73 int (*show)(struct seq_file *, void *),
74 proc_write_t write, 74 proc_write_t write,
75 void *data); 75 void *data);
76extern struct pid *tgid_pidfd_to_pid(const struct file *file);
76 77
77#else /* CONFIG_PROC_FS */ 78#else /* CONFIG_PROC_FS */
78 79
@@ -114,6 +115,11 @@ static inline int remove_proc_subtree(const char *name, struct proc_dir_entry *p
114#define proc_create_net(name, mode, parent, state_size, ops) ({NULL;}) 115#define proc_create_net(name, mode, parent, state_size, ops) ({NULL;})
115#define proc_create_net_single(name, mode, parent, show, data) ({NULL;}) 116#define proc_create_net_single(name, mode, parent, show, data) ({NULL;})
116 117
118static inline struct pid *tgid_pidfd_to_pid(const struct file *file)
119{
120 return ERR_PTR(-EBADF);
121}
122
117#endif /* CONFIG_PROC_FS */ 123#endif /* CONFIG_PROC_FS */
118 124
119struct net; 125struct net;
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index c2962953bf11..e446806a561f 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -985,6 +985,9 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
985 unsigned mask, struct statx __user *buffer); 985 unsigned mask, struct statx __user *buffer);
986asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len, 986asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len,
987 int flags, uint32_t sig); 987 int flags, uint32_t sig);
988asmlinkage long sys_pidfd_send_signal(int pidfd, int sig,
989 siginfo_t __user *info,
990 unsigned int flags);
988 991
989/* 992/*
990 * Architecture-specific system calls 993 * Architecture-specific system calls
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index bf4624efe5e6..dee7292e1df6 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -824,6 +824,8 @@ __SYSCALL(__NR_futex_time64, sys_futex)
824__SYSCALL(__NR_sched_rr_get_interval_time64, sys_sched_rr_get_interval) 824__SYSCALL(__NR_sched_rr_get_interval_time64, sys_sched_rr_get_interval)
825#endif 825#endif
826 826
827#define __NR_pidfd_send_signal 424
828__SYSCALL(__NR_pidfd_send_signal, sys_pidfd_send_signal)
827#define __NR_io_uring_setup 425 829#define __NR_io_uring_setup 425
828__SYSCALL(__NR_io_uring_setup, sys_io_uring_setup) 830__SYSCALL(__NR_io_uring_setup, sys_io_uring_setup)
829#define __NR_io_uring_enter 426 831#define __NR_io_uring_enter 426
diff --git a/kernel/signal.c b/kernel/signal.c
index 5d53183e2705..b7953934aa99 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -19,7 +19,9 @@
19#include <linux/sched/task.h> 19#include <linux/sched/task.h>
20#include <linux/sched/task_stack.h> 20#include <linux/sched/task_stack.h>
21#include <linux/sched/cputime.h> 21#include <linux/sched/cputime.h>
22#include <linux/file.h>
22#include <linux/fs.h> 23#include <linux/fs.h>
24#include <linux/proc_fs.h>
23#include <linux/tty.h> 25#include <linux/tty.h>
24#include <linux/binfmts.h> 26#include <linux/binfmts.h>
25#include <linux/coredump.h> 27#include <linux/coredump.h>
@@ -3487,6 +3489,16 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time32, compat_sigset_t __user *, uthese,
3487#endif 3489#endif
3488#endif 3490#endif
3489 3491
3492static inline void prepare_kill_siginfo(int sig, struct kernel_siginfo *info)
3493{
3494 clear_siginfo(info);
3495 info->si_signo = sig;
3496 info->si_errno = 0;
3497 info->si_code = SI_USER;
3498 info->si_pid = task_tgid_vnr(current);
3499 info->si_uid = from_kuid_munged(current_user_ns(), current_uid());
3500}
3501
3490/** 3502/**
3491 * sys_kill - send a signal to a process 3503 * sys_kill - send a signal to a process
3492 * @pid: the PID of the process 3504 * @pid: the PID of the process
@@ -3496,16 +3508,125 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
3496{ 3508{
3497 struct kernel_siginfo info; 3509 struct kernel_siginfo info;
3498 3510
3499 clear_siginfo(&info); 3511 prepare_kill_siginfo(sig, &info);
3500 info.si_signo = sig;
3501 info.si_errno = 0;
3502 info.si_code = SI_USER;
3503 info.si_pid = task_tgid_vnr(current);
3504 info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
3505 3512
3506 return kill_something_info(sig, &info, pid); 3513 return kill_something_info(sig, &info, pid);
3507} 3514}
3508 3515
3516#ifdef CONFIG_PROC_FS
3517/*
3518 * Verify that the signaler and signalee either are in the same pid namespace
3519 * or that the signaler's pid namespace is an ancestor of the signalee's pid
3520 * namespace.
3521 */
3522static bool access_pidfd_pidns(struct pid *pid)
3523{
3524 struct pid_namespace *active = task_active_pid_ns(current);
3525 struct pid_namespace *p = ns_of_pid(pid);
3526
3527 for (;;) {
3528 if (!p)
3529 return false;
3530 if (p == active)
3531 break;
3532 p = p->parent;
3533 }
3534
3535 return true;
3536}
3537
3538static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
3539{
3540#ifdef CONFIG_COMPAT
3541 /*
3542 * Avoid hooking up compat syscalls and instead handle necessary
3543 * conversions here. Note, this is a stop-gap measure and should not be
3544 * considered a generic solution.
3545 */
3546 if (in_compat_syscall())
3547 return copy_siginfo_from_user32(
3548 kinfo, (struct compat_siginfo __user *)info);
3549#endif
3550 return copy_siginfo_from_user(kinfo, info);
3551}
3552
3553/**
3554 * sys_pidfd_send_signal - send a signal to a process through a task file
3555 * descriptor
3556 * @pidfd: the file descriptor of the process
3557 * @sig: signal to be sent
3558 * @info: the signal info
3559 * @flags: future flags to be passed
3560 *
3561 * The syscall currently only signals via PIDTYPE_PID which covers
3562 * kill(<positive-pid>, <signal>. It does not signal threads or process
3563 * groups.
3564 * In order to extend the syscall to threads and process groups the @flags
3565 * argument should be used. In essence, the @flags argument will determine
3566 * what is signaled and not the file descriptor itself. Put in other words,
3567 * grouping is a property of the flags argument not a property of the file
3568 * descriptor.
3569 *
3570 * Return: 0 on success, negative errno on failure
3571 */
3572SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
3573 siginfo_t __user *, info, unsigned int, flags)
3574{
3575 int ret;
3576 struct fd f;
3577 struct pid *pid;
3578 kernel_siginfo_t kinfo;
3579
3580 /* Enforce flags be set to 0 until we add an extension. */
3581 if (flags)
3582 return -EINVAL;
3583
3584 f = fdget_raw(pidfd);
3585 if (!f.file)
3586 return -EBADF;
3587
3588 /* Is this a pidfd? */
3589 pid = tgid_pidfd_to_pid(f.file);
3590 if (IS_ERR(pid)) {
3591 ret = PTR_ERR(pid);
3592 goto err;
3593 }
3594
3595 ret = -EINVAL;
3596 if (!access_pidfd_pidns(pid))
3597 goto err;
3598
3599 if (info) {
3600 ret = copy_siginfo_from_user_any(&kinfo, info);
3601 if (unlikely(ret))
3602 goto err;
3603
3604 ret = -EINVAL;
3605 if (unlikely(sig != kinfo.si_signo))
3606 goto err;
3607
3608 if ((task_pid(current) != pid) &&
3609 (kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL)) {
3610 /* Only allow sending arbitrary signals to yourself. */
3611 ret = -EPERM;
3612 if (kinfo.si_code != SI_USER)
3613 goto err;
3614
3615 /* Turn this into a regular kill signal. */
3616 prepare_kill_siginfo(sig, &kinfo);
3617 }
3618 } else {
3619 prepare_kill_siginfo(sig, &kinfo);
3620 }
3621
3622 ret = kill_pid_info(sig, &kinfo, pid);
3623
3624err:
3625 fdput(f);
3626 return ret;
3627}
3628#endif /* CONFIG_PROC_FS */
3629
3509static int 3630static int
3510do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info) 3631do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info)
3511{ 3632{
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 51d7c6794bf1..d21f4befaea4 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -168,6 +168,7 @@ COND_SYSCALL(syslog);
168/* kernel/sched/core.c */ 168/* kernel/sched/core.c */
169 169
170/* kernel/signal.c */ 170/* kernel/signal.c */
171COND_SYSCALL(pidfd_send_signal);
171 172
172/* kernel/sys.c */ 173/* kernel/sys.c */
173COND_SYSCALL(setregid); 174COND_SYSCALL(setregid);
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index fb5758ac469e..971fc8428117 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -32,6 +32,7 @@ TARGETS += net
32TARGETS += netfilter 32TARGETS += netfilter
33TARGETS += networking/timestamping 33TARGETS += networking/timestamping
34TARGETS += nsfs 34TARGETS += nsfs
35TARGETS += pidfd
35TARGETS += powerpc 36TARGETS += powerpc
36TARGETS += proc 37TARGETS += proc
37TARGETS += pstore 38TARGETS += pstore
diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
new file mode 100644
index 000000000000..deaf8073bc06
--- /dev/null
+++ b/tools/testing/selftests/pidfd/Makefile
@@ -0,0 +1,6 @@
1CFLAGS += -g -I../../../../usr/include/
2
3TEST_GEN_PROGS := pidfd_test
4
5include ../lib.mk
6
diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c
new file mode 100644
index 000000000000..d59378a93782
--- /dev/null
+++ b/tools/testing/selftests/pidfd/pidfd_test.c
@@ -0,0 +1,381 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <fcntl.h>
6#include <linux/types.h>
7#include <sched.h>
8#include <signal.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <syscall.h>
13#include <sys/mount.h>
14#include <sys/wait.h>
15#include <unistd.h>
16
17#include "../kselftest.h"
18
19static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
20 unsigned int flags)
21{
22 return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
23}
24
25static int signal_received;
26
27static void set_signal_received_on_sigusr1(int sig)
28{
29 if (sig == SIGUSR1)
30 signal_received = 1;
31}
32
33/*
34 * Straightforward test to see whether pidfd_send_signal() works is to send
35 * a signal to ourself.
36 */
37static int test_pidfd_send_signal_simple_success(void)
38{
39 int pidfd, ret;
40 const char *test_name = "pidfd_send_signal send SIGUSR1";
41
42 pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC);
43 if (pidfd < 0)
44 ksft_exit_fail_msg(
45 "%s test: Failed to open process file descriptor\n",
46 test_name);
47
48 signal(SIGUSR1, set_signal_received_on_sigusr1);
49
50 ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0);
51 close(pidfd);
52 if (ret < 0)
53 ksft_exit_fail_msg("%s test: Failed to send signal\n",
54 test_name);
55
56 if (signal_received != 1)
57 ksft_exit_fail_msg("%s test: Failed to receive signal\n",
58 test_name);
59
60 signal_received = 0;
61 ksft_test_result_pass("%s test: Sent signal\n", test_name);
62 return 0;
63}
64
65static int wait_for_pid(pid_t pid)
66{
67 int status, ret;
68
69again:
70 ret = waitpid(pid, &status, 0);
71 if (ret == -1) {
72 if (errno == EINTR)
73 goto again;
74
75 return -1;
76 }
77
78 if (ret != pid)
79 goto again;
80
81 if (!WIFEXITED(status))
82 return -1;
83
84 return WEXITSTATUS(status);
85}
86
87static int test_pidfd_send_signal_exited_fail(void)
88{
89 int pidfd, ret, saved_errno;
90 char buf[256];
91 pid_t pid;
92 const char *test_name = "pidfd_send_signal signal exited process";
93
94 pid = fork();
95 if (pid < 0)
96 ksft_exit_fail_msg("%s test: Failed to create new process\n",
97 test_name);
98
99 if (pid == 0)
100 _exit(EXIT_SUCCESS);
101
102 snprintf(buf, sizeof(buf), "/proc/%d", pid);
103
104 pidfd = open(buf, O_DIRECTORY | O_CLOEXEC);
105
106 (void)wait_for_pid(pid);
107
108 if (pidfd < 0)
109 ksft_exit_fail_msg(
110 "%s test: Failed to open process file descriptor\n",
111 test_name);
112
113 ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
114 saved_errno = errno;
115 close(pidfd);
116 if (ret == 0)
117 ksft_exit_fail_msg(
118 "%s test: Managed to send signal to process even though it should have failed\n",
119 test_name);
120
121 if (saved_errno != ESRCH)
122 ksft_exit_fail_msg(
123 "%s test: Expected to receive ESRCH as errno value but received %d instead\n",
124 test_name, saved_errno);
125
126 ksft_test_result_pass("%s test: Failed to send signal as expected\n",
127 test_name);
128 return 0;
129}
130
131/*
132 * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c
133 * That means, when it wraps around any pid < 300 will be skipped.
134 * So we need to use a pid > 300 in order to test recycling.
135 */
136#define PID_RECYCLE 1000
137
138/*
139 * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT.
140 * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of
141 * times then we skip the test to not go into an infinite loop or block for a
142 * long time.
143 */
144#define PIDFD_MAX_DEFAULT 0x8000
145
146/*
147 * Define a few custom error codes for the child process to clearly indicate
148 * what is happening. This way we can tell the difference between a system
149 * error, a test error, etc.
150 */
151#define PIDFD_PASS 0
152#define PIDFD_FAIL 1
153#define PIDFD_ERROR 2
154#define PIDFD_SKIP 3
155#define PIDFD_XFAIL 4
156
157static int test_pidfd_send_signal_recycled_pid_fail(void)
158{
159 int i, ret;
160 pid_t pid1;
161 const char *test_name = "pidfd_send_signal signal recycled pid";
162
163 ret = unshare(CLONE_NEWPID);
164 if (ret < 0)
165 ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n",
166 test_name);
167
168 ret = unshare(CLONE_NEWNS);
169 if (ret < 0)
170 ksft_exit_fail_msg(
171 "%s test: Failed to unshare mount namespace\n",
172 test_name);
173
174 ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
175 if (ret < 0)
176 ksft_exit_fail_msg("%s test: Failed to remount / private\n",
177 test_name);
178
179 /* pid 1 in new pid namespace */
180 pid1 = fork();
181 if (pid1 < 0)
182 ksft_exit_fail_msg("%s test: Failed to create new process\n",
183 test_name);
184
185 if (pid1 == 0) {
186 char buf[256];
187 pid_t pid2;
188 int pidfd = -1;
189
190 (void)umount2("/proc", MNT_DETACH);
191 ret = mount("proc", "/proc", "proc", 0, NULL);
192 if (ret < 0)
193 _exit(PIDFD_ERROR);
194
195 /* grab pid PID_RECYCLE */
196 for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) {
197 pid2 = fork();
198 if (pid2 < 0)
199 _exit(PIDFD_ERROR);
200
201 if (pid2 == 0)
202 _exit(PIDFD_PASS);
203
204 if (pid2 == PID_RECYCLE) {
205 snprintf(buf, sizeof(buf), "/proc/%d", pid2);
206 ksft_print_msg("pid to recycle is %d\n", pid2);
207 pidfd = open(buf, O_DIRECTORY | O_CLOEXEC);
208 }
209
210 if (wait_for_pid(pid2))
211 _exit(PIDFD_ERROR);
212
213 if (pid2 >= PID_RECYCLE)
214 break;
215 }
216
217 /*
218 * We want to be as predictable as we can so if we haven't been
219 * able to grab pid PID_RECYCLE skip the test.
220 */
221 if (pid2 != PID_RECYCLE) {
222 /* skip test */
223 close(pidfd);
224 _exit(PIDFD_SKIP);
225 }
226
227 if (pidfd < 0)
228 _exit(PIDFD_ERROR);
229
230 for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) {
231 char c;
232 int pipe_fds[2];
233 pid_t recycled_pid;
234 int child_ret = PIDFD_PASS;
235
236 ret = pipe2(pipe_fds, O_CLOEXEC);
237 if (ret < 0)
238 _exit(PIDFD_ERROR);
239
240 recycled_pid = fork();
241 if (recycled_pid < 0)
242 _exit(PIDFD_ERROR);
243
244 if (recycled_pid == 0) {
245 close(pipe_fds[1]);
246 (void)read(pipe_fds[0], &c, 1);
247 close(pipe_fds[0]);
248
249 _exit(PIDFD_PASS);
250 }
251
252 /*
253 * Stop the child so we can inspect whether we have
254 * recycled pid PID_RECYCLE.
255 */
256 close(pipe_fds[0]);
257 ret = kill(recycled_pid, SIGSTOP);
258 close(pipe_fds[1]);
259 if (ret) {
260 (void)wait_for_pid(recycled_pid);
261 _exit(PIDFD_ERROR);
262 }
263
264 /*
265 * We have recycled the pid. Try to signal it. This
266 * needs to fail since this is a different process than
267 * the one the pidfd refers to.
268 */
269 if (recycled_pid == PID_RECYCLE) {
270 ret = sys_pidfd_send_signal(pidfd, SIGCONT,
271 NULL, 0);
272 if (ret && errno == ESRCH)
273 child_ret = PIDFD_XFAIL;
274 else
275 child_ret = PIDFD_FAIL;
276 }
277
278 /* let the process move on */
279 ret = kill(recycled_pid, SIGCONT);
280 if (ret)
281 (void)kill(recycled_pid, SIGKILL);
282
283 if (wait_for_pid(recycled_pid))
284 _exit(PIDFD_ERROR);
285
286 switch (child_ret) {
287 case PIDFD_FAIL:
288 /* fallthrough */
289 case PIDFD_XFAIL:
290 _exit(child_ret);
291 case PIDFD_PASS:
292 break;
293 default:
294 /* not reached */
295 _exit(PIDFD_ERROR);
296 }
297
298 /*
299 * If the user set a custom pid_max limit we could be
300 * in the millions.
301 * Skip the test in this case.
302 */
303 if (recycled_pid > PIDFD_MAX_DEFAULT)
304 _exit(PIDFD_SKIP);
305 }
306
307 /* failed to recycle pid */
308 _exit(PIDFD_SKIP);
309 }
310
311 ret = wait_for_pid(pid1);
312 switch (ret) {
313 case PIDFD_FAIL:
314 ksft_exit_fail_msg(
315 "%s test: Managed to signal recycled pid %d\n",
316 test_name, PID_RECYCLE);
317 case PIDFD_PASS:
318 ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n",
319 test_name, PID_RECYCLE);
320 case PIDFD_SKIP:
321 ksft_print_msg("%s test: Skipping test\n", test_name);
322 ret = 0;
323 break;
324 case PIDFD_XFAIL:
325 ksft_test_result_pass(
326 "%s test: Failed to signal recycled pid as expected\n",
327 test_name);
328 ret = 0;
329 break;
330 default /* PIDFD_ERROR */:
331 ksft_exit_fail_msg("%s test: Error while running tests\n",
332 test_name);
333 }
334
335 return ret;
336}
337
338static int test_pidfd_send_signal_syscall_support(void)
339{
340 int pidfd, ret;
341 const char *test_name = "pidfd_send_signal check for support";
342
343 pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC);
344 if (pidfd < 0)
345 ksft_exit_fail_msg(
346 "%s test: Failed to open process file descriptor\n",
347 test_name);
348
349 ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
350 if (ret < 0) {
351 /*
352 * pidfd_send_signal() will currently return ENOSYS when
353 * CONFIG_PROC_FS is not set.
354 */
355 if (errno == ENOSYS)
356 ksft_exit_skip(
357 "%s test: pidfd_send_signal() syscall not supported (Ensure that CONFIG_PROC_FS=y is set)\n",
358 test_name);
359
360 ksft_exit_fail_msg("%s test: Failed to send signal\n",
361 test_name);
362 }
363
364 close(pidfd);
365 ksft_test_result_pass(
366 "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n",
367 test_name);
368 return 0;
369}
370
371int main(int argc, char **argv)
372{
373 ksft_print_header();
374
375 test_pidfd_send_signal_syscall_support();
376 test_pidfd_send_signal_simple_success();
377 test_pidfd_send_signal_exited_fail();
378 test_pidfd_send_signal_recycled_pid_fail();
379
380 return ksft_exit_pass();
381}