1 /*
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 <sys/cdefs.h>
22
23 #include <gtest/gtest.h>
24
25 #include "SignalUtils.h"
26 #include "utils.h"
27
28 #include <android-base/file.h>
29 #include <android-base/strings.h>
30
31 // Old versions of glibc didn't have POSIX_SPAWN_SETSID.
32 #if __GLIBC__
33 # if !defined(POSIX_SPAWN_SETSID)
34 # define POSIX_SPAWN_SETSID 0
35 # endif
36 #elif defined(__BIONIC__)
37 #include <platform/bionic/reserved_signals.h>
38 #endif
39
TEST(spawn,posix_spawnattr_init_posix_spawnattr_destroy)40 TEST(spawn, posix_spawnattr_init_posix_spawnattr_destroy) {
41 posix_spawnattr_t sa;
42 ASSERT_EQ(0, posix_spawnattr_init(&sa));
43 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
44 }
45
TEST(spawn,posix_spawnattr_setflags_EINVAL)46 TEST(spawn, posix_spawnattr_setflags_EINVAL) {
47 posix_spawnattr_t sa;
48 ASSERT_EQ(0, posix_spawnattr_init(&sa));
49 ASSERT_EQ(EINVAL, posix_spawnattr_setflags(&sa, ~0));
50 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
51 }
52
TEST(spawn,posix_spawnattr_setflags_posix_spawnattr_getflags)53 TEST(spawn, posix_spawnattr_setflags_posix_spawnattr_getflags) {
54 posix_spawnattr_t sa;
55 ASSERT_EQ(0, posix_spawnattr_init(&sa));
56
57 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_RESETIDS));
58 short flags;
59 ASSERT_EQ(0, posix_spawnattr_getflags(&sa, &flags));
60 ASSERT_EQ(POSIX_SPAWN_RESETIDS, flags);
61
62 constexpr short all_flags = POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF |
63 POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSCHEDPARAM |
64 POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_USEVFORK | POSIX_SPAWN_SETSID;
65 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, all_flags));
66 ASSERT_EQ(0, posix_spawnattr_getflags(&sa, &flags));
67 ASSERT_EQ(all_flags, flags);
68
69 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
70 }
71
TEST(spawn,posix_spawnattr_setpgroup_posix_spawnattr_getpgroup)72 TEST(spawn, posix_spawnattr_setpgroup_posix_spawnattr_getpgroup) {
73 posix_spawnattr_t sa;
74 ASSERT_EQ(0, posix_spawnattr_init(&sa));
75
76 ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 123));
77 pid_t g;
78 ASSERT_EQ(0, posix_spawnattr_getpgroup(&sa, &g));
79 ASSERT_EQ(123, g);
80
81 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
82 }
83
TEST(spawn,posix_spawnattr_setsigmask_posix_spawnattr_getsigmask)84 TEST(spawn, posix_spawnattr_setsigmask_posix_spawnattr_getsigmask) {
85 posix_spawnattr_t sa;
86 ASSERT_EQ(0, posix_spawnattr_init(&sa));
87
88 sigset_t sigs;
89 ASSERT_EQ(0, posix_spawnattr_getsigmask(&sa, &sigs));
90 ASSERT_FALSE(sigismember(&sigs, SIGALRM));
91
92 sigset_t just_SIGALRM;
93 sigemptyset(&just_SIGALRM);
94 sigaddset(&just_SIGALRM, SIGALRM);
95 ASSERT_EQ(0, posix_spawnattr_setsigmask(&sa, &just_SIGALRM));
96
97 ASSERT_EQ(0, posix_spawnattr_getsigmask(&sa, &sigs));
98 ASSERT_TRUE(sigismember(&sigs, SIGALRM));
99
100 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
101 }
102
TEST(spawn,posix_spawnattr_setsigmask64_posix_spawnattr_getsigmask64)103 TEST(spawn, posix_spawnattr_setsigmask64_posix_spawnattr_getsigmask64) {
104 posix_spawnattr_t sa;
105 ASSERT_EQ(0, posix_spawnattr_init(&sa));
106
107 sigset64_t sigs;
108 ASSERT_EQ(0, posix_spawnattr_getsigmask64(&sa, &sigs));
109 ASSERT_FALSE(sigismember64(&sigs, SIGRTMIN));
110
111 sigset64_t just_SIGRTMIN;
112 sigemptyset64(&just_SIGRTMIN);
113 sigaddset64(&just_SIGRTMIN, SIGRTMIN);
114 ASSERT_EQ(0, posix_spawnattr_setsigmask64(&sa, &just_SIGRTMIN));
115
116 ASSERT_EQ(0, posix_spawnattr_getsigmask64(&sa, &sigs));
117 ASSERT_TRUE(sigismember64(&sigs, SIGRTMIN));
118
119 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
120 }
121
TEST(spawn,posix_spawnattr_setsigdefault_posix_spawnattr_getsigdefault)122 TEST(spawn, posix_spawnattr_setsigdefault_posix_spawnattr_getsigdefault) {
123 posix_spawnattr_t sa;
124 ASSERT_EQ(0, posix_spawnattr_init(&sa));
125
126 sigset_t sigs;
127 ASSERT_EQ(0, posix_spawnattr_getsigdefault(&sa, &sigs));
128 ASSERT_FALSE(sigismember(&sigs, SIGALRM));
129
130 sigset_t just_SIGALRM;
131 sigemptyset(&just_SIGALRM);
132 sigaddset(&just_SIGALRM, SIGALRM);
133 ASSERT_EQ(0, posix_spawnattr_setsigdefault(&sa, &just_SIGALRM));
134
135 ASSERT_EQ(0, posix_spawnattr_getsigdefault(&sa, &sigs));
136 ASSERT_TRUE(sigismember(&sigs, SIGALRM));
137
138 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
139 }
140
TEST(spawn,posix_spawnattr_setsigdefault64_posix_spawnattr_getsigdefault64)141 TEST(spawn, posix_spawnattr_setsigdefault64_posix_spawnattr_getsigdefault64) {
142 posix_spawnattr_t sa;
143 ASSERT_EQ(0, posix_spawnattr_init(&sa));
144
145 sigset64_t sigs;
146 ASSERT_EQ(0, posix_spawnattr_getsigdefault64(&sa, &sigs));
147 ASSERT_FALSE(sigismember64(&sigs, SIGRTMIN));
148
149 sigset64_t just_SIGRTMIN;
150 sigemptyset64(&just_SIGRTMIN);
151 sigaddset64(&just_SIGRTMIN, SIGRTMIN);
152 ASSERT_EQ(0, posix_spawnattr_setsigdefault64(&sa, &just_SIGRTMIN));
153
154 ASSERT_EQ(0, posix_spawnattr_getsigdefault64(&sa, &sigs));
155 ASSERT_TRUE(sigismember64(&sigs, SIGRTMIN));
156
157 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
158 }
159
TEST(spawn,posix_spawnattr_setsschedparam_posix_spawnattr_getsschedparam)160 TEST(spawn, posix_spawnattr_setsschedparam_posix_spawnattr_getsschedparam) {
161 posix_spawnattr_t sa;
162 ASSERT_EQ(0, posix_spawnattr_init(&sa));
163
164 sched_param sp;
165 ASSERT_EQ(0, posix_spawnattr_getschedparam(&sa, &sp));
166 ASSERT_EQ(0, sp.sched_priority);
167
168 sched_param sp123 = { .sched_priority = 123 };
169 ASSERT_EQ(0, posix_spawnattr_setschedparam(&sa, &sp123));
170
171 ASSERT_EQ(0, posix_spawnattr_getschedparam(&sa, &sp));
172 ASSERT_EQ(123, sp.sched_priority);
173
174 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
175 }
176
TEST(spawn,posix_spawnattr_setschedpolicy_posix_spawnattr_getschedpolicy)177 TEST(spawn, posix_spawnattr_setschedpolicy_posix_spawnattr_getschedpolicy) {
178 posix_spawnattr_t sa;
179 ASSERT_EQ(0, posix_spawnattr_init(&sa));
180
181 int p;
182 ASSERT_EQ(0, posix_spawnattr_getschedpolicy(&sa, &p));
183 ASSERT_EQ(0, p);
184
185 ASSERT_EQ(0, posix_spawnattr_setschedpolicy(&sa, SCHED_FIFO));
186
187 ASSERT_EQ(0, posix_spawnattr_getschedpolicy(&sa, &p));
188 ASSERT_EQ(SCHED_FIFO, p);
189
190 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
191 }
192
TEST(spawn,posix_spawn)193 TEST(spawn, posix_spawn) {
194 ExecTestHelper eth;
195 eth.SetArgs({BIN_DIR "true", nullptr});
196 pid_t pid;
197 ASSERT_EQ(0, posix_spawn(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
198 AssertChildExited(pid, 0);
199 }
200
TEST(spawn,posix_spawn_not_found)201 TEST(spawn, posix_spawn_not_found) {
202 ExecTestHelper eth;
203 eth.SetArgs({"true", nullptr});
204 pid_t pid;
205 ASSERT_EQ(0, posix_spawn(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
206 AssertChildExited(pid, 127);
207 }
208
TEST(spawn,posix_spawnp)209 TEST(spawn, posix_spawnp) {
210 ExecTestHelper eth;
211 eth.SetArgs({"true", nullptr});
212 pid_t pid;
213 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
214 AssertChildExited(pid, 0);
215 }
216
TEST(spawn,posix_spawnp_not_found)217 TEST(spawn, posix_spawnp_not_found) {
218 ExecTestHelper eth;
219 eth.SetArgs({"does-not-exist", nullptr});
220 pid_t pid;
221 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
222 AssertChildExited(pid, 127);
223 }
224
TEST(spawn,posix_spawn_environment)225 TEST(spawn, posix_spawn_environment) {
226 ExecTestHelper eth;
227 eth.SetArgs({"sh", "-c", "exit $posix_spawn_environment_test", nullptr});
228 eth.SetEnv({"posix_spawn_environment_test=66", nullptr});
229 pid_t pid;
230 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), eth.GetEnv()));
231 AssertChildExited(pid, 66);
232 }
233
TEST(spawn,posix_spawn_file_actions)234 TEST(spawn, posix_spawn_file_actions) {
235 #if !defined(__GLIBC__)
236 int fds[2];
237 ASSERT_NE(-1, pipe(fds));
238
239 posix_spawn_file_actions_t fa;
240 ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
241
242 // Test addclose and adddup2 by redirecting output to the pipe created above.
243 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
244 ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
245 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
246 // Check that close(2) failures are ignored by closing the same fd again.
247 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
248 // Open a file directly, to test addopen.
249 ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 56, "/proc/version", O_RDONLY, 0));
250 // Test addfchdir by opening the same file a second way...
251 ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 57, "/proc", O_PATH, 0));
252 ASSERT_EQ(0, posix_spawn_file_actions_addfchdir_np(&fa, 57));
253 ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 58, "version", O_RDONLY, 0));
254 // Test addchdir by opening the same file a third way...
255 ASSERT_EQ(0, posix_spawn_file_actions_addchdir_np(&fa, "/"));
256 ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 59, "proc/version", O_RDONLY, 0));
257
258 ExecTestHelper eth;
259 eth.SetArgs({"ls", "-l", "/proc/self/fd", nullptr});
260 pid_t pid;
261 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, nullptr, eth.GetArgs(), eth.GetEnv()));
262 ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));
263
264 ASSERT_EQ(0, close(fds[1]));
265 std::string content;
266 ASSERT_TRUE(android::base::ReadFdToString(fds[0], &content));
267 ASSERT_EQ(0, close(fds[0]));
268
269 AssertChildExited(pid, 0);
270
271 // We'll know the dup2 worked if we see any ls(1) output in our pipe.
272 // The opens we can check manually (and they implicitly check the chdirs)...
273 bool open_to_fd_56_worked = false;
274 bool open_to_fd_58_worked = false;
275 bool open_to_fd_59_worked = false;
276 for (const auto& line : android::base::Split(content, "\n")) {
277 if (line.find(" 56 -> /proc/version") != std::string::npos) open_to_fd_56_worked = true;
278 if (line.find(" 58 -> /proc/version") != std::string::npos) open_to_fd_58_worked = true;
279 if (line.find(" 59 -> /proc/version") != std::string::npos) open_to_fd_59_worked = true;
280 }
281 ASSERT_TRUE(open_to_fd_56_worked) << content;
282 ASSERT_TRUE(open_to_fd_58_worked) << content;
283 ASSERT_TRUE(open_to_fd_59_worked) << content;
284 #else
285 GTEST_SKIP() << "our old glibc doesn't have the chdirs; newer versions and musl do.";
286 #endif
287 }
288
CatFileToString(posix_spawnattr_t * sa,const char * path,std::string * content)289 static void CatFileToString(posix_spawnattr_t* sa, const char* path, std::string* content) {
290 int fds[2];
291 ASSERT_NE(-1, pipe(fds));
292
293 posix_spawn_file_actions_t fa;
294 ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
295 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
296 ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
297 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
298
299 ExecTestHelper eth;
300 eth.SetArgs({"cat", path, nullptr});
301 pid_t pid;
302 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, sa, eth.GetArgs(), nullptr));
303 ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));
304
305 ASSERT_EQ(0, close(fds[1]));
306 ASSERT_TRUE(android::base::ReadFdToString(fds[0], content));
307 ASSERT_EQ(0, close(fds[0]));
308 AssertChildExited(pid, 0);
309 }
310
311 struct ProcStat {
312 pid_t pid;
313 pid_t ppid;
314 pid_t pgrp;
315 pid_t sid;
316 };
317
GetChildStat(posix_spawnattr_t * sa,ProcStat * ps)318 static __attribute__((unused)) void GetChildStat(posix_spawnattr_t* sa, ProcStat* ps) {
319 std::string content;
320 CatFileToString(sa, "/proc/self/stat", &content);
321
322 ASSERT_EQ(4, sscanf(content.c_str(), "%d (cat) %*c %d %d %d", &ps->pid, &ps->ppid, &ps->pgrp,
323 &ps->sid));
324
325 ASSERT_EQ(getpid(), ps->ppid);
326 }
327
328 struct ProcStatus {
329 uint64_t sigblk;
330 uint64_t sigign;
331 };
332
GetChildStatus(posix_spawnattr_t * sa,ProcStatus * ps)333 static void __attribute__((unused)) GetChildStatus(posix_spawnattr_t* sa, ProcStatus* ps) {
334 std::string content;
335 CatFileToString(sa, "/proc/self/status", &content);
336
337 bool saw_blk = false;
338 bool saw_ign = false;
339 for (const auto& line : android::base::Split(content, "\n")) {
340 if (sscanf(line.c_str(), "SigBlk: %" SCNx64, &ps->sigblk) == 1) saw_blk = true;
341 if (sscanf(line.c_str(), "SigIgn: %" SCNx64, &ps->sigign) == 1) saw_ign = true;
342 }
343 ASSERT_TRUE(saw_blk);
344 ASSERT_TRUE(saw_ign);
345 }
346
TEST(spawn,posix_spawn_POSIX_SPAWN_SETSID_clear)347 TEST(spawn, posix_spawn_POSIX_SPAWN_SETSID_clear) {
348 pid_t parent_sid = getsid(0);
349
350 posix_spawnattr_t sa;
351 ASSERT_EQ(0, posix_spawnattr_init(&sa));
352 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, 0));
353
354 ProcStat ps = {};
355 GetChildStat(&sa, &ps);
356 ASSERT_EQ(parent_sid, ps.sid);
357 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
358 }
359
TEST(spawn,posix_spawn_POSIX_SPAWN_SETSID_set)360 TEST(spawn, posix_spawn_POSIX_SPAWN_SETSID_set) {
361 pid_t parent_sid = getsid(0);
362
363 posix_spawnattr_t sa;
364 ASSERT_EQ(0, posix_spawnattr_init(&sa));
365 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSID));
366
367 ProcStat ps = {};
368 GetChildStat(&sa, &ps);
369 ASSERT_NE(parent_sid, ps.sid);
370 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
371 }
372
TEST(spawn,posix_spawn_POSIX_SPAWN_SETPGROUP_clear)373 TEST(spawn, posix_spawn_POSIX_SPAWN_SETPGROUP_clear) {
374 pid_t parent_pgrp = getpgrp();
375
376 posix_spawnattr_t sa;
377 ASSERT_EQ(0, posix_spawnattr_init(&sa));
378 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, 0));
379
380 ProcStat ps = {};
381 GetChildStat(&sa, &ps);
382 ASSERT_EQ(parent_pgrp, ps.pgrp);
383 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
384 }
385
TEST(spawn,posix_spawn_POSIX_SPAWN_SETPGROUP_set)386 TEST(spawn, posix_spawn_POSIX_SPAWN_SETPGROUP_set) {
387 pid_t parent_pgrp = getpgrp();
388
389 posix_spawnattr_t sa;
390 ASSERT_EQ(0, posix_spawnattr_init(&sa));
391 ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 0));
392 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETPGROUP));
393
394 ProcStat ps = {};
395 GetChildStat(&sa, &ps);
396 ASSERT_NE(parent_pgrp, ps.pgrp);
397 // Setting pgid 0 means "the same as the caller's pid".
398 ASSERT_EQ(ps.pid, ps.pgrp);
399 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
400 }
401
TEST(spawn,posix_spawn_POSIX_SPAWN_SETSIGMASK)402 TEST(spawn, posix_spawn_POSIX_SPAWN_SETSIGMASK) {
403 #if defined(__GLIBC__) || defined(ANDROID_HOST_MUSL)
404 GTEST_SKIP() << "glibc doesn't ignore the same signals.";
405 #else
406 // Block SIGBUS in the parent...
407 sigset_t just_SIGBUS;
408 sigemptyset(&just_SIGBUS);
409 sigaddset(&just_SIGBUS, SIGBUS);
410 ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGBUS, nullptr));
411
412 posix_spawnattr_t sa;
413 ASSERT_EQ(0, posix_spawnattr_init(&sa));
414
415 // Ask for only SIGALRM to be blocked in the child...
416 sigset_t just_SIGALRM;
417 sigemptyset(&just_SIGALRM);
418 sigaddset(&just_SIGALRM, SIGALRM);
419 ASSERT_EQ(0, posix_spawnattr_setsigmask(&sa, &just_SIGALRM));
420 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSIGMASK));
421
422 // Check that's what happens...
423 ProcStatus ps = {};
424 GetChildStatus(&sa, &ps);
425
426 // TIMER_SIGNAL should also be blocked.
427 uint64_t expected_blocked = 0;
428 SignalSetAdd(&expected_blocked, SIGALRM);
429 SignalSetAdd(&expected_blocked, BIONIC_SIGNAL_POSIX_TIMERS);
430 EXPECT_EQ(expected_blocked, ps.sigblk);
431
432 uint64_t expected_ignored = 0;
433 SignalSetAdd(&expected_ignored, BIONIC_SIGNAL_ART_PROFILER);
434 EXPECT_EQ(expected_ignored, ps.sigign);
435
436 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
437 #endif
438 }
439
TEST(spawn,posix_spawn_POSIX_SPAWN_SETSIGDEF)440 TEST(spawn, posix_spawn_POSIX_SPAWN_SETSIGDEF) {
441 #if defined(__GLIBC__) || defined(ANDROID_HOST_MUSL)
442 GTEST_SKIP() << "glibc doesn't ignore the same signals.";
443 #else
444 // Ignore SIGALRM and SIGCONT in the parent...
445 ASSERT_NE(SIG_ERR, signal(SIGALRM, SIG_IGN));
446 ASSERT_NE(SIG_ERR, signal(SIGCONT, SIG_IGN));
447
448 posix_spawnattr_t sa;
449 ASSERT_EQ(0, posix_spawnattr_init(&sa));
450
451 // Ask for SIGALRM to be defaulted in the child...
452 sigset_t just_SIGALRM;
453 sigemptyset(&just_SIGALRM);
454 sigaddset(&just_SIGALRM, SIGALRM);
455
456 ASSERT_EQ(0, posix_spawnattr_setsigdefault(&sa, &just_SIGALRM));
457 ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSIGDEF));
458
459 // Check that's what happens...
460 ProcStatus ps = {};
461 GetChildStatus(&sa, &ps);
462
463 // TIMER_SIGNAL should be blocked.
464 uint64_t expected_blocked = 0;
465 SignalSetAdd(&expected_blocked, BIONIC_SIGNAL_POSIX_TIMERS);
466 EXPECT_EQ(expected_blocked, ps.sigblk);
467
468 uint64_t expected_ignored = 0;
469 SignalSetAdd(&expected_ignored, SIGCONT);
470 SignalSetAdd(&expected_ignored, BIONIC_SIGNAL_ART_PROFILER);
471 EXPECT_EQ(expected_ignored, ps.sigign);
472
473 ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
474 #endif
475 }
476
TEST(spawn,signal_stress)477 TEST(spawn, signal_stress) {
478 // Ensure that posix_spawn doesn't restore the caller's signal mask in the
479 // child without first defaulting any caught signals (http://b/68707996).
480 static pid_t parent = getpid();
481
482 setpgid(0, 0);
483 signal(SIGRTMIN, SIG_IGN);
484
485 pid_t pid = fork();
486 ASSERT_NE(-1, pid);
487
488 if (pid == 0) {
489 for (size_t i = 0; i < 1024; ++i) {
490 kill(0, SIGRTMIN);
491 usleep(10);
492 }
493 _exit(99);
494 }
495
496 // We test both with and without attributes, because they used to be
497 // different codepaths. We also test with an empty `sigdefault` set.
498 posix_spawnattr_t attr1;
499 posix_spawnattr_init(&attr1);
500
501 sigset_t empty_mask = {};
502 posix_spawnattr_t attr2;
503 posix_spawnattr_init(&attr2);
504 posix_spawnattr_setflags(&attr2, POSIX_SPAWN_SETSIGDEF);
505 posix_spawnattr_setsigdefault(&attr2, &empty_mask);
506
507 posix_spawnattr_t* attrs[] = { nullptr, &attr1, &attr2 };
508
509 // We use a real-time signal because that's a tricky case for LP32
510 // because our sigset_t was too small.
511 ScopedSignalHandler ssh(SIGRTMIN, [](int) { ASSERT_EQ(getpid(), parent); });
512
513 const size_t pid_count = 128;
514 pid_t spawned_pids[pid_count];
515
516 ExecTestHelper eth;
517 eth.SetArgs({"true", nullptr});
518 for (size_t i = 0; i < pid_count; ++i) {
519 pid_t spawned_pid;
520 ASSERT_EQ(0, posix_spawn(&spawned_pid, "true", nullptr, attrs[i % 3], eth.GetArgs(), nullptr));
521 spawned_pids[i] = spawned_pid;
522 }
523
524 for (pid_t spawned_pid : spawned_pids) {
525 ASSERT_EQ(spawned_pid, TEMP_FAILURE_RETRY(waitpid(spawned_pid, nullptr, 0)));
526 }
527
528 AssertChildExited(pid, 99);
529 }
530
TEST(spawn,posix_spawn_dup2_CLOEXEC)531 TEST(spawn, posix_spawn_dup2_CLOEXEC) {
532 int fds[2];
533 ASSERT_NE(-1, pipe(fds));
534
535 posix_spawn_file_actions_t fa;
536 ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
537
538 int fd = open("/proc/version", O_RDONLY | O_CLOEXEC);
539 ASSERT_NE(-1, fd);
540
541 ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
542 ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
543 // dup2() is a no-op when the two fds are the same, so this won't clear
544 // O_CLOEXEC unless we're doing extra work to make that happen.
545 ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fd, fd));
546
547 // Read /proc/self/fd/<fd> in the child...
548 std::string fdinfo_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
549 ExecTestHelper eth;
550 eth.SetArgs({"cat", fdinfo_path.c_str(), nullptr});
551 pid_t pid;
552 ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, nullptr, eth.GetArgs(), eth.GetEnv()));
553 ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));
554 ASSERT_EQ(0, close(fds[1]));
555 std::string content;
556 ASSERT_TRUE(android::base::ReadFdToString(fds[0], &content));
557 ASSERT_EQ(0, close(fds[0]));
558
559 // ...and compare that to the parent. This is overkill really, since the very
560 // fact that the child had a valid file descriptor strongly implies that we
561 // removed O_CLOEXEC, but we may as well check that the child ended up with
562 // the *right* file descriptor :-)
563 std::string expected;
564 ASSERT_TRUE(android::base::ReadFdToString(fd, &expected));
565 ASSERT_EQ(expected, content);
566
567 AssertChildExited(pid, 0);
568 }
569