Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <sched.h>
4 : : #include <sys/mount.h>
5 : : #include <sys/personality.h>
6 : : #include <sys/prctl.h>
7 : : #include <sys/stat.h>
8 : : #include <sys/types.h>
9 : : #include <sys/wait.h>
10 : : #include <unistd.h>
11 : : #if HAVE_VALGRIND_VALGRIND_H
12 : : #include <valgrind/valgrind.h>
13 : : #endif
14 : :
15 : : #include "alloc-util.h"
16 : : #include "architecture.h"
17 : : #include "fd-util.h"
18 : : #include "log.h"
19 : : #include "macro.h"
20 : : #include "missing.h"
21 : : #include "parse-util.h"
22 : : #include "process-util.h"
23 : : #include "signal-util.h"
24 : : #include "stdio-util.h"
25 : : #include "string-util.h"
26 : : #include "terminal-util.h"
27 : : #include "test-helper.h"
28 : : #include "tests.h"
29 : : #include "util.h"
30 : : #include "virt.h"
31 : :
32 : 8 : static void test_get_process_comm(pid_t pid) {
33 : : struct stat st;
34 : 8 : _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL;
35 : 16 : _cleanup_free_ char *env = NULL;
36 : : char path[STRLEN("/proc//comm") + DECIMAL_STR_MAX(pid_t)];
37 : : pid_t e;
38 : : uid_t u;
39 : : gid_t g;
40 : : dev_t h;
41 : : int r;
42 : :
43 [ - + ]: 8 : xsprintf(path, "/proc/"PID_FMT"/comm", pid);
44 : :
45 [ + - ]: 8 : if (stat(path, &st) == 0) {
46 [ - + ]: 8 : assert_se(get_process_comm(pid, &a) >= 0);
47 [ + - ]: 8 : log_info("PID"PID_FMT" comm: '%s'", pid, a);
48 : : } else
49 [ # # ]: 0 : log_warning("%s not exist.", path);
50 : :
51 [ - + ]: 8 : assert_se(get_process_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c) >= 0);
52 [ + - ]: 8 : log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
53 : :
54 [ - + ]: 8 : assert_se(get_process_cmdline(pid, 8, 0, &d) >= 0);
55 [ + - ]: 8 : log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
56 : :
57 : 8 : free(d);
58 [ - + ]: 8 : assert_se(get_process_cmdline(pid, 1, 0, &d) >= 0);
59 [ + - ]: 8 : log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
60 : :
61 [ - + ]: 8 : assert_se(get_process_ppid(pid, &e) >= 0);
62 [ + - ]: 8 : log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
63 [ + + - + ]: 8 : assert_se(pid == 1 ? e == 0 : e > 0);
64 : :
65 [ - + # # ]: 8 : assert_se(is_kernel_thread(pid) == 0 || pid != 1);
66 : :
67 : 8 : r = get_process_exe(pid, &f);
68 [ + + - + ]: 8 : assert_se(r >= 0 || r == -EACCES);
69 [ + - ]: 8 : log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
70 : :
71 [ - + ]: 8 : assert_se(get_process_uid(pid, &u) == 0);
72 [ + - ]: 8 : log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
73 : :
74 [ - + ]: 8 : assert_se(get_process_gid(pid, &g) == 0);
75 [ + - ]: 8 : log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
76 : :
77 : 8 : r = get_process_environ(pid, &env);
78 [ + + - + ]: 8 : assert_se(r >= 0 || r == -EACCES);
79 [ + - + + ]: 8 : log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
80 : :
81 [ + - ]: 8 : if (!detect_container())
82 [ - + # # ]: 8 : assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1);
83 : :
84 : 8 : (void) getenv_for_pid(pid, "PATH", &i);
85 [ + - ]: 8 : log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
86 : 8 : }
87 : :
88 : 40 : static void test_get_process_comm_escape_one(const char *input, const char *output) {
89 : 40 : _cleanup_free_ char *n = NULL;
90 : :
91 [ + - ]: 40 : log_info("input: <%s> — output: <%s>", input, output);
92 : :
93 [ - + ]: 40 : assert_se(prctl(PR_SET_NAME, input) >= 0);
94 [ - + ]: 40 : assert_se(get_process_comm(0, &n) >= 0);
95 : :
96 [ + - ]: 40 : log_info("got: <%s>", n);
97 : :
98 [ - + ]: 40 : assert_se(streq_ptr(n, output));
99 : 40 : }
100 : :
101 : 4 : static void test_get_process_comm_escape(void) {
102 : 4 : _cleanup_free_ char *saved = NULL;
103 : :
104 [ - + ]: 4 : assert_se(get_process_comm(0, &saved) >= 0);
105 : :
106 : 4 : test_get_process_comm_escape_one("", "");
107 : 4 : test_get_process_comm_escape_one("foo", "foo");
108 : 4 : test_get_process_comm_escape_one("012345678901234", "012345678901234");
109 : 4 : test_get_process_comm_escape_one("0123456789012345", "012345678901234");
110 : 4 : test_get_process_comm_escape_one("äöüß", "\\303\\244\\303\\266\\303\\274\\303\\237");
111 : 4 : test_get_process_comm_escape_one("xäöüß", "x\\303\\244\\303\\266\\303\\274\\303\\237");
112 : 4 : test_get_process_comm_escape_one("xxäöüß", "xx\\303\\244\\303\\266\\303\\274\\303\\237");
113 : 4 : test_get_process_comm_escape_one("xxxäöüß", "xxx\\303\\244\\303\\266\\303\\274\\303\\237");
114 : 4 : test_get_process_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237");
115 : 4 : test_get_process_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237");
116 : :
117 [ - + ]: 4 : assert_se(prctl(PR_SET_NAME, saved) >= 0);
118 : 4 : }
119 : :
120 : 4 : static void test_pid_is_unwaited(void) {
121 : : pid_t pid;
122 : :
123 : 4 : pid = fork();
124 [ - + ]: 4 : assert_se(pid >= 0);
125 [ - + ]: 4 : if (pid == 0) {
126 : 0 : _exit(EXIT_SUCCESS);
127 : : } else {
128 : : int status;
129 : :
130 : 4 : waitpid(pid, &status, 0);
131 [ - + ]: 4 : assert_se(!pid_is_unwaited(pid));
132 : : }
133 [ - + ]: 4 : assert_se(pid_is_unwaited(getpid_cached()));
134 [ - + ]: 4 : assert_se(!pid_is_unwaited(-1));
135 : 4 : }
136 : :
137 : 4 : static void test_pid_is_alive(void) {
138 : : pid_t pid;
139 : :
140 : 4 : pid = fork();
141 [ - + ]: 4 : assert_se(pid >= 0);
142 [ - + ]: 4 : if (pid == 0) {
143 : 0 : _exit(EXIT_SUCCESS);
144 : : } else {
145 : : int status;
146 : :
147 : 4 : waitpid(pid, &status, 0);
148 [ - + ]: 4 : assert_se(!pid_is_alive(pid));
149 : : }
150 [ - + ]: 4 : assert_se(pid_is_alive(getpid_cached()));
151 [ - + ]: 4 : assert_se(!pid_is_alive(-1));
152 : 4 : }
153 : :
154 : 4 : static void test_personality(void) {
155 : :
156 [ - + ]: 4 : assert_se(personality_to_string(PER_LINUX));
157 [ - + ]: 4 : assert_se(!personality_to_string(PERSONALITY_INVALID));
158 : :
159 [ - + ]: 4 : assert_se(streq(personality_to_string(PER_LINUX), architecture_to_string(native_architecture())));
160 : :
161 [ - + ]: 4 : assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX);
162 [ - + ]: 4 : assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX);
163 : :
164 : : #ifdef __x86_64__
165 [ - + ]: 4 : assert_se(streq_ptr(personality_to_string(PER_LINUX), "x86-64"));
166 [ - + ]: 4 : assert_se(streq_ptr(personality_to_string(PER_LINUX32), "x86"));
167 : :
168 [ - + ]: 4 : assert_se(personality_from_string("x86-64") == PER_LINUX);
169 [ - + ]: 4 : assert_se(personality_from_string("x86") == PER_LINUX32);
170 [ - + ]: 4 : assert_se(personality_from_string("ia64") == PERSONALITY_INVALID);
171 [ - + ]: 4 : assert_se(personality_from_string(NULL) == PERSONALITY_INVALID);
172 : :
173 [ - + ]: 4 : assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32);
174 : : #endif
175 : 4 : }
176 : :
177 : 4 : static void test_get_process_cmdline_harder(void) {
178 : 4 : char path[] = "/tmp/test-cmdlineXXXXXX";
179 : 4 : _cleanup_close_ int fd = -1;
180 : 4 : _cleanup_free_ char *line = NULL;
181 : : pid_t pid;
182 : :
183 [ + - ]: 4 : if (geteuid() != 0) {
184 [ + - ]: 4 : log_info("Skipping %s: not root", __func__);
185 : 4 : return;
186 : : }
187 : :
188 [ # # ]: 0 : if (!have_namespaces()) {
189 [ # # ]: 0 : log_notice("Testing without namespaces, skipping %s", __func__);
190 : 0 : return;
191 : : }
192 : :
193 : : #if HAVE_VALGRIND_VALGRIND_H
194 : : /* valgrind patches open(/proc//cmdline)
195 : : * so, test_get_process_cmdline_harder fails always
196 : : * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */
197 : : if (RUNNING_ON_VALGRIND) {
198 : : log_info("Skipping %s: running on valgrind", __func__);
199 : : return;
200 : : }
201 : : #endif
202 : :
203 : 0 : pid = fork();
204 [ # # ]: 0 : if (pid > 0) {
205 : : siginfo_t si;
206 : :
207 : 0 : (void) wait_for_terminate(pid, &si);
208 : :
209 [ # # ]: 0 : assert_se(si.si_code == CLD_EXITED);
210 [ # # ]: 0 : assert_se(si.si_status == 0);
211 : :
212 : 0 : return;
213 : : }
214 : :
215 [ # # ]: 0 : assert_se(pid == 0);
216 [ # # ]: 0 : assert_se(unshare(CLONE_NEWNS) >= 0);
217 : :
218 [ # # ]: 0 : if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
219 [ # # ]: 0 : log_warning_errno(errno, "mount(..., \"/\", MS_SLAVE|MS_REC, ...) failed: %m");
220 [ # # # # ]: 0 : assert_se(IN_SET(errno, EPERM, EACCES));
221 : 0 : return;
222 : : }
223 : :
224 : 0 : fd = mkostemp(path, O_CLOEXEC);
225 [ # # ]: 0 : assert_se(fd >= 0);
226 : :
227 : : /* Note that we don't unmount the following bind-mount at the end of the test because the kernel
228 : : * will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */
229 [ # # ]: 0 : if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
230 : : /* This happens under selinux… Abort the test in this case. */
231 [ # # ]: 0 : log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
232 [ # # # # ]: 0 : assert_se(IN_SET(errno, EPERM, EACCES));
233 : 0 : return;
234 : : }
235 : :
236 [ # # ]: 0 : assert_se(unlink(path) >= 0);
237 : :
238 [ # # ]: 0 : assert_se(prctl(PR_SET_NAME, "testa") >= 0);
239 : :
240 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) == -ENOENT);
241 : :
242 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
243 [ # # ]: 0 : assert_se(streq(line, "[testa]"));
244 : 0 : line = mfree(line);
245 : :
246 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 0, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
247 [ # # ]: 0 : log_info("'%s'", line);
248 [ # # ]: 0 : assert_se(streq(line, ""));
249 : 0 : line = mfree(line);
250 : :
251 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
252 [ # # ]: 0 : assert_se(streq(line, "…"));
253 : 0 : line = mfree(line);
254 : :
255 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
256 [ # # ]: 0 : assert_se(streq(line, "[…"));
257 : 0 : line = mfree(line);
258 : :
259 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
260 [ # # ]: 0 : assert_se(streq(line, "[t…"));
261 : 0 : line = mfree(line);
262 : :
263 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
264 [ # # ]: 0 : assert_se(streq(line, "[te…"));
265 : 0 : line = mfree(line);
266 : :
267 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
268 [ # # ]: 0 : assert_se(streq(line, "[tes…"));
269 : 0 : line = mfree(line);
270 : :
271 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
272 [ # # ]: 0 : assert_se(streq(line, "[test…"));
273 : 0 : line = mfree(line);
274 : :
275 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
276 [ # # ]: 0 : assert_se(streq(line, "[testa]"));
277 : 0 : line = mfree(line);
278 : :
279 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
280 [ # # ]: 0 : assert_se(streq(line, "[testa]"));
281 : 0 : line = mfree(line);
282 : :
283 [ # # ]: 0 : assert_se(write(fd, "foo\0bar", 8) == 8);
284 : :
285 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) >= 0);
286 [ # # ]: 0 : log_info("'%s'", line);
287 [ # # ]: 0 : assert_se(streq(line, "foo bar"));
288 : 0 : line = mfree(line);
289 : :
290 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
291 [ # # ]: 0 : assert_se(streq(line, "foo bar"));
292 : 0 : line = mfree(line);
293 : :
294 [ # # ]: 0 : assert_se(write(fd, "quux", 4) == 4);
295 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) >= 0);
296 [ # # ]: 0 : log_info("'%s'", line);
297 [ # # ]: 0 : assert_se(streq(line, "foo bar quux"));
298 : 0 : line = mfree(line);
299 : :
300 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
301 [ # # ]: 0 : assert_se(streq(line, "foo bar quux"));
302 : 0 : line = mfree(line);
303 : :
304 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
305 [ # # ]: 0 : assert_se(streq(line, "…"));
306 : 0 : line = mfree(line);
307 : :
308 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
309 [ # # ]: 0 : assert_se(streq(line, "f…"));
310 : 0 : line = mfree(line);
311 : :
312 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
313 [ # # ]: 0 : assert_se(streq(line, "fo…"));
314 : 0 : line = mfree(line);
315 : :
316 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
317 [ # # ]: 0 : assert_se(streq(line, "foo…"));
318 : 0 : line = mfree(line);
319 : :
320 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
321 [ # # ]: 0 : assert_se(streq(line, "foo …"));
322 : 0 : line = mfree(line);
323 : :
324 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
325 [ # # ]: 0 : assert_se(streq(line, "foo b…"));
326 : 0 : line = mfree(line);
327 : :
328 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
329 [ # # ]: 0 : assert_se(streq(line, "foo ba…"));
330 : 0 : line = mfree(line);
331 : :
332 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
333 [ # # ]: 0 : assert_se(streq(line, "foo bar…"));
334 : 0 : line = mfree(line);
335 : :
336 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 9, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
337 [ # # ]: 0 : assert_se(streq(line, "foo bar …"));
338 : 0 : line = mfree(line);
339 : :
340 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
341 [ # # ]: 0 : assert_se(streq(line, "foo bar q…"));
342 : 0 : line = mfree(line);
343 : :
344 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
345 [ # # ]: 0 : assert_se(streq(line, "foo bar qu…"));
346 : 0 : line = mfree(line);
347 : :
348 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
349 [ # # ]: 0 : assert_se(streq(line, "foo bar quux"));
350 : 0 : line = mfree(line);
351 : :
352 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 13, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
353 [ # # ]: 0 : assert_se(streq(line, "foo bar quux"));
354 : 0 : line = mfree(line);
355 : :
356 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 14, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
357 [ # # ]: 0 : assert_se(streq(line, "foo bar quux"));
358 : 0 : line = mfree(line);
359 : :
360 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
361 [ # # ]: 0 : assert_se(streq(line, "foo bar quux"));
362 : 0 : line = mfree(line);
363 : :
364 [ # # ]: 0 : assert_se(ftruncate(fd, 0) >= 0);
365 [ # # ]: 0 : assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
366 : :
367 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) == -ENOENT);
368 : :
369 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
370 [ # # ]: 0 : assert_se(streq(line, "[aaaa bbbb cccc]"));
371 : 0 : line = mfree(line);
372 : :
373 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
374 [ # # ]: 0 : assert_se(streq(line, "[aaaa bbb…"));
375 : 0 : line = mfree(line);
376 : :
377 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
378 [ # # ]: 0 : assert_se(streq(line, "[aaaa bbbb…"));
379 : 0 : line = mfree(line);
380 : :
381 [ # # ]: 0 : assert_se(get_process_cmdline(getpid_cached(), 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
382 [ # # ]: 0 : assert_se(streq(line, "[aaaa bbbb …"));
383 : 0 : line = mfree(line);
384 : :
385 : 0 : safe_close(fd);
386 : 0 : _exit(EXIT_SUCCESS);
387 : : }
388 : :
389 : 16 : static void test_rename_process_now(const char *p, int ret) {
390 [ + - + - ]: 16 : _cleanup_free_ char *comm = NULL, *cmdline = NULL;
391 : : int r;
392 : :
393 : 16 : r = rename_process(p);
394 [ - + # # : 16 : assert_se(r == ret ||
# # # # -
+ # # # #
# # ]
395 : : (ret == 0 && r >= 0) ||
396 : : (ret > 0 && r > 0));
397 : :
398 [ - + ]: 16 : if (r < 0)
399 : 0 : return;
400 : :
401 : : #if HAVE_VALGRIND_VALGRIND_H
402 : : /* see above, valgrind is weird, we can't verify what we are doing here */
403 : : if (RUNNING_ON_VALGRIND)
404 : : return;
405 : : #endif
406 : :
407 [ - + ]: 16 : assert_se(get_process_comm(0, &comm) >= 0);
408 [ + - ]: 16 : log_info("comm = <%s>", comm);
409 [ - + ]: 16 : assert_se(strneq(comm, p, TASK_COMM_LEN-1));
410 : : /* We expect comm to be at most 16 bytes (TASK_COMM_LEN). The kernel may raise this limit in the
411 : : * future. We'd only check the initial part, at least until we recompile, but this will still pass. */
412 : :
413 : 16 : r = get_process_cmdline(0, SIZE_MAX, 0, &cmdline);
414 [ - + ]: 16 : assert_se(r >= 0);
415 : : /* we cannot expect cmdline to be renamed properly without privileges */
416 [ - + ]: 16 : if (geteuid() == 0) {
417 [ # # # # ]: 0 : if (r == 0 && detect_container() > 0)
418 [ # # ]: 0 : log_info("cmdline = <%s> (not verified, Running in unprivileged container?)", cmdline);
419 : : else {
420 [ # # ]: 0 : log_info("cmdline = <%s>", cmdline);
421 [ # # ]: 0 : assert_se(strneq(p, cmdline, STRLEN("test-process-util")));
422 [ # # ]: 0 : assert_se(startswith(p, cmdline));
423 : : }
424 : : } else
425 [ + - ]: 16 : log_info("cmdline = <%s> (not verified)", cmdline);
426 : : }
427 : :
428 : 28 : static void test_rename_process_one(const char *p, int ret) {
429 : : siginfo_t si;
430 : : pid_t pid;
431 : :
432 : 28 : pid = fork();
433 [ - + ]: 24 : assert_se(pid >= 0);
434 : :
435 [ - + ]: 24 : if (pid == 0) {
436 : : /* child */
437 : 0 : test_rename_process_now(p, ret);
438 : 0 : _exit(EXIT_SUCCESS);
439 : : }
440 : :
441 [ - + ]: 24 : assert_se(wait_for_terminate(pid, &si) >= 0);
442 [ - + ]: 24 : assert_se(si.si_code == CLD_EXITED);
443 [ - + ]: 24 : assert_se(si.si_status == EXIT_SUCCESS);
444 : 24 : }
445 : :
446 : 4 : static void test_rename_process_multi(void) {
447 : : pid_t pid;
448 : :
449 : 4 : pid = fork();
450 [ - + ]: 8 : assert_se(pid >= 0);
451 : :
452 [ + + ]: 8 : if (pid > 0) {
453 : : siginfo_t si;
454 : :
455 [ - + ]: 4 : assert_se(wait_for_terminate(pid, &si) >= 0);
456 [ - + ]: 4 : assert_se(si.si_code == CLD_EXITED);
457 [ - + ]: 4 : assert_se(si.si_status == EXIT_SUCCESS);
458 : :
459 : 4 : return;
460 : : }
461 : :
462 : : /* child */
463 : 4 : test_rename_process_now("one", 1);
464 : 4 : test_rename_process_now("more", 0); /* longer than "one", hence truncated */
465 : 4 : (void) setresuid(99, 99, 99); /* change uid when running privileged */
466 : 4 : test_rename_process_now("time!", 0);
467 : 4 : test_rename_process_now("0", 1); /* shorter than "one", should fit */
468 : 4 : test_rename_process_one("", -EINVAL);
469 : 4 : test_rename_process_one(NULL, -EINVAL);
470 : 0 : _exit(EXIT_SUCCESS);
471 : : }
472 : :
473 : 4 : static void test_rename_process(void) {
474 : 4 : test_rename_process_one(NULL, -EINVAL);
475 : 4 : test_rename_process_one("", -EINVAL);
476 : 4 : test_rename_process_one("foo", 1); /* should always fit */
477 : 4 : test_rename_process_one("this is a really really long process name, followed by some more words", 0); /* unlikely to fit */
478 : 4 : test_rename_process_one("1234567", 1); /* should always fit */
479 : 4 : test_rename_process_multi(); /* multiple invocations and dropped privileges */
480 : 4 : }
481 : :
482 : 4 : static void test_getpid_cached(void) {
483 : : siginfo_t si;
484 : : pid_t a, b, c, d, e, f, child;
485 : :
486 : 4 : a = raw_getpid();
487 : 4 : b = getpid_cached();
488 : 4 : c = getpid();
489 : :
490 [ + - - + ]: 4 : assert_se(a == b && a == c);
491 : :
492 : 4 : child = fork();
493 [ - + ]: 4 : assert_se(child >= 0);
494 : :
495 [ - + ]: 4 : if (child == 0) {
496 : : /* In child */
497 : 0 : a = raw_getpid();
498 : 0 : b = getpid_cached();
499 : 0 : c = getpid();
500 : :
501 [ # # # # ]: 0 : assert_se(a == b && a == c);
502 : 0 : _exit(EXIT_SUCCESS);
503 : : }
504 : :
505 : 4 : d = raw_getpid();
506 : 4 : e = getpid_cached();
507 : 4 : f = getpid();
508 : :
509 [ + - - + : 4 : assert_se(a == d && a == e && a == f);
+ - - + ]
510 : :
511 [ - + ]: 4 : assert_se(wait_for_terminate(child, &si) >= 0);
512 [ - + ]: 4 : assert_se(si.si_status == 0);
513 [ - + ]: 4 : assert_se(si.si_code == CLD_EXITED);
514 : 4 : }
515 : :
516 : : #define MEASURE_ITERATIONS (10000000LLU)
517 : :
518 : 4 : static void test_getpid_measure(void) {
519 : : unsigned long long i;
520 : : usec_t t, q;
521 : :
522 : 4 : t = now(CLOCK_MONOTONIC);
523 [ + + ]: 40000004 : for (i = 0; i < MEASURE_ITERATIONS; i++)
524 : 40000000 : (void) getpid();
525 : 4 : q = now(CLOCK_MONOTONIC) - t;
526 : :
527 [ + - ]: 4 : log_info(" glibc getpid(): %lf µs each\n", (double) q / MEASURE_ITERATIONS);
528 : :
529 : 4 : t = now(CLOCK_MONOTONIC);
530 [ + + ]: 40000004 : for (i = 0; i < MEASURE_ITERATIONS; i++)
531 : 40000000 : (void) getpid_cached();
532 : 4 : q = now(CLOCK_MONOTONIC) - t;
533 : :
534 [ + - ]: 4 : log_info("getpid_cached(): %lf µs each\n", (double) q / MEASURE_ITERATIONS);
535 : 4 : }
536 : :
537 : 4 : static void test_safe_fork(void) {
538 : : siginfo_t status;
539 : : pid_t pid;
540 : : int r;
541 : :
542 [ - + ]: 8 : BLOCK_SIGNALS(SIGCHLD);
543 : :
544 : 4 : r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_REOPEN_LOG, &pid);
545 [ - + ]: 4 : assert_se(r >= 0);
546 : :
547 [ - + ]: 4 : if (r == 0) {
548 : : /* child */
549 : 0 : usleep(100 * USEC_PER_MSEC);
550 : :
551 : 0 : _exit(88);
552 : : }
553 : :
554 [ - + ]: 4 : assert_se(wait_for_terminate(pid, &status) >= 0);
555 [ - + ]: 4 : assert_se(status.si_code == CLD_EXITED);
556 [ - + ]: 4 : assert_se(status.si_status == 88);
557 : 4 : }
558 : :
559 : 4 : static void test_pid_to_ptr(void) {
560 : :
561 [ - + ]: 4 : assert_se(PTR_TO_PID(NULL) == 0);
562 [ - + ]: 4 : assert_se(PID_TO_PTR(0) == NULL);
563 : :
564 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(1)) == 1);
565 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(2)) == 2);
566 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(-1)) == -1);
567 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(-2)) == -2);
568 : :
569 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MAX)) == INT16_MAX);
570 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MIN)) == INT16_MIN);
571 : :
572 : : #if SIZEOF_PID_T >= 4
573 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MAX)) == INT32_MAX);
574 [ - + ]: 4 : assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MIN)) == INT32_MIN);
575 : : #endif
576 : 4 : }
577 : :
578 : 40 : static void test_ioprio_class_from_to_string_one(const char *val, int expected) {
579 [ - + ]: 40 : assert_se(ioprio_class_from_string(val) == expected);
580 [ + + ]: 40 : if (expected >= 0) {
581 : 32 : _cleanup_free_ char *s = NULL;
582 : : unsigned ret;
583 : :
584 [ - + ]: 32 : assert_se(ioprio_class_to_string_alloc(expected, &s) == 0);
585 : : /* We sometimes get a class number and sometimes a number back */
586 [ + + - + ]: 32 : assert_se(streq(s, val) ||
587 : : safe_atou(val, &ret) == 0);
588 : : }
589 : 40 : }
590 : :
591 : 4 : static void test_ioprio_class_from_to_string(void) {
592 : 4 : test_ioprio_class_from_to_string_one("none", IOPRIO_CLASS_NONE);
593 : 4 : test_ioprio_class_from_to_string_one("realtime", IOPRIO_CLASS_RT);
594 : 4 : test_ioprio_class_from_to_string_one("best-effort", IOPRIO_CLASS_BE);
595 : 4 : test_ioprio_class_from_to_string_one("idle", IOPRIO_CLASS_IDLE);
596 : 4 : test_ioprio_class_from_to_string_one("0", 0);
597 : 4 : test_ioprio_class_from_to_string_one("1", 1);
598 : 4 : test_ioprio_class_from_to_string_one("7", 7);
599 : 4 : test_ioprio_class_from_to_string_one("8", 8);
600 : 4 : test_ioprio_class_from_to_string_one("9", -1);
601 : 4 : test_ioprio_class_from_to_string_one("-1", -1);
602 : 4 : }
603 : :
604 : 4 : int main(int argc, char *argv[]) {
605 : 4 : test_setup_logging(LOG_DEBUG);
606 : :
607 : 4 : save_argc_argv(argc, argv);
608 : :
609 [ - + ]: 4 : if (argc > 1) {
610 : 0 : pid_t pid = 0;
611 : :
612 : 0 : (void) parse_pid(argv[1], &pid);
613 : 0 : test_get_process_comm(pid);
614 : : } else {
615 [ + - ]: 4 : TEST_REQ_RUNNING_SYSTEMD(test_get_process_comm(1));
616 : 4 : test_get_process_comm(getpid());
617 : : }
618 : :
619 : 4 : test_get_process_comm_escape();
620 : 4 : test_pid_is_unwaited();
621 : 4 : test_pid_is_alive();
622 : 4 : test_personality();
623 : 4 : test_get_process_cmdline_harder();
624 : 4 : test_rename_process();
625 : 4 : test_getpid_cached();
626 : 4 : test_getpid_measure();
627 : 4 : test_safe_fork();
628 : 4 : test_pid_to_ptr();
629 : 4 : test_ioprio_class_from_to_string();
630 : :
631 : 4 : return 0;
632 : : }
|