143c6afeeSChristian Brauner // SPDX-License-Identifier: GPL-2.0
243c6afeeSChristian Brauner
343c6afeeSChristian Brauner #define _GNU_SOURCE
443c6afeeSChristian Brauner #include <err.h>
543c6afeeSChristian Brauner #include <errno.h>
643c6afeeSChristian Brauner #include <fcntl.h>
743c6afeeSChristian Brauner #include <inttypes.h>
843c6afeeSChristian Brauner #include <limits.h>
943c6afeeSChristian Brauner #include <sched.h>
1043c6afeeSChristian Brauner #include <signal.h>
1143c6afeeSChristian Brauner #include <stdio.h>
1243c6afeeSChristian Brauner #include <stdlib.h>
1343c6afeeSChristian Brauner #include <string.h>
1443c6afeeSChristian Brauner #include <sys/stat.h>
1543c6afeeSChristian Brauner #include <sys/syscall.h>
1643c6afeeSChristian Brauner #include <sys/types.h>
1743c6afeeSChristian Brauner #include <sys/wait.h>
1843c6afeeSChristian Brauner #include <unistd.h>
1943c6afeeSChristian Brauner
2043c6afeeSChristian Brauner #ifndef CLONE_PIDFD
2143c6afeeSChristian Brauner #define CLONE_PIDFD 0x00001000
2243c6afeeSChristian Brauner #endif
2343c6afeeSChristian Brauner
247c33277bSGuenter Roeck #ifndef __NR_pidfd_send_signal
257c33277bSGuenter Roeck #define __NR_pidfd_send_signal -1
267c33277bSGuenter Roeck #endif
277c33277bSGuenter Roeck
do_child(void * args)2843c6afeeSChristian Brauner static int do_child(void *args)
2943c6afeeSChristian Brauner {
3043c6afeeSChristian Brauner printf("%d\n", getpid());
3143c6afeeSChristian Brauner _exit(EXIT_SUCCESS);
3243c6afeeSChristian Brauner }
3343c6afeeSChristian Brauner
pidfd_clone(int flags,int * pidfd)3443c6afeeSChristian Brauner static pid_t pidfd_clone(int flags, int *pidfd)
3543c6afeeSChristian Brauner {
3643c6afeeSChristian Brauner size_t stack_size = 1024;
3743c6afeeSChristian Brauner char *stack[1024] = { 0 };
3843c6afeeSChristian Brauner
3943c6afeeSChristian Brauner #ifdef __ia64__
4043c6afeeSChristian Brauner return __clone2(do_child, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
4143c6afeeSChristian Brauner #else
4243c6afeeSChristian Brauner return clone(do_child, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
4343c6afeeSChristian Brauner #endif
4443c6afeeSChristian Brauner }
4543c6afeeSChristian Brauner
sys_pidfd_send_signal(int pidfd,int sig,siginfo_t * info,unsigned int flags)4643c6afeeSChristian Brauner static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
4743c6afeeSChristian Brauner unsigned int flags)
4843c6afeeSChristian Brauner {
4943c6afeeSChristian Brauner return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
5043c6afeeSChristian Brauner }
5143c6afeeSChristian Brauner
pidfd_metadata_fd(pid_t pid,int pidfd)5243c6afeeSChristian Brauner static int pidfd_metadata_fd(pid_t pid, int pidfd)
5343c6afeeSChristian Brauner {
5443c6afeeSChristian Brauner int procfd, ret;
5543c6afeeSChristian Brauner char path[100];
5643c6afeeSChristian Brauner
5743c6afeeSChristian Brauner snprintf(path, sizeof(path), "/proc/%d", pid);
5843c6afeeSChristian Brauner procfd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
5943c6afeeSChristian Brauner if (procfd < 0) {
6043c6afeeSChristian Brauner warn("Failed to open %s\n", path);
6143c6afeeSChristian Brauner return -1;
6243c6afeeSChristian Brauner }
6343c6afeeSChristian Brauner
6443c6afeeSChristian Brauner /*
6543c6afeeSChristian Brauner * Verify that the pid has not been recycled and our /proc/<pid> handle
6643c6afeeSChristian Brauner * is still valid.
6743c6afeeSChristian Brauner */
6843c6afeeSChristian Brauner ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
6943c6afeeSChristian Brauner if (ret < 0) {
7043c6afeeSChristian Brauner switch (errno) {
7143c6afeeSChristian Brauner case EPERM:
7243c6afeeSChristian Brauner /* Process exists, just not allowed to signal it. */
7343c6afeeSChristian Brauner break;
7443c6afeeSChristian Brauner default:
7543c6afeeSChristian Brauner warn("Failed to signal process\n");
7643c6afeeSChristian Brauner close(procfd);
7743c6afeeSChristian Brauner procfd = -1;
7843c6afeeSChristian Brauner }
7943c6afeeSChristian Brauner }
8043c6afeeSChristian Brauner
8143c6afeeSChristian Brauner return procfd;
8243c6afeeSChristian Brauner }
8343c6afeeSChristian Brauner
main(int argc,char * argv[])8443c6afeeSChristian Brauner int main(int argc, char *argv[])
8543c6afeeSChristian Brauner {
86*bee19cd8SDmitry V. Levin int pidfd = -1, ret = EXIT_FAILURE;
8743c6afeeSChristian Brauner char buf[4096] = { 0 };
8843c6afeeSChristian Brauner pid_t pid;
8943c6afeeSChristian Brauner int procfd, statusfd;
9043c6afeeSChristian Brauner ssize_t bytes;
9143c6afeeSChristian Brauner
9243c6afeeSChristian Brauner pid = pidfd_clone(CLONE_PIDFD, &pidfd);
9343c6afeeSChristian Brauner if (pid < 0)
94*bee19cd8SDmitry V. Levin err(ret, "CLONE_PIDFD");
95*bee19cd8SDmitry V. Levin if (pidfd == -1) {
96*bee19cd8SDmitry V. Levin warnx("CLONE_PIDFD is not supported by the kernel");
97*bee19cd8SDmitry V. Levin goto out;
98*bee19cd8SDmitry V. Levin }
9943c6afeeSChristian Brauner
10043c6afeeSChristian Brauner procfd = pidfd_metadata_fd(pid, pidfd);
10143c6afeeSChristian Brauner close(pidfd);
10243c6afeeSChristian Brauner if (procfd < 0)
10343c6afeeSChristian Brauner goto out;
10443c6afeeSChristian Brauner
10543c6afeeSChristian Brauner statusfd = openat(procfd, "status", O_RDONLY | O_CLOEXEC);
10643c6afeeSChristian Brauner close(procfd);
10743c6afeeSChristian Brauner if (statusfd < 0)
10843c6afeeSChristian Brauner goto out;
10943c6afeeSChristian Brauner
11043c6afeeSChristian Brauner bytes = read(statusfd, buf, sizeof(buf));
11143c6afeeSChristian Brauner if (bytes > 0)
11243c6afeeSChristian Brauner bytes = write(STDOUT_FILENO, buf, bytes);
11343c6afeeSChristian Brauner close(statusfd);
11443c6afeeSChristian Brauner ret = EXIT_SUCCESS;
11543c6afeeSChristian Brauner
11643c6afeeSChristian Brauner out:
11743c6afeeSChristian Brauner (void)wait(NULL);
11843c6afeeSChristian Brauner
11943c6afeeSChristian Brauner exit(ret);
12043c6afeeSChristian Brauner }
121