xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2019 SUSE LLC
4  * Author: Christian Amann <[email protected]>
5  */
6 
7 /*\
8  * [Description]
9  *
10  * This test checks if the pidfd_send_signal syscall wrongfully sends
11  * a signal to a new process which inherited the PID of the actual
12  * target process.
13  *
14  * In order to do so it is necessary to start a process with a pre-
15  * determined PID. This is accomplished by writing to the
16  * /proc/sys/kernel/ns_last_pid file.
17  *
18  * By utilizing this, this test forks two children with the same PID.
19  * It is then checked, if the syscall will send a signal to the second
20  * child using the pidfd of the first one.
21  */
22 
23 #define _GNU_SOURCE
24 #include <signal.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include "tst_test.h"
28 #include "lapi/pidfd.h"
29 #include "tst_safe_pthread.h"
30 
31 #define PIDTRIES	3
32 
33 static char *last_pid_file;
34 static int pidfd, new_pidfd;
35 static int old_inode, new_inode;
36 
get_inode_number(int fd)37 static int get_inode_number(int fd)
38 {
39 	struct stat file_stat;
40 
41 	SAFE_FSTAT(fd, &file_stat);
42 	return file_stat.st_ino;
43 }
44 
verify_pidfd_send_signal(void)45 static void verify_pidfd_send_signal(void)
46 {
47 	pid_t pid, new_pid;
48 	char pid_filename[32];
49 	char pid_str[16];
50 	int i, fail;
51 
52 	fail = 1;
53 	for (i = 0; i < PIDTRIES; i++) {
54 		pid = SAFE_FORK();
55 		if (pid == 0) {
56 			TST_CHECKPOINT_WAIT(0);
57 			return;
58 		}
59 
60 		sprintf(pid_filename, "/proc/%d", pid);
61 		pidfd = SAFE_OPEN(pid_filename, O_DIRECTORY | O_CLOEXEC);
62 		old_inode = get_inode_number(pidfd);
63 
64 		TST_CHECKPOINT_WAKE(0);
65 		tst_reap_children();
66 
67 		/* Manipulate PID for next process */
68 		sprintf(pid_str, "%d", pid - 1);
69 		SAFE_FILE_PRINTF(last_pid_file, "%s", pid_str);
70 
71 		new_pid = SAFE_FORK();
72 		if (new_pid == 0) {
73 			TST_CHECKPOINT_WAIT(0);
74 			return;
75 		}
76 
77 		if (new_pid == pid) {
78 			new_pidfd = SAFE_OPEN(pid_filename,
79 					O_DIRECTORY | O_CLOEXEC);
80 			new_inode = get_inode_number(new_pidfd);
81 			SAFE_CLOSE(new_pidfd);
82 			fail = 0;
83 			break;
84 		}
85 
86 		if (i < PIDTRIES) {
87 			tst_res(TINFO,
88 				"Failed to set correct PID, trying again...");
89 		}
90 		SAFE_CLOSE(pidfd);
91 		TST_CHECKPOINT_WAKE(0);
92 		tst_reap_children();
93 	}
94 	if (fail) {
95 		tst_brk(TBROK,
96 			"Could not set new child to same PID as the old one!");
97 	}
98 	if (old_inode == new_inode) {
99 		tst_res(TWARN,
100 			"File descriptor of new process points to the inode of the old process!");
101 	}
102 
103 	TEST(pidfd_send_signal(pidfd, SIGUSR1, NULL, 0));
104 	if (TST_RET == -1 && TST_ERR == ESRCH) {
105 		tst_res(TPASS,
106 			"Did not send signal to wrong process with same PID!");
107 	} else {
108 		tst_res(TFAIL | TTERRNO,
109 			"pidf_send_signal() ended unexpectedly - return value: %ld, error",
110 			TST_RET);
111 	}
112 	TST_CHECKPOINT_WAKE(0);
113 	tst_reap_children();
114 
115 	SAFE_CLOSE(pidfd);
116 }
117 
setup(void)118 static void setup(void)
119 {
120 	pidfd_send_signal_supported();
121 
122 	last_pid_file = "/proc/sys/kernel/ns_last_pid";
123 	if (access(last_pid_file, F_OK) == -1) {
124 		tst_brk(TCONF, "%s does not exist, cannot set PIDs",
125 			last_pid_file);
126 	}
127 }
128 
cleanup(void)129 static void cleanup(void)
130 {
131 	tst_reap_children();
132 	if (new_pidfd > 0)
133 		SAFE_CLOSE(new_pidfd);
134 	if (pidfd > 0)
135 		SAFE_CLOSE(pidfd);
136 }
137 
138 static struct tst_test test = {
139 	.test_all = verify_pidfd_send_signal,
140 	.setup = setup,
141 	.cleanup = cleanup,
142 	.needs_root = 1,
143 	.needs_checkpoints = 1,
144 	.forks_child = 1,
145 };
146