blob: 7e45ec3d12bf76c578290e152741218589dfc011 [file] [log] [blame]
Elliott Hughes14e3ff92017-10-06 16:58:36 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <spawn.h>
18
19#include <errno.h>
20#include <fcntl.h>
21#include <gtest/gtest.h>
22
Elliott Hughes71ba5892018-02-07 12:44:45 -080023#include "SignalUtils.h"
Elliott Hughes14e3ff92017-10-06 16:58:36 -070024#include "utils.h"
25
26#include <android-base/file.h>
27#include <android-base/strings.h>
28
29// Old versions of glibc didn't have POSIX_SPAWN_SETSID.
30#if __GLIBC__
31# if !defined(POSIX_SPAWN_SETSID)
32# define POSIX_SPAWN_SETSID 0
33# endif
34#endif
35
36TEST(spawn, posix_spawnattr_init_posix_spawnattr_destroy) {
37 posix_spawnattr_t sa;
38 ASSERT_EQ(0, posix_spawnattr_init(&sa));
39 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
40}
41
42TEST(spawn, posix_spawnattr_setflags_EINVAL) {
43 posix_spawnattr_t sa;
44 ASSERT_EQ(0, posix_spawnattr_init(&sa));
45 ASSERT_EQ(EINVAL, posix_spawnattr_setflags(&sa, ~0));
46 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
47}
48
49TEST(spawn, posix_spawnattr_setflags_posix_spawnattr_getflags) {
50 posix_spawnattr_t sa;
51 ASSERT_EQ(0, posix_spawnattr_init(&sa));
52
53 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_RESETIDS));
54 short flags;
55 ASSERT_EQ(0, posix_spawnattr_getflags(&sa, &flags));
56 ASSERT_EQ(POSIX_SPAWN_RESETIDS, flags);
57
58 constexpr short all_flags = POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF |
59 POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSCHEDPARAM |
60 POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_USEVFORK | POSIX_SPAWN_SETSID;
61 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, all_flags));
62 ASSERT_EQ(0, posix_spawnattr_getflags(&sa, &flags));
63 ASSERT_EQ(all_flags, flags);
64
65 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
66}
67
68TEST(spawn, posix_spawnattr_setpgroup_posix_spawnattr_getpgroup) {
69 posix_spawnattr_t sa;
70 ASSERT_EQ(0, posix_spawnattr_init(&sa));
71
72 ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 123));
73 pid_t g;
74 ASSERT_EQ(0, posix_spawnattr_getpgroup(&sa, &g));
75 ASSERT_EQ(123, g);
76
77 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
78}
79
80TEST(spawn, posix_spawnattr_setsigmask_posix_spawnattr_getsigmask) {
81 posix_spawnattr_t sa;
82 ASSERT_EQ(0, posix_spawnattr_init(&sa));
83
84 sigset_t sigs;
85 ASSERT_EQ(0, posix_spawnattr_getsigmask(&sa, &sigs));
86 ASSERT_FALSE(sigismember(&sigs, SIGALRM));
87
88 sigset_t just_SIGALRM;
89 sigemptyset(&just_SIGALRM);
90 sigaddset(&just_SIGALRM, SIGALRM);
91 ASSERT_EQ(0, posix_spawnattr_setsigmask(&sa, &just_SIGALRM));
92
93 ASSERT_EQ(0, posix_spawnattr_getsigmask(&sa, &sigs));
94 ASSERT_TRUE(sigismember(&sigs, SIGALRM));
95
96 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
97}
98
Elliott Hughes5905d6f2018-01-30 15:09:51 -080099TEST(spawn, posix_spawnattr_setsigmask64_posix_spawnattr_getsigmask64) {
100 posix_spawnattr_t sa;
101 ASSERT_EQ(0, posix_spawnattr_init(&sa));
102
103 sigset64_t sigs;
104 ASSERT_EQ(0, posix_spawnattr_getsigmask64(&sa, &sigs));
105 ASSERT_FALSE(sigismember64(&sigs, SIGRTMIN));
106
107 sigset64_t just_SIGRTMIN;
108 sigemptyset64(&just_SIGRTMIN);
109 sigaddset64(&just_SIGRTMIN, SIGRTMIN);
110 ASSERT_EQ(0, posix_spawnattr_setsigmask64(&sa, &just_SIGRTMIN));
111
112 ASSERT_EQ(0, posix_spawnattr_getsigmask64(&sa, &sigs));
113 ASSERT_TRUE(sigismember64(&sigs, SIGRTMIN));
114
115 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
116}
117
Elliott Hughes14e3ff92017-10-06 16:58:36 -0700118TEST(spawn, posix_spawnattr_setsigdefault_posix_spawnattr_getsigdefault) {
119 posix_spawnattr_t sa;
120 ASSERT_EQ(0, posix_spawnattr_init(&sa));
121
122 sigset_t sigs;
123 ASSERT_EQ(0, posix_spawnattr_getsigdefault(&sa, &sigs));
124 ASSERT_FALSE(sigismember(&sigs, SIGALRM));
125
126 sigset_t just_SIGALRM;
127 sigemptyset(&just_SIGALRM);
128 sigaddset(&just_SIGALRM, SIGALRM);
129 ASSERT_EQ(0, posix_spawnattr_setsigdefault(&sa, &just_SIGALRM));
130
131 ASSERT_EQ(0, posix_spawnattr_getsigdefault(&sa, &sigs));
132 ASSERT_TRUE(sigismember(&sigs, SIGALRM));
133
134 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
135}
136
Elliott Hughes5905d6f2018-01-30 15:09:51 -0800137TEST(spawn, posix_spawnattr_setsigdefault64_posix_spawnattr_getsigdefault64) {
138 posix_spawnattr_t sa;
139 ASSERT_EQ(0, posix_spawnattr_init(&sa));
140
141 sigset64_t sigs;
142 ASSERT_EQ(0, posix_spawnattr_getsigdefault64(&sa, &sigs));
143 ASSERT_FALSE(sigismember64(&sigs, SIGRTMIN));
144
145 sigset64_t just_SIGRTMIN;
146 sigemptyset64(&just_SIGRTMIN);
147 sigaddset64(&just_SIGRTMIN, SIGRTMIN);
148 ASSERT_EQ(0, posix_spawnattr_setsigdefault64(&sa, &just_SIGRTMIN));
149
150 ASSERT_EQ(0, posix_spawnattr_getsigdefault64(&sa, &sigs));
151 ASSERT_TRUE(sigismember64(&sigs, SIGRTMIN));
152
153 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
154}
155
Elliott Hughes14e3ff92017-10-06 16:58:36 -0700156TEST(spawn, posix_spawnattr_setsschedparam_posix_spawnattr_getsschedparam) {
157 posix_spawnattr_t sa;
158 ASSERT_EQ(0, posix_spawnattr_init(&sa));
159
160 sched_param sp;
161 ASSERT_EQ(0, posix_spawnattr_getschedparam(&sa, &sp));
162 ASSERT_EQ(0, sp.sched_priority);
163
164 sched_param sp123 = { .sched_priority = 123 };
165 ASSERT_EQ(0, posix_spawnattr_setschedparam(&sa, &sp123));
166
167 ASSERT_EQ(0, posix_spawnattr_getschedparam(&sa, &sp));
168 ASSERT_EQ(123, sp.sched_priority);
169
170 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
171}
172
173TEST(spawn, posix_spawnattr_setschedpolicy_posix_spawnattr_getschedpolicy) {
174 posix_spawnattr_t sa;
175 ASSERT_EQ(0, posix_spawnattr_init(&sa));
176
177 int p;
178 ASSERT_EQ(0, posix_spawnattr_getschedpolicy(&sa, &p));
179 ASSERT_EQ(0, p);
180
181 ASSERT_EQ(0, posix_spawnattr_setschedpolicy(&sa, SCHED_FIFO));
182
183 ASSERT_EQ(0, posix_spawnattr_getschedpolicy(&sa, &p));
184 ASSERT_EQ(SCHED_FIFO, p);
185
186 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
187}
188
189TEST(spawn, posix_spawn) {
190 ExecTestHelper eth;
191 eth.SetArgs({BIN_DIR "true", nullptr});
192 pid_t pid;
193 ASSERT_EQ(0, posix_spawn(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
194 AssertChildExited(pid, 0);
195}
196
197TEST(spawn, posix_spawn_not_found) {
198 ExecTestHelper eth;
199 eth.SetArgs({"true", nullptr});
200 pid_t pid;
201 ASSERT_EQ(0, posix_spawn(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
202 AssertChildExited(pid, 127);
203}
204
205TEST(spawn, posix_spawnp) {
206 ExecTestHelper eth;
207 eth.SetArgs({"true", nullptr});
208 pid_t pid;
209 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
210 AssertChildExited(pid, 0);
211}
212
213TEST(spawn, posix_spawnp_not_found) {
214 ExecTestHelper eth;
215 eth.SetArgs({"does-not-exist", nullptr});
216 pid_t pid;
217 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
218 AssertChildExited(pid, 127);
219}
220
221TEST(spawn, posix_spawn_environment) {
222 ExecTestHelper eth;
223 eth.SetArgs({"sh", "-c", "exit $posix_spawn_environment_test", nullptr});
224 eth.SetEnv({"posix_spawn_environment_test=66", nullptr});
225 pid_t pid;
226 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), eth.GetEnv()));
227 AssertChildExited(pid, 66);
228}
229
230TEST(spawn, posix_spawn_file_actions) {
231 int fds[2];
232 ASSERT_NE(-1, pipe(fds));
233
234 posix_spawn_file_actions_t fa;
235 ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
236
237 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
238 ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
239 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
240 // Check that close(2) failures are ignored by closing the same fd again.
241 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
242 ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 56, "/proc/version", O_RDONLY, 0));
243
244 ExecTestHelper eth;
245 eth.SetArgs({"ls", "-l", "/proc/self/fd", nullptr});
246 pid_t pid;
247 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, nullptr, eth.GetArgs(), eth.GetEnv()));
248 ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));
249
250 ASSERT_EQ(0, close(fds[1]));
251 std::string content;
252 ASSERT_TRUE(android::base::ReadFdToString(fds[0], &content));
253 ASSERT_EQ(0, close(fds[0]));
254
255 AssertChildExited(pid, 0);
256
257 // We'll know the dup2 worked if we see any ls(1) output in our pipe.
258 // The open we can check manually...
259 bool open_to_fd_56_worked = false;
260 for (const auto& line : android::base::Split(content, "\n")) {
261 if (line.find(" 56 -> /proc/version") != std::string::npos) open_to_fd_56_worked = true;
262 }
263 ASSERT_TRUE(open_to_fd_56_worked);
264}
265
266static void CatFileToString(posix_spawnattr_t* sa, const char* path, std::string* content) {
267 int fds[2];
268 ASSERT_NE(-1, pipe(fds));
269
270 posix_spawn_file_actions_t fa;
271 ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
272 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
273 ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
274 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
275
276 ExecTestHelper eth;
277 eth.SetArgs({"cat", path, nullptr});
278 pid_t pid;
279 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, sa, eth.GetArgs(), nullptr));
280 ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));
281
282 ASSERT_EQ(0, close(fds[1]));
283 ASSERT_TRUE(android::base::ReadFdToString(fds[0], content));
284 ASSERT_EQ(0, close(fds[0]));
285 AssertChildExited(pid, 0);
286}
287
288struct ProcStat {
289 pid_t pid;
290 pid_t ppid;
291 pid_t pgrp;
292 pid_t sid;
293};
294
295static void GetChildStat(posix_spawnattr_t* sa, ProcStat* ps) {
296 std::string content;
297 CatFileToString(sa, "/proc/self/stat", &content);
298
299 ASSERT_EQ(4, sscanf(content.c_str(), "%d (cat) %*c %d %d %d", &ps->pid, &ps->ppid, &ps->pgrp,
300 &ps->sid));
301
302 ASSERT_EQ(getpid(), ps->ppid);
303}
304
305struct ProcStatus {
306 uint64_t sigblk;
307 uint64_t sigign;
308};
309
310static void GetChildStatus(posix_spawnattr_t* sa, ProcStatus* ps) {
311 std::string content;
312 CatFileToString(sa, "/proc/self/status", &content);
313
314 bool saw_blk = false;
315 bool saw_ign = false;
316 for (const auto& line : android::base::Split(content, "\n")) {
317 if (sscanf(line.c_str(), "SigBlk: %" SCNx64, &ps->sigblk) == 1) saw_blk = true;
318 if (sscanf(line.c_str(), "SigIgn: %" SCNx64, &ps->sigign) == 1) saw_ign = true;
319 }
320 ASSERT_TRUE(saw_blk);
321 ASSERT_TRUE(saw_ign);
322}
323
324TEST(spawn, posix_spawn_POSIX_SPAWN_SETSID_clear) {
325 pid_t parent_sid = getsid(0);
326
327 posix_spawnattr_t sa;
328 ASSERT_EQ(0, posix_spawnattr_init(&sa));
329 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, 0));
330
331 ProcStat ps = {};
332 GetChildStat(&sa, &ps);
333 ASSERT_EQ(parent_sid, ps.sid);
334 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
335}
336
337TEST(spawn, posix_spawn_POSIX_SPAWN_SETSID_set) {
338 pid_t parent_sid = getsid(0);
339
340 posix_spawnattr_t sa;
341 ASSERT_EQ(0, posix_spawnattr_init(&sa));
342 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSID));
343
344 ProcStat ps = {};
345 GetChildStat(&sa, &ps);
346 ASSERT_NE(parent_sid, ps.sid);
347 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
348}
349
350TEST(spawn, posix_spawn_POSIX_SPAWN_SETPGROUP_clear) {
351 pid_t parent_pgrp = getpgrp();
352
353 posix_spawnattr_t sa;
354 ASSERT_EQ(0, posix_spawnattr_init(&sa));
355 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, 0));
356
357 ProcStat ps = {};
358 GetChildStat(&sa, &ps);
359 ASSERT_EQ(parent_pgrp, ps.pgrp);
360 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
361}
362
363TEST(spawn, posix_spawn_POSIX_SPAWN_SETPGROUP_set) {
364 pid_t parent_pgrp = getpgrp();
365
366 posix_spawnattr_t sa;
367 ASSERT_EQ(0, posix_spawnattr_init(&sa));
368 ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 0));
369 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETPGROUP));
370
371 ProcStat ps = {};
372 GetChildStat(&sa, &ps);
373 ASSERT_NE(parent_pgrp, ps.pgrp);
374 // Setting pgid 0 means "the same as the caller's pid".
375 ASSERT_EQ(ps.pid, ps.pgrp);
376 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
377}
378
379TEST(spawn, posix_spawn_POSIX_SPAWN_SETSIGMASK) {
380 // Block SIGBUS in the parent...
381 sigset_t just_SIGBUS;
382 sigemptyset(&just_SIGBUS);
383 sigaddset(&just_SIGBUS, SIGBUS);
384 ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGBUS, nullptr));
385
386 posix_spawnattr_t sa;
387 ASSERT_EQ(0, posix_spawnattr_init(&sa));
388
389 // Ask for only SIGALRM to be blocked in the child...
390 sigset_t just_SIGALRM;
391 sigemptyset(&just_SIGALRM);
392 sigaddset(&just_SIGALRM, SIGALRM);
393 ASSERT_EQ(0, posix_spawnattr_setsigmask(&sa, &just_SIGALRM));
394 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSIGMASK));
395
396 // Check that's what happens...
397 ProcStatus ps = {};
398 GetChildStatus(&sa, &ps);
399 EXPECT_EQ(static_cast<uint64_t>(1 << (SIGALRM - 1)), ps.sigblk);
400 EXPECT_EQ(static_cast<uint64_t>(0), ps.sigign);
401
402 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
403}
404
405TEST(spawn, posix_spawn_POSIX_SPAWN_SETSIGDEF) {
406 // Ignore SIGALRM and SIGCONT in the parent...
407 ASSERT_NE(SIG_ERR, signal(SIGALRM, SIG_IGN));
408 ASSERT_NE(SIG_ERR, signal(SIGCONT, SIG_IGN));
409
410 posix_spawnattr_t sa;
411 ASSERT_EQ(0, posix_spawnattr_init(&sa));
412
413 // Ask for SIGALRM to be defaulted in the child...
414 sigset_t just_SIGALRM;
415 sigemptyset(&just_SIGALRM);
416 sigaddset(&just_SIGALRM, SIGALRM);
Elliott Hughes4b1c6e72018-01-24 18:54:38 -0800417
Elliott Hughes14e3ff92017-10-06 16:58:36 -0700418 ASSERT_EQ(0, posix_spawnattr_setsigdefault(&sa, &just_SIGALRM));
419 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSIGDEF));
420
421 // Check that's what happens...
422 ProcStatus ps = {};
423 GetChildStatus(&sa, &ps);
424 EXPECT_EQ(static_cast<uint64_t>(0), ps.sigblk);
425 EXPECT_EQ(static_cast<uint64_t>(1 << (SIGCONT - 1)), ps.sigign);
426
427 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
428}
Elliott Hughes7bfacaa2017-11-28 19:58:00 -0800429
430TEST(spawn, signal_stress) {
431 // Ensure that posix_spawn doesn't restore the caller's signal mask in the
432 // child without first defaulting any caught signals (http://b/68707996).
433 static pid_t parent = getpid();
434
Elliott Hughes4b1c6e72018-01-24 18:54:38 -0800435 setpgid(0, 0);
Ryan Pricharda1bc8262018-04-03 20:46:11 -0700436 signal(SIGRTMIN, SIG_IGN);
Elliott Hughes4b1c6e72018-01-24 18:54:38 -0800437
Elliott Hughes7bfacaa2017-11-28 19:58:00 -0800438 pid_t pid = fork();
439 ASSERT_NE(-1, pid);
440
441 if (pid == 0) {
442 for (size_t i = 0; i < 1024; ++i) {
Elliott Hughes4b1c6e72018-01-24 18:54:38 -0800443 kill(0, SIGRTMIN);
Elliott Hughes7bfacaa2017-11-28 19:58:00 -0800444 usleep(10);
445 }
Elliott Hughes4b1c6e72018-01-24 18:54:38 -0800446 _exit(99);
Elliott Hughes7bfacaa2017-11-28 19:58:00 -0800447 }
448
449 // We test both with and without attributes, because they used to be
450 // different codepaths. We also test with an empty `sigdefault` set.
451 posix_spawnattr_t attr1;
452 posix_spawnattr_init(&attr1);
453
454 sigset_t empty_mask = {};
455 posix_spawnattr_t attr2;
456 posix_spawnattr_init(&attr2);
457 posix_spawnattr_setflags(&attr2, POSIX_SPAWN_SETSIGDEF);
458 posix_spawnattr_setsigdefault(&attr2, &empty_mask);
459
460 posix_spawnattr_t* attrs[] = { nullptr, &attr1, &attr2 };
461
Elliott Hughes4b1c6e72018-01-24 18:54:38 -0800462 // We use a real-time signal because that's a tricky case for LP32
463 // because our sigset_t was too small.
464 ScopedSignalHandler ssh(SIGRTMIN, [](int) { ASSERT_EQ(getpid(), parent); });
Elliott Hughes7bfacaa2017-11-28 19:58:00 -0800465
466 ExecTestHelper eth;
467 eth.SetArgs({"true", nullptr});
468 for (size_t i = 0; i < 128; ++i) {
469 posix_spawn(nullptr, "true", nullptr, attrs[i % 3], eth.GetArgs(), nullptr);
470 }
Elliott Hughes4b1c6e72018-01-24 18:54:38 -0800471
472 AssertChildExited(pid, 99);
Elliott Hughes7bfacaa2017-11-28 19:58:00 -0800473}