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