Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'pidfd-v5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux

Pull pidfd system call from Christian Brauner:
"This introduces the ability to use file descriptors from /proc/<pid>/
as stable handles on struct pid. Even if a pid is recycled the handle
will not change. For a start these fds can be used to send signals to
the processes they refer to.

With the ability to use /proc/<pid> fds as stable handles on struct
pid we can fix a long-standing issue where after a process has exited
its pid can be reused by another process. If a caller sends a signal
to a reused pid it will end up signaling the wrong process.

With this patchset we enable a variety of use cases. One obvious
example is that we can now safely delegate an important part of
process management - sending signals - to processes other than the
parent of a given process by sending file descriptors around via scm
rights and not fearing that the given process will have been recycled
in the meantime. It also allows for easy testing whether a given
process is still alive or not by sending signal 0 to a pidfd which is
quite handy.

There has been some interest in this feature e.g. from systems
management (systemd, glibc) and container managers. I have requested
and gotten comments from glibc to make sure that this syscall is
suitable for their needs as well. In the future I expect it to take on
most other pid-based signal syscalls. But such features are left for
the future once they are needed.

This has been sitting in linux-next for quite a while and has not
caused any issues. It comes with selftests which verify basic
functionality and also test that a recycled pid cannot be signaled via
a pidfd.

Jon has written about a prior version of this patchset. It should
cover the basic functionality since not a lot has changed since then:

https://lwn.net/Articles/773459/

The commit message for the syscall itself is extensively documenting
the syscall, including it's functionality and extensibility"

* tag 'pidfd-v5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux:
selftests: add tests for pidfd_send_signal()
signal: add pidfd_send_signal() syscall

+538 -6
+1
arch/x86/entry/syscalls/syscall_32.tbl
··· 429 429 421 i386 rt_sigtimedwait_time64 sys_rt_sigtimedwait __ia32_compat_sys_rt_sigtimedwait_time64 430 430 422 i386 futex_time64 sys_futex __ia32_sys_futex 431 431 423 i386 sched_rr_get_interval_time64 sys_sched_rr_get_interval __ia32_sys_sched_rr_get_interval 432 + 424 i386 pidfd_send_signal sys_pidfd_send_signal __ia32_sys_pidfd_send_signal 432 433 425 i386 io_uring_setup sys_io_uring_setup __ia32_sys_io_uring_setup 433 434 426 i386 io_uring_enter sys_io_uring_enter __ia32_sys_io_uring_enter 434 435 427 i386 io_uring_register sys_io_uring_register __ia32_sys_io_uring_register
+1
arch/x86/entry/syscalls/syscall_64.tbl
··· 345 345 334 common rseq __x64_sys_rseq 346 346 # don't use numbers 387 through 423, add new calls after the last 347 347 # 'common' entry 348 + 424 common pidfd_send_signal __x64_sys_pidfd_send_signal 348 349 425 common io_uring_setup __x64_sys_io_uring_setup 349 350 426 common io_uring_enter __x64_sys_io_uring_enter 350 351 427 common io_uring_register __x64_sys_io_uring_register
+9
fs/proc/base.c
··· 3074 3074 .llseek = generic_file_llseek, 3075 3075 }; 3076 3076 3077 + struct 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 + 3077 3086 static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 3078 3087 { 3079 3088 return proc_pident_lookup(dir, dentry,
+6
include/linux/proc_fs.h
··· 73 73 int (*show)(struct seq_file *, void *), 74 74 proc_write_t write, 75 75 void *data); 76 + extern struct pid *tgid_pidfd_to_pid(const struct file *file); 76 77 77 78 #else /* CONFIG_PROC_FS */ 78 79 ··· 114 113 #define proc_create_net_data(name, mode, parent, ops, state_size, data) ({NULL;}) 115 114 #define proc_create_net(name, mode, parent, state_size, ops) ({NULL;}) 116 115 #define proc_create_net_single(name, mode, parent, show, data) ({NULL;}) 116 + 117 + static inline struct pid *tgid_pidfd_to_pid(const struct file *file) 118 + { 119 + return ERR_PTR(-EBADF); 120 + } 117 121 118 122 #endif /* CONFIG_PROC_FS */ 119 123
+3
include/linux/syscalls.h
··· 985 985 unsigned mask, struct statx __user *buffer); 986 986 asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len, 987 987 int flags, uint32_t sig); 988 + asmlinkage long sys_pidfd_send_signal(int pidfd, int sig, 989 + siginfo_t __user *info, 990 + unsigned int flags); 988 991 989 992 /* 990 993 * Architecture-specific system calls
+2
include/uapi/asm-generic/unistd.h
··· 824 824 __SYSCALL(__NR_sched_rr_get_interval_time64, sys_sched_rr_get_interval) 825 825 #endif 826 826 827 + #define __NR_pidfd_send_signal 424 828 + __SYSCALL(__NR_pidfd_send_signal, sys_pidfd_send_signal) 827 829 #define __NR_io_uring_setup 425 828 830 __SYSCALL(__NR_io_uring_setup, sys_io_uring_setup) 829 831 #define __NR_io_uring_enter 426
+127 -6
kernel/signal.c
··· 19 19 #include <linux/sched/task.h> 20 20 #include <linux/sched/task_stack.h> 21 21 #include <linux/sched/cputime.h> 22 + #include <linux/file.h> 22 23 #include <linux/fs.h> 24 + #include <linux/proc_fs.h> 23 25 #include <linux/tty.h> 24 26 #include <linux/binfmts.h> 25 27 #include <linux/coredump.h> ··· 3489 3487 #endif 3490 3488 #endif 3491 3489 3490 + static inline void prepare_kill_siginfo(int sig, struct kernel_siginfo *info) 3491 + { 3492 + clear_siginfo(info); 3493 + info->si_signo = sig; 3494 + info->si_errno = 0; 3495 + info->si_code = SI_USER; 3496 + info->si_pid = task_tgid_vnr(current); 3497 + info->si_uid = from_kuid_munged(current_user_ns(), current_uid()); 3498 + } 3499 + 3492 3500 /** 3493 3501 * sys_kill - send a signal to a process 3494 3502 * @pid: the PID of the process ··· 3508 3496 { 3509 3497 struct kernel_siginfo info; 3510 3498 3511 - clear_siginfo(&info); 3512 - info.si_signo = sig; 3513 - info.si_errno = 0; 3514 - info.si_code = SI_USER; 3515 - info.si_pid = task_tgid_vnr(current); 3516 - info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); 3499 + prepare_kill_siginfo(sig, &info); 3517 3500 3518 3501 return kill_something_info(sig, &info, pid); 3519 3502 } 3503 + 3504 + #ifdef CONFIG_PROC_FS 3505 + /* 3506 + * Verify that the signaler and signalee either are in the same pid namespace 3507 + * or that the signaler's pid namespace is an ancestor of the signalee's pid 3508 + * namespace. 3509 + */ 3510 + static bool access_pidfd_pidns(struct pid *pid) 3511 + { 3512 + struct pid_namespace *active = task_active_pid_ns(current); 3513 + struct pid_namespace *p = ns_of_pid(pid); 3514 + 3515 + for (;;) { 3516 + if (!p) 3517 + return false; 3518 + if (p == active) 3519 + break; 3520 + p = p->parent; 3521 + } 3522 + 3523 + return true; 3524 + } 3525 + 3526 + static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info) 3527 + { 3528 + #ifdef CONFIG_COMPAT 3529 + /* 3530 + * Avoid hooking up compat syscalls and instead handle necessary 3531 + * conversions here. Note, this is a stop-gap measure and should not be 3532 + * considered a generic solution. 3533 + */ 3534 + if (in_compat_syscall()) 3535 + return copy_siginfo_from_user32( 3536 + kinfo, (struct compat_siginfo __user *)info); 3537 + #endif 3538 + return copy_siginfo_from_user(kinfo, info); 3539 + } 3540 + 3541 + /** 3542 + * sys_pidfd_send_signal - send a signal to a process through a task file 3543 + * descriptor 3544 + * @pidfd: the file descriptor of the process 3545 + * @sig: signal to be sent 3546 + * @info: the signal info 3547 + * @flags: future flags to be passed 3548 + * 3549 + * The syscall currently only signals via PIDTYPE_PID which covers 3550 + * kill(<positive-pid>, <signal>. It does not signal threads or process 3551 + * groups. 3552 + * In order to extend the syscall to threads and process groups the @flags 3553 + * argument should be used. In essence, the @flags argument will determine 3554 + * what is signaled and not the file descriptor itself. Put in other words, 3555 + * grouping is a property of the flags argument not a property of the file 3556 + * descriptor. 3557 + * 3558 + * Return: 0 on success, negative errno on failure 3559 + */ 3560 + SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig, 3561 + siginfo_t __user *, info, unsigned int, flags) 3562 + { 3563 + int ret; 3564 + struct fd f; 3565 + struct pid *pid; 3566 + kernel_siginfo_t kinfo; 3567 + 3568 + /* Enforce flags be set to 0 until we add an extension. */ 3569 + if (flags) 3570 + return -EINVAL; 3571 + 3572 + f = fdget_raw(pidfd); 3573 + if (!f.file) 3574 + return -EBADF; 3575 + 3576 + /* Is this a pidfd? */ 3577 + pid = tgid_pidfd_to_pid(f.file); 3578 + if (IS_ERR(pid)) { 3579 + ret = PTR_ERR(pid); 3580 + goto err; 3581 + } 3582 + 3583 + ret = -EINVAL; 3584 + if (!access_pidfd_pidns(pid)) 3585 + goto err; 3586 + 3587 + if (info) { 3588 + ret = copy_siginfo_from_user_any(&kinfo, info); 3589 + if (unlikely(ret)) 3590 + goto err; 3591 + 3592 + ret = -EINVAL; 3593 + if (unlikely(sig != kinfo.si_signo)) 3594 + goto err; 3595 + 3596 + if ((task_pid(current) != pid) && 3597 + (kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL)) { 3598 + /* Only allow sending arbitrary signals to yourself. */ 3599 + ret = -EPERM; 3600 + if (kinfo.si_code != SI_USER) 3601 + goto err; 3602 + 3603 + /* Turn this into a regular kill signal. */ 3604 + prepare_kill_siginfo(sig, &kinfo); 3605 + } 3606 + } else { 3607 + prepare_kill_siginfo(sig, &kinfo); 3608 + } 3609 + 3610 + ret = kill_pid_info(sig, &kinfo, pid); 3611 + 3612 + err: 3613 + fdput(f); 3614 + return ret; 3615 + } 3616 + #endif /* CONFIG_PROC_FS */ 3520 3617 3521 3618 static int 3522 3619 do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info)
+1
kernel/sys_ni.c
··· 168 168 /* kernel/sched/core.c */ 169 169 170 170 /* kernel/signal.c */ 171 + COND_SYSCALL(pidfd_send_signal); 171 172 172 173 /* kernel/sys.c */ 173 174 COND_SYSCALL(setregid);
+1
tools/testing/selftests/Makefile
··· 32 32 TARGETS += netfilter 33 33 TARGETS += networking/timestamping 34 34 TARGETS += nsfs 35 + TARGETS += pidfd 35 36 TARGETS += powerpc 36 37 TARGETS += proc 37 38 TARGETS += pstore
+6
tools/testing/selftests/pidfd/Makefile
··· 1 + CFLAGS += -g -I../../../../usr/include/ 2 + 3 + TEST_GEN_PROGS := pidfd_test 4 + 5 + include ../lib.mk 6 +
+381
tools/testing/selftests/pidfd/pidfd_test.c
··· 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 + 19 + static 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 + 25 + static int signal_received; 26 + 27 + static 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 + */ 37 + static 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 + 65 + static int wait_for_pid(pid_t pid) 66 + { 67 + int status, ret; 68 + 69 + again: 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 + 87 + static 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 + 157 + static 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 + 338 + static 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 + 371 + int 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 + }