1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #define _CRT_SECURE_NO_WARNINGS
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <limits>
11
12 #include "base/command_line.h"
13 #include "base/debug/alias.h"
14 #include "base/debug/stack_trace.h"
15 #include "base/files/file_enumerator.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/files/scoped_file.h"
19 #include "base/logging.h"
20 #include "base/macros.h"
21 #include "base/path_service.h"
22 #include "base/posix/eintr_wrapper.h"
23 #include "base/process/kill.h"
24 #include "base/process/launch.h"
25 #include "base/process/memory.h"
26 #include "base/process/process.h"
27 #include "base/process/process_metrics.h"
28 #include "base/strings/string_number_conversions.h"
29 #include "base/strings/utf_string_conversions.h"
30 #include "base/synchronization/waitable_event.h"
31 #include "base/test/multiprocess_test.h"
32 #include "base/test/scoped_task_environment.h"
33 #include "base/test/test_timeouts.h"
34 #include "base/threading/platform_thread.h"
35 #include "base/threading/thread.h"
36 #include "build/build_config.h"
37 #include "testing/gtest/include/gtest/gtest.h"
38 #include "testing/multiprocess_func_list.h"
39
40 #if defined(OS_LINUX)
41 #include <malloc.h>
42 #include <sched.h>
43 #include <sys/syscall.h>
44 #endif
45 #if defined(OS_POSIX)
46 #include <sys/resource.h>
47 #endif
48 #if defined(OS_POSIX)
49 #include <dlfcn.h>
50 #include <errno.h>
51 #include <sched.h>
52 #include <signal.h>
53 #include <sys/wait.h>
54 #include <unistd.h>
55 #endif
56 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
57 #include <fcntl.h>
58 #include <sys/socket.h>
59 #include <sys/types.h>
60 #endif
61 #if defined(OS_WIN)
62 #include <windows.h>
63 #endif
64 #if defined(OS_MACOSX)
65 #include <mach/vm_param.h>
66 #include <malloc/malloc.h>
67 #endif
68 #if defined(OS_ANDROID)
69 #include "third_party/lss/linux_syscall_support.h"
70 #endif
71 #if defined(OS_FUCHSIA)
72 #include <lib/fdio/limits.h>
73 #include <zircon/process.h>
74 #include <zircon/processargs.h>
75 #include <zircon/syscalls.h>
76 #include "base/base_paths_fuchsia.h"
77 #include "base/files/scoped_temp_dir.h"
78 #include "base/fuchsia/file_utils.h"
79 #include "base/fuchsia/fuchsia_logging.h"
80 #endif
81
82 namespace base {
83
84 namespace {
85
86 const char kSignalFileSlow[] = "SlowChildProcess.die";
87 const char kSignalFileKill[] = "KilledChildProcess.die";
88 const char kTestHelper[] = "test_child_process";
89
90 #if defined(OS_POSIX)
91 const char kSignalFileTerm[] = "TerminatedChildProcess.die";
92 #endif
93
94 #if defined(OS_FUCHSIA)
95 const char kSignalFileClone[] = "ClonedTmpDir.die";
96 const char kDataDirHasStaged[] = "DataDirHasStaged.die";
97 const char kFooDirHasStaged[] = "FooDirHasStaged.die";
98 const char kFooDirDoesNotHaveStaged[] = "FooDirDoesNotHaveStaged.die";
99 #endif
100
101 #if defined(OS_WIN)
102 const int kExpectedStillRunningExitCode = 0x102;
103 const int kExpectedKilledExitCode = 1;
104 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
105 const int kExpectedStillRunningExitCode = 0;
106 #endif
107
108 // Sleeps until file filename is created.
WaitToDie(const char * filename)109 void WaitToDie(const char* filename) {
110 FILE* fp;
111 do {
112 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
113 fp = fopen(filename, "r");
114 } while (!fp);
115 fclose(fp);
116 }
117
118 // Signals children they should die now.
SignalChildren(const char * filename)119 void SignalChildren(const char* filename) {
120 FILE* fp = fopen(filename, "w");
121 fclose(fp);
122 }
123
124 // Using a pipe to the child to wait for an event was considered, but
125 // there were cases in the past where pipes caused problems (other
126 // libraries closing the fds, child deadlocking). This is a simple
127 // case, so it's not worth the risk. Using wait loops is discouraged
128 // in most instances.
WaitForChildTermination(ProcessHandle handle,int * exit_code)129 TerminationStatus WaitForChildTermination(ProcessHandle handle,
130 int* exit_code) {
131 // Now we wait until the result is something other than STILL_RUNNING.
132 TerminationStatus status = TERMINATION_STATUS_STILL_RUNNING;
133 const TimeDelta kInterval = TimeDelta::FromMilliseconds(20);
134 TimeDelta waited;
135 do {
136 status = GetTerminationStatus(handle, exit_code);
137 PlatformThread::Sleep(kInterval);
138 waited += kInterval;
139 } while (status == TERMINATION_STATUS_STILL_RUNNING &&
140 waited < TestTimeouts::action_max_timeout());
141
142 return status;
143 }
144
145 } // namespace
146
147 const int kSuccess = 0;
148
149 class ProcessUtilTest : public MultiProcessTest {
150 public:
SetUp()151 void SetUp() override {
152 ASSERT_TRUE(PathService::Get(DIR_ASSETS, &test_helper_path_));
153 test_helper_path_ = test_helper_path_.AppendASCII(kTestHelper);
154 }
155
156 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
157 // Spawn a child process that counts how many file descriptors are open.
158 int CountOpenFDsInChild();
159 #endif
160 // Converts the filename to a platform specific filepath.
161 // On Android files can not be created in arbitrary directories.
162 static std::string GetSignalFilePath(const char* filename);
163
164 protected:
165 base::FilePath test_helper_path_;
166 };
167
GetSignalFilePath(const char * filename)168 std::string ProcessUtilTest::GetSignalFilePath(const char* filename) {
169 #if defined(OS_ANDROID) || defined(OS_FUCHSIA)
170 FilePath tmp_dir;
171 PathService::Get(DIR_TEMP, &tmp_dir);
172 tmp_dir = tmp_dir.Append(filename);
173 return tmp_dir.value();
174 #else
175 return filename;
176 #endif
177 }
178
MULTIPROCESS_TEST_MAIN(SimpleChildProcess)179 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
180 return kSuccess;
181 }
182
183 // TODO(viettrungluu): This should be in a "MultiProcessTestTest".
TEST_F(ProcessUtilTest,SpawnChild)184 TEST_F(ProcessUtilTest, SpawnChild) {
185 Process process = SpawnChild("SimpleChildProcess");
186 ASSERT_TRUE(process.IsValid());
187 int exit_code;
188 EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
189 &exit_code));
190 }
191
MULTIPROCESS_TEST_MAIN(SlowChildProcess)192 MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
193 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileSlow).c_str());
194 return kSuccess;
195 }
196
TEST_F(ProcessUtilTest,KillSlowChild)197 TEST_F(ProcessUtilTest, KillSlowChild) {
198 const std::string signal_file =
199 ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
200 remove(signal_file.c_str());
201 Process process = SpawnChild("SlowChildProcess");
202 ASSERT_TRUE(process.IsValid());
203 SignalChildren(signal_file.c_str());
204 int exit_code;
205 EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
206 &exit_code));
207 remove(signal_file.c_str());
208 }
209
210 // Times out on Linux and Win, flakes on other platforms, http://crbug.com/95058
TEST_F(ProcessUtilTest,DISABLED_GetTerminationStatusExit)211 TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) {
212 const std::string signal_file =
213 ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
214 remove(signal_file.c_str());
215 Process process = SpawnChild("SlowChildProcess");
216 ASSERT_TRUE(process.IsValid());
217
218 int exit_code = 42;
219 EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
220 GetTerminationStatus(process.Handle(), &exit_code));
221 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
222
223 SignalChildren(signal_file.c_str());
224 exit_code = 42;
225 TerminationStatus status =
226 WaitForChildTermination(process.Handle(), &exit_code);
227 EXPECT_EQ(TERMINATION_STATUS_NORMAL_TERMINATION, status);
228 EXPECT_EQ(kSuccess, exit_code);
229 remove(signal_file.c_str());
230 }
231
232 #if defined(OS_FUCHSIA)
233
MULTIPROCESS_TEST_MAIN(CheckDataDirHasStaged)234 MULTIPROCESS_TEST_MAIN(CheckDataDirHasStaged) {
235 if (!PathExists(base::FilePath("/data/staged"))) {
236 return 1;
237 }
238 WaitToDie(ProcessUtilTest::GetSignalFilePath(kDataDirHasStaged).c_str());
239 return kSuccess;
240 }
241
242 // Test transferred paths override cloned paths.
TEST_F(ProcessUtilTest,HandleTransfersOverrideClones)243 TEST_F(ProcessUtilTest, HandleTransfersOverrideClones) {
244 const std::string signal_file =
245 ProcessUtilTest::GetSignalFilePath(kDataDirHasStaged);
246 remove(signal_file.c_str());
247
248 // Create a tempdir with "staged" as its contents.
249 ScopedTempDir tmpdir_with_staged;
250 ASSERT_TRUE(tmpdir_with_staged.CreateUniqueTempDir());
251 {
252 base::FilePath staged_file_path =
253 tmpdir_with_staged.GetPath().Append("staged");
254 base::File staged_file(staged_file_path,
255 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
256 ASSERT_TRUE(staged_file.created());
257 staged_file.Close();
258 }
259
260 base::LaunchOptions options;
261 options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
262
263 // Attach the tempdir to "data", but also try to duplicate the existing "data"
264 // directory.
265 options.paths_to_clone.push_back(base::FilePath("/data"));
266 options.paths_to_clone.push_back(base::FilePath("/tmp"));
267 options.paths_to_transfer.push_back(
268 {FilePath("/data"),
269 fuchsia::GetHandleFromFile(
270 base::File(base::FilePath(tmpdir_with_staged.GetPath()),
271 base::File::FLAG_OPEN | base::File::FLAG_READ))
272 .release()});
273
274 // Verify from that "/data/staged" exists from the child process' perspective.
275 Process process(SpawnChildWithOptions("CheckDataDirHasStaged", options));
276 ASSERT_TRUE(process.IsValid());
277 SignalChildren(signal_file.c_str());
278
279 int exit_code = 42;
280 EXPECT_TRUE(process.WaitForExit(&exit_code));
281 EXPECT_EQ(kSuccess, exit_code);
282 }
283
MULTIPROCESS_TEST_MAIN(CheckMountedDir)284 MULTIPROCESS_TEST_MAIN(CheckMountedDir) {
285 if (!PathExists(base::FilePath("/foo/staged"))) {
286 return 1;
287 }
288 WaitToDie(ProcessUtilTest::GetSignalFilePath(kFooDirHasStaged).c_str());
289 return kSuccess;
290 }
291
292 // Test that we can install an opaque handle in the child process' namespace.
TEST_F(ProcessUtilTest,TransferHandleToPath)293 TEST_F(ProcessUtilTest, TransferHandleToPath) {
294 const std::string signal_file =
295 ProcessUtilTest::GetSignalFilePath(kFooDirHasStaged);
296 remove(signal_file.c_str());
297
298 // Create a tempdir with "staged" as its contents.
299 ScopedTempDir new_tmpdir;
300 ASSERT_TRUE(new_tmpdir.CreateUniqueTempDir());
301 base::FilePath staged_file_path = new_tmpdir.GetPath().Append("staged");
302 base::File staged_file(staged_file_path,
303 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
304 ASSERT_TRUE(staged_file.created());
305 staged_file.Close();
306
307 // Mount the tempdir to "/foo".
308 zx::handle tmp_handle = fuchsia::GetHandleFromFile(
309 base::File(base::FilePath(new_tmpdir.GetPath()),
310 base::File::FLAG_OPEN | base::File::FLAG_READ));
311 ASSERT_TRUE(tmp_handle.is_valid());
312 LaunchOptions options;
313 options.paths_to_clone.push_back(base::FilePath("/tmp"));
314 options.paths_to_transfer.push_back(
315 {base::FilePath("/foo"), tmp_handle.release()});
316 options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
317
318 // Verify from that "/foo/staged" exists from the child process' perspective.
319 Process process(SpawnChildWithOptions("CheckMountedDir", options));
320 ASSERT_TRUE(process.IsValid());
321 SignalChildren(signal_file.c_str());
322
323 int exit_code = 42;
324 EXPECT_TRUE(process.WaitForExit(&exit_code));
325 EXPECT_EQ(kSuccess, exit_code);
326 }
327
MULTIPROCESS_TEST_MAIN(CheckTmpFileExists)328 MULTIPROCESS_TEST_MAIN(CheckTmpFileExists) {
329 // Look through the filesystem to ensure that no other directories
330 // besides "tmp" are in the namespace.
331 base::FileEnumerator enumerator(
332 base::FilePath("/"), false,
333 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
334 base::FilePath next_path;
335 while (!(next_path = enumerator.Next()).empty()) {
336 if (next_path != base::FilePath("/tmp")) {
337 LOG(ERROR) << "Clone policy violation: found non-tmp directory "
338 << next_path.MaybeAsASCII();
339 return 1;
340 }
341 }
342 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileClone).c_str());
343 return kSuccess;
344 }
345
TEST_F(ProcessUtilTest,CloneTmp)346 TEST_F(ProcessUtilTest, CloneTmp) {
347 const std::string signal_file =
348 ProcessUtilTest::GetSignalFilePath(kSignalFileClone);
349 remove(signal_file.c_str());
350
351 LaunchOptions options;
352 options.paths_to_clone.push_back(base::FilePath("/tmp"));
353 options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
354
355 Process process(SpawnChildWithOptions("CheckTmpFileExists", options));
356 ASSERT_TRUE(process.IsValid());
357
358 SignalChildren(signal_file.c_str());
359
360 int exit_code = 42;
361 EXPECT_TRUE(process.WaitForExit(&exit_code));
362 EXPECT_EQ(kSuccess, exit_code);
363 }
364
MULTIPROCESS_TEST_MAIN(CheckMountedDirDoesNotExist)365 MULTIPROCESS_TEST_MAIN(CheckMountedDirDoesNotExist) {
366 if (PathExists(base::FilePath("/foo"))) {
367 return 1;
368 }
369 WaitToDie(
370 ProcessUtilTest::GetSignalFilePath(kFooDirDoesNotHaveStaged).c_str());
371 return kSuccess;
372 }
373
TEST_F(ProcessUtilTest,TransferInvalidHandleFails)374 TEST_F(ProcessUtilTest, TransferInvalidHandleFails) {
375 LaunchOptions options;
376 options.paths_to_clone.push_back(base::FilePath("/tmp"));
377 options.paths_to_transfer.push_back(
378 {base::FilePath("/foo"), ZX_HANDLE_INVALID});
379 options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
380
381 // Verify that the process is never constructed.
382 const std::string signal_file =
383 ProcessUtilTest::GetSignalFilePath(kFooDirDoesNotHaveStaged);
384 remove(signal_file.c_str());
385 Process process(
386 SpawnChildWithOptions("CheckMountedDirDoesNotExist", options));
387 ASSERT_FALSE(process.IsValid());
388 }
389
TEST_F(ProcessUtilTest,CloneInvalidDirFails)390 TEST_F(ProcessUtilTest, CloneInvalidDirFails) {
391 const std::string signal_file =
392 ProcessUtilTest::GetSignalFilePath(kSignalFileClone);
393 remove(signal_file.c_str());
394
395 LaunchOptions options;
396 options.paths_to_clone.push_back(base::FilePath("/tmp"));
397 options.paths_to_clone.push_back(base::FilePath("/definitely_not_a_dir"));
398 options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
399
400 Process process(SpawnChildWithOptions("CheckTmpFileExists", options));
401 ASSERT_FALSE(process.IsValid());
402 }
403
404 // Test that we can clone other directories. CheckTmpFileExists will return an
405 // error code if it detects a directory other than "/tmp", so we can use that as
406 // a signal that it successfully detected another entry in the root namespace.
TEST_F(ProcessUtilTest,CloneAlternateDir)407 TEST_F(ProcessUtilTest, CloneAlternateDir) {
408 const std::string signal_file =
409 ProcessUtilTest::GetSignalFilePath(kSignalFileClone);
410 remove(signal_file.c_str());
411
412 LaunchOptions options;
413 options.paths_to_clone.push_back(base::FilePath("/tmp"));
414 options.paths_to_clone.push_back(base::FilePath("/data"));
415 options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
416
417 Process process(SpawnChildWithOptions("CheckTmpFileExists", options));
418 ASSERT_TRUE(process.IsValid());
419
420 SignalChildren(signal_file.c_str());
421
422 int exit_code = 42;
423 EXPECT_TRUE(process.WaitForExit(&exit_code));
424 EXPECT_EQ(1, exit_code);
425 }
426
TEST_F(ProcessUtilTest,HandlesToTransferClosedOnSpawnFailure)427 TEST_F(ProcessUtilTest, HandlesToTransferClosedOnSpawnFailure) {
428 zx::handle handles[2];
429 zx_status_t result = zx_channel_create(0, handles[0].reset_and_get_address(),
430 handles[1].reset_and_get_address());
431 ZX_CHECK(ZX_OK == result, result) << "zx_channel_create";
432
433 LaunchOptions options;
434 options.handles_to_transfer.push_back({0, handles[0].get()});
435
436 // Launch a non-existent binary, causing fdio_spawn() to fail.
437 CommandLine command_line(FilePath(
438 FILE_PATH_LITERAL("magical_filename_that_will_never_exist_ever")));
439 Process process(LaunchProcess(command_line, options));
440 ASSERT_FALSE(process.IsValid());
441
442 // If LaunchProcess did its job then handles[0] is no longer valid, and
443 // handles[1] should observe a channel-closed signal.
444 EXPECT_EQ(
445 zx_object_wait_one(handles[1].get(), ZX_CHANNEL_PEER_CLOSED, 0, nullptr),
446 ZX_OK);
447 EXPECT_EQ(ZX_ERR_BAD_HANDLE, zx_handle_close(handles[0].get()));
448 ignore_result(handles[0].release());
449 }
450
TEST_F(ProcessUtilTest,HandlesToTransferClosedOnBadPathToMapFailure)451 TEST_F(ProcessUtilTest, HandlesToTransferClosedOnBadPathToMapFailure) {
452 zx::handle handles[2];
453 zx_status_t result = zx_channel_create(0, handles[0].reset_and_get_address(),
454 handles[1].reset_and_get_address());
455 ZX_CHECK(ZX_OK == result, result) << "zx_channel_create";
456
457 LaunchOptions options;
458 options.handles_to_transfer.push_back({0, handles[0].get()});
459 options.spawn_flags = options.spawn_flags & ~FDIO_SPAWN_CLONE_NAMESPACE;
460 options.paths_to_clone.emplace_back(
461 "magical_path_that_will_never_exist_ever");
462
463 // LaunchProces should fail to open() the path_to_map, and fail before
464 // fdio_spawn().
465 Process process(LaunchProcess(CommandLine(FilePath()), options));
466 ASSERT_FALSE(process.IsValid());
467
468 // If LaunchProcess did its job then handles[0] is no longer valid, and
469 // handles[1] should observe a channel-closed signal.
470 EXPECT_EQ(
471 zx_object_wait_one(handles[1].get(), ZX_CHANNEL_PEER_CLOSED, 0, nullptr),
472 ZX_OK);
473 EXPECT_EQ(ZX_ERR_BAD_HANDLE, zx_handle_close(handles[0].get()));
474 ignore_result(handles[0].release());
475 }
476 #endif // defined(OS_FUCHSIA)
477
478 // On Android SpawnProcess() doesn't use LaunchProcess() and doesn't support
479 // LaunchOptions::current_directory.
480 #if !defined(OS_ANDROID)
MULTIPROCESS_TEST_MAIN(CheckCwdProcess)481 MULTIPROCESS_TEST_MAIN(CheckCwdProcess) {
482 FilePath expected;
483 CHECK(GetTempDir(&expected));
484 expected = MakeAbsoluteFilePath(expected);
485 CHECK(!expected.empty());
486
487 FilePath actual;
488 CHECK(GetCurrentDirectory(&actual));
489 actual = MakeAbsoluteFilePath(actual);
490 CHECK(!actual.empty());
491
492 CHECK(expected == actual) << "Expected: " << expected.value()
493 << " Actual: " << actual.value();
494 return kSuccess;
495 }
496
TEST_F(ProcessUtilTest,CurrentDirectory)497 TEST_F(ProcessUtilTest, CurrentDirectory) {
498 // TODO(rickyz): Add support for passing arguments to multiprocess children,
499 // then create a special directory for this test.
500 FilePath tmp_dir;
501 ASSERT_TRUE(GetTempDir(&tmp_dir));
502
503 LaunchOptions options;
504 options.current_directory = tmp_dir;
505
506 Process process(SpawnChildWithOptions("CheckCwdProcess", options));
507 ASSERT_TRUE(process.IsValid());
508
509 int exit_code = 42;
510 EXPECT_TRUE(process.WaitForExit(&exit_code));
511 EXPECT_EQ(kSuccess, exit_code);
512 }
513 #endif // !defined(OS_ANDROID)
514
515 #if defined(OS_WIN)
516 // TODO(cpu): figure out how to test this in other platforms.
TEST_F(ProcessUtilTest,GetProcId)517 TEST_F(ProcessUtilTest, GetProcId) {
518 ProcessId id1 = GetProcId(GetCurrentProcess());
519 EXPECT_NE(0ul, id1);
520 Process process = SpawnChild("SimpleChildProcess");
521 ASSERT_TRUE(process.IsValid());
522 ProcessId id2 = process.Pid();
523 EXPECT_NE(0ul, id2);
524 EXPECT_NE(id1, id2);
525 }
526 #endif // defined(OS_WIN)
527
528 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
529 // This test is disabled on Mac, since it's flaky due to ReportCrash
530 // taking a variable amount of time to parse and load the debug and
531 // symbol data for this unit test's executable before firing the
532 // signal handler.
533 //
534 // TODO(gspencer): turn this test process into a very small program
535 // with no symbols (instead of using the multiprocess testing
536 // framework) to reduce the ReportCrash overhead.
537 //
538 // It is disabled on Android as MultiprocessTests are started as services that
539 // the framework restarts on crashes.
540 const char kSignalFileCrash[] = "CrashingChildProcess.die";
541
MULTIPROCESS_TEST_MAIN(CrashingChildProcess)542 MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
543 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str());
544 #if defined(OS_POSIX)
545 // Have to disable to signal handler for segv so we can get a crash
546 // instead of an abnormal termination through the crash dump handler.
547 ::signal(SIGSEGV, SIG_DFL);
548 #endif
549 // Make this process have a segmentation fault.
550 volatile int* oops = nullptr;
551 *oops = 0xDEAD;
552 return 1;
553 }
554
555 // This test intentionally crashes, so we don't need to run it under
556 // AddressSanitizer.
557 #if defined(ADDRESS_SANITIZER) || defined(OS_FUCHSIA)
558 // TODO(crbug.com/753490): Access to the process termination reason is not
559 // implemented in Fuchsia.
560 #define MAYBE_GetTerminationStatusCrash DISABLED_GetTerminationStatusCrash
561 #else
562 #define MAYBE_GetTerminationStatusCrash GetTerminationStatusCrash
563 #endif
TEST_F(ProcessUtilTest,MAYBE_GetTerminationStatusCrash)564 TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
565 const std::string signal_file =
566 ProcessUtilTest::GetSignalFilePath(kSignalFileCrash);
567 remove(signal_file.c_str());
568 Process process = SpawnChild("CrashingChildProcess");
569 ASSERT_TRUE(process.IsValid());
570
571 int exit_code = 42;
572 EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
573 GetTerminationStatus(process.Handle(), &exit_code));
574 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
575
576 SignalChildren(signal_file.c_str());
577 exit_code = 42;
578 TerminationStatus status =
579 WaitForChildTermination(process.Handle(), &exit_code);
580 EXPECT_EQ(TERMINATION_STATUS_PROCESS_CRASHED, status);
581
582 #if defined(OS_WIN)
583 EXPECT_EQ(static_cast<int>(0xc0000005), exit_code);
584 #elif defined(OS_POSIX)
585 int signaled = WIFSIGNALED(exit_code);
586 EXPECT_NE(0, signaled);
587 int signal = WTERMSIG(exit_code);
588 EXPECT_EQ(SIGSEGV, signal);
589 #endif
590
591 // Reset signal handlers back to "normal".
592 debug::EnableInProcessStackDumping();
593 remove(signal_file.c_str());
594 }
595 #endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
596
MULTIPROCESS_TEST_MAIN(KilledChildProcess)597 MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
598 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str());
599 #if defined(OS_WIN)
600 // Kill ourselves.
601 HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
602 ::TerminateProcess(handle, kExpectedKilledExitCode);
603 #elif defined(OS_POSIX)
604 // Send a SIGKILL to this process, just like the OOM killer would.
605 ::kill(getpid(), SIGKILL);
606 #elif defined(OS_FUCHSIA)
607 zx_task_kill(zx_process_self());
608 #endif
609 return 1;
610 }
611
612 #if defined(OS_POSIX)
MULTIPROCESS_TEST_MAIN(TerminatedChildProcess)613 MULTIPROCESS_TEST_MAIN(TerminatedChildProcess) {
614 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileTerm).c_str());
615 // Send a SIGTERM to this process.
616 ::kill(getpid(), SIGTERM);
617 return 1;
618 }
619 #endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
620
621 #if defined(OS_FUCHSIA)
622 // TODO(crbug.com/753490): Access to the process termination reason is not
623 // implemented in Fuchsia.
624 #define MAYBE_GetTerminationStatusSigKill DISABLED_GetTerminationStatusSigKill
625 #else
626 #define MAYBE_GetTerminationStatusSigKill GetTerminationStatusSigKill
627 #endif
TEST_F(ProcessUtilTest,MAYBE_GetTerminationStatusSigKill)628 TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusSigKill) {
629 const std::string signal_file =
630 ProcessUtilTest::GetSignalFilePath(kSignalFileKill);
631 remove(signal_file.c_str());
632 Process process = SpawnChild("KilledChildProcess");
633 ASSERT_TRUE(process.IsValid());
634
635 int exit_code = 42;
636 EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
637 GetTerminationStatus(process.Handle(), &exit_code));
638 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
639
640 SignalChildren(signal_file.c_str());
641 exit_code = 42;
642 TerminationStatus status =
643 WaitForChildTermination(process.Handle(), &exit_code);
644 #if defined(OS_CHROMEOS)
645 EXPECT_EQ(TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status);
646 #else
647 EXPECT_EQ(TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
648 #endif
649
650 #if defined(OS_WIN)
651 EXPECT_EQ(kExpectedKilledExitCode, exit_code);
652 #elif defined(OS_POSIX)
653 int signaled = WIFSIGNALED(exit_code);
654 EXPECT_NE(0, signaled);
655 int signal = WTERMSIG(exit_code);
656 EXPECT_EQ(SIGKILL, signal);
657 #endif
658 remove(signal_file.c_str());
659 }
660
661 #if defined(OS_POSIX)
662 // TODO(crbug.com/753490): Access to the process termination reason is not
663 // implemented in Fuchsia. Unix signals are not implemented in Fuchsia so this
664 // test might not be relevant anyway.
TEST_F(ProcessUtilTest,GetTerminationStatusSigTerm)665 TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) {
666 const std::string signal_file =
667 ProcessUtilTest::GetSignalFilePath(kSignalFileTerm);
668 remove(signal_file.c_str());
669 Process process = SpawnChild("TerminatedChildProcess");
670 ASSERT_TRUE(process.IsValid());
671
672 int exit_code = 42;
673 EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
674 GetTerminationStatus(process.Handle(), &exit_code));
675 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
676
677 SignalChildren(signal_file.c_str());
678 exit_code = 42;
679 TerminationStatus status =
680 WaitForChildTermination(process.Handle(), &exit_code);
681 EXPECT_EQ(TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
682
683 int signaled = WIFSIGNALED(exit_code);
684 EXPECT_NE(0, signaled);
685 int signal = WTERMSIG(exit_code);
686 EXPECT_EQ(SIGTERM, signal);
687 remove(signal_file.c_str());
688 }
689 #endif // defined(OS_POSIX)
690
TEST_F(ProcessUtilTest,EnsureTerminationUndying)691 TEST_F(ProcessUtilTest, EnsureTerminationUndying) {
692 test::ScopedTaskEnvironment task_environment;
693
694 Process child_process = SpawnChild("process_util_test_never_die");
695 ASSERT_TRUE(child_process.IsValid());
696
697 EnsureProcessTerminated(child_process.Duplicate());
698
699 #if defined(OS_POSIX)
700 errno = 0;
701 #endif // defined(OS_POSIX)
702
703 // Allow a generous timeout, to cope with slow/loaded test bots.
704 bool did_exit = child_process.WaitForExitWithTimeout(
705 TestTimeouts::action_max_timeout(), nullptr);
706
707 #if defined(OS_POSIX)
708 // Both EnsureProcessTerminated() and WaitForExitWithTimeout() will call
709 // waitpid(). One will succeed, and the other will fail with ECHILD. If our
710 // wait failed then check for ECHILD, and assumed |did_exit| in that case.
711 did_exit = did_exit || (errno == ECHILD);
712 #endif // defined(OS_POSIX)
713
714 EXPECT_TRUE(did_exit);
715 }
716
MULTIPROCESS_TEST_MAIN(process_util_test_never_die)717 MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
718 while (1) {
719 PlatformThread::Sleep(TimeDelta::FromSeconds(500));
720 }
721 return kSuccess;
722 }
723
TEST_F(ProcessUtilTest,EnsureTerminationGracefulExit)724 TEST_F(ProcessUtilTest, EnsureTerminationGracefulExit) {
725 test::ScopedTaskEnvironment task_environment;
726
727 Process child_process = SpawnChild("process_util_test_die_immediately");
728 ASSERT_TRUE(child_process.IsValid());
729
730 // Wait for the child process to actually exit.
731 child_process.Duplicate().WaitForExitWithTimeout(
732 TestTimeouts::action_max_timeout(), nullptr);
733
734 EnsureProcessTerminated(child_process.Duplicate());
735
736 // Verify that the process is really, truly gone.
737 EXPECT_TRUE(child_process.WaitForExitWithTimeout(
738 TestTimeouts::action_max_timeout(), nullptr));
739 }
740
MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately)741 MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
742 return kSuccess;
743 }
744
745 #if defined(OS_WIN)
746 // TODO(estade): if possible, port this test.
TEST_F(ProcessUtilTest,LaunchAsUser)747 TEST_F(ProcessUtilTest, LaunchAsUser) {
748 UserTokenHandle token;
749 ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
750 LaunchOptions options;
751 options.as_user = token;
752 EXPECT_TRUE(
753 LaunchProcess(MakeCmdLine("SimpleChildProcess"), options).IsValid());
754 }
755
756 static const char kEventToTriggerHandleSwitch[] = "event-to-trigger-handle";
757
MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess)758 MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess) {
759 std::string handle_value_string =
760 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
761 kEventToTriggerHandleSwitch);
762 CHECK(!handle_value_string.empty());
763
764 uint64_t handle_value_uint64;
765 CHECK(StringToUint64(handle_value_string, &handle_value_uint64));
766 // Give ownership of the handle to |event|.
767 WaitableEvent event(
768 win::ScopedHandle(reinterpret_cast<HANDLE>(handle_value_uint64)));
769
770 event.Signal();
771
772 return 0;
773 }
774
TEST_F(ProcessUtilTest,InheritSpecifiedHandles)775 TEST_F(ProcessUtilTest, InheritSpecifiedHandles) {
776 // Manually create the event, so that it can be inheritable.
777 SECURITY_ATTRIBUTES security_attributes = {};
778 security_attributes.nLength = static_cast<DWORD>(sizeof(security_attributes));
779 security_attributes.lpSecurityDescriptor = NULL;
780 security_attributes.bInheritHandle = true;
781
782 // Takes ownership of the event handle.
783 WaitableEvent event(
784 win::ScopedHandle(CreateEvent(&security_attributes, true, false, NULL)));
785 LaunchOptions options;
786 options.handles_to_inherit.emplace_back(event.handle());
787
788 CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess");
789 cmd_line.AppendSwitchASCII(
790 kEventToTriggerHandleSwitch,
791 NumberToString(reinterpret_cast<uint64_t>(event.handle())));
792
793 // Launch the process and wait for it to trigger the event.
794 ASSERT_TRUE(LaunchProcess(cmd_line, options).IsValid());
795 EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
796 }
797 #endif // defined(OS_WIN)
798
TEST_F(ProcessUtilTest,GetAppOutput)799 TEST_F(ProcessUtilTest, GetAppOutput) {
800 base::CommandLine command(test_helper_path_);
801 command.AppendArg("hello");
802 command.AppendArg("there");
803 command.AppendArg("good");
804 command.AppendArg("people");
805 std::string output;
806 EXPECT_TRUE(GetAppOutput(command, &output));
807 EXPECT_EQ("hello there good people", output);
808 output.clear();
809
810 const char* kEchoMessage = "blah";
811 command = base::CommandLine(test_helper_path_);
812 command.AppendArg("-x");
813 command.AppendArg("28");
814 command.AppendArg(kEchoMessage);
815 EXPECT_FALSE(GetAppOutput(command, &output));
816 EXPECT_EQ(kEchoMessage, output);
817 }
818
TEST_F(ProcessUtilTest,GetAppOutputWithExitCode)819 TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) {
820 const char* kEchoMessage1 = "doge";
821 int exit_code = -1;
822 base::CommandLine command(test_helper_path_);
823 command.AppendArg(kEchoMessage1);
824 std::string output;
825 EXPECT_TRUE(GetAppOutputWithExitCode(command, &output, &exit_code));
826 EXPECT_EQ(kEchoMessage1, output);
827 EXPECT_EQ(0, exit_code);
828 output.clear();
829
830 const char* kEchoMessage2 = "pupper";
831 const int kExpectedExitCode = 42;
832 command = base::CommandLine(test_helper_path_);
833 command.AppendArg("-x");
834 command.AppendArg(base::IntToString(kExpectedExitCode));
835 command.AppendArg(kEchoMessage2);
836 #if defined(OS_WIN)
837 // On Windows, anything that quits with a nonzero status code is handled as a
838 // "crash", so just ignore GetAppOutputWithExitCode's return value.
839 GetAppOutputWithExitCode(command, &output, &exit_code);
840 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
841 EXPECT_TRUE(GetAppOutputWithExitCode(command, &output, &exit_code));
842 #endif
843 EXPECT_EQ(kEchoMessage2, output);
844 EXPECT_EQ(kExpectedExitCode, exit_code);
845 }
846
847 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
848
849 namespace {
850
851 // Returns the maximum number of files that a process can have open.
852 // Returns 0 on error.
GetMaxFilesOpenInProcess()853 int GetMaxFilesOpenInProcess() {
854 #if defined(OS_FUCHSIA)
855 return FDIO_MAX_FD;
856 #else
857 struct rlimit rlim;
858 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
859 return 0;
860 }
861
862 // rlim_t is a uint64_t - clip to maxint. We do this since FD #s are ints
863 // which are all 32 bits on the supported platforms.
864 rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32_t>::max());
865 if (rlim.rlim_cur > max_int) {
866 return max_int;
867 }
868
869 return rlim.rlim_cur;
870 #endif // defined(OS_FUCHSIA)
871 }
872
873 const int kChildPipe = 20; // FD # for write end of pipe in child process.
874
875 #if defined(OS_MACOSX)
876
877 // <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h>
878 #if !defined(_GUARDID_T)
879 #define _GUARDID_T
880 typedef __uint64_t guardid_t;
881 #endif // _GUARDID_T
882
883 // From .../MacOSX10.9.sdk/usr/include/sys/syscall.h
884 #if !defined(SYS_change_fdguard_np)
885 #define SYS_change_fdguard_np 444
886 #endif
887
888 // <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h>
889 #if !defined(GUARD_DUP)
890 #define GUARD_DUP (1u << 1)
891 #endif
892
893 // <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/kern/kern_guarded.c?txt>
894 //
895 // Atomically replaces |guard|/|guardflags| with |nguard|/|nguardflags| on |fd|.
change_fdguard_np(int fd,const guardid_t * guard,u_int guardflags,const guardid_t * nguard,u_int nguardflags,int * fdflagsp)896 int change_fdguard_np(int fd,
897 const guardid_t *guard, u_int guardflags,
898 const guardid_t *nguard, u_int nguardflags,
899 int *fdflagsp) {
900 return syscall(SYS_change_fdguard_np, fd, guard, guardflags,
901 nguard, nguardflags, fdflagsp);
902 }
903
904 // Attempt to set a file-descriptor guard on |fd|. In case of success, remove
905 // it and return |true| to indicate that it can be guarded. Returning |false|
906 // means either that |fd| is guarded by some other code, or more likely EBADF.
907 //
908 // Starting with 10.9, libdispatch began setting GUARD_DUP on a file descriptor.
909 // Unfortunately, it is spun up as part of +[NSApplication initialize], which is
910 // not really something that Chromium can avoid using on OSX. See
911 // <http://crbug.com/338157>. This function allows querying whether the file
912 // descriptor is guarded before attempting to close it.
CanGuardFd(int fd)913 bool CanGuardFd(int fd) {
914 // Saves the original flags to reset later.
915 int original_fdflags = 0;
916
917 // This can be any value at all, it just has to match up between the two
918 // calls.
919 const guardid_t kGuard = 15;
920
921 // Attempt to change the guard. This can fail with EBADF if the file
922 // descriptor is bad, or EINVAL if the fd already has a guard set.
923 int ret =
924 change_fdguard_np(fd, NULL, 0, &kGuard, GUARD_DUP, &original_fdflags);
925 if (ret == -1)
926 return false;
927
928 // Remove the guard. It should not be possible to fail in removing the guard
929 // just added.
930 ret = change_fdguard_np(fd, &kGuard, GUARD_DUP, NULL, 0, &original_fdflags);
931 DPCHECK(ret == 0);
932
933 return true;
934 }
935 #endif // defined(OS_MACOSX)
936
937 } // namespace
938
MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess)939 MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) {
940 // This child process counts the number of open FDs, it then writes that
941 // number out to a pipe connected to the parent.
942 int num_open_files = 0;
943 int write_pipe = kChildPipe;
944 int max_files = GetMaxFilesOpenInProcess();
945 for (int i = STDERR_FILENO + 1; i < max_files; i++) {
946 #if defined(OS_MACOSX)
947 // Ignore guarded or invalid file descriptors.
948 if (!CanGuardFd(i))
949 continue;
950 #endif
951
952 if (i != kChildPipe) {
953 int fd;
954 if ((fd = HANDLE_EINTR(dup(i))) != -1) {
955 close(fd);
956 num_open_files += 1;
957 }
958 }
959 }
960
961 int written = HANDLE_EINTR(write(write_pipe, &num_open_files,
962 sizeof(num_open_files)));
963 DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files));
964 int ret = IGNORE_EINTR(close(write_pipe));
965 DPCHECK(ret == 0);
966
967 return 0;
968 }
969
CountOpenFDsInChild()970 int ProcessUtilTest::CountOpenFDsInChild() {
971 int fds[2];
972 if (pipe(fds) < 0)
973 NOTREACHED();
974
975 LaunchOptions options;
976 options.fds_to_remap.emplace_back(fds[1], kChildPipe);
977 Process process =
978 SpawnChildWithOptions("ProcessUtilsLeakFDChildProcess", options);
979 CHECK(process.IsValid());
980 int ret = IGNORE_EINTR(close(fds[1]));
981 DPCHECK(ret == 0);
982
983 // Read number of open files in client process from pipe;
984 int num_open_files = -1;
985 ssize_t bytes_read =
986 HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files)));
987 CHECK_EQ(bytes_read, static_cast<ssize_t>(sizeof(num_open_files)));
988
989 #if defined(THREAD_SANITIZER)
990 // Compiler-based ThreadSanitizer makes this test slow.
991 TimeDelta timeout = TimeDelta::FromSeconds(3);
992 #else
993 TimeDelta timeout = TimeDelta::FromSeconds(1);
994 #endif
995 int exit_code;
996 CHECK(process.WaitForExitWithTimeout(timeout, &exit_code));
997 ret = IGNORE_EINTR(close(fds[0]));
998 DPCHECK(ret == 0);
999
1000 return num_open_files;
1001 }
1002
1003 #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
1004 // ProcessUtilTest.FDRemapping is flaky when ran under xvfb-run on Precise.
1005 // The problem is 100% reproducible with both ASan and TSan.
1006 // See http://crbug.com/136720.
1007 #define MAYBE_FDRemapping DISABLED_FDRemapping
1008 #else
1009 #define MAYBE_FDRemapping FDRemapping
1010 #endif // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
TEST_F(ProcessUtilTest,MAYBE_FDRemapping)1011 TEST_F(ProcessUtilTest, MAYBE_FDRemapping) {
1012 int fds_before = CountOpenFDsInChild();
1013
1014 // open some dummy fds to make sure they don't propagate over to the
1015 // child process.
1016 int dev_null = open("/dev/null", O_RDONLY);
1017 DPCHECK(dev_null != -1);
1018 int sockets[2];
1019 int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
1020 DPCHECK(ret == 0);
1021
1022 int fds_after = CountOpenFDsInChild();
1023
1024 ASSERT_EQ(fds_after, fds_before);
1025
1026 ret = IGNORE_EINTR(close(sockets[0]));
1027 DPCHECK(ret == 0);
1028 ret = IGNORE_EINTR(close(sockets[1]));
1029 DPCHECK(ret == 0);
1030 ret = IGNORE_EINTR(close(dev_null));
1031 DPCHECK(ret == 0);
1032 }
1033
1034 const char kPipeValue = '\xcc';
MULTIPROCESS_TEST_MAIN(ProcessUtilsVerifyStdio)1035 MULTIPROCESS_TEST_MAIN(ProcessUtilsVerifyStdio) {
1036 // Write to stdio so the parent process can observe output.
1037 CHECK_EQ(1, HANDLE_EINTR(write(STDOUT_FILENO, &kPipeValue, 1)));
1038
1039 // Close all of the handles, to verify they are valid.
1040 CHECK_EQ(0, IGNORE_EINTR(close(STDIN_FILENO)));
1041 CHECK_EQ(0, IGNORE_EINTR(close(STDOUT_FILENO)));
1042 CHECK_EQ(0, IGNORE_EINTR(close(STDERR_FILENO)));
1043 return 0;
1044 }
1045
TEST_F(ProcessUtilTest,FDRemappingIncludesStdio)1046 TEST_F(ProcessUtilTest, FDRemappingIncludesStdio) {
1047 int dev_null = open("/dev/null", O_RDONLY);
1048 ASSERT_LT(2, dev_null);
1049
1050 // Backup stdio and replace it with the write end of a pipe, for our
1051 // child process to inherit.
1052 int pipe_fds[2];
1053 int result = pipe(pipe_fds);
1054 ASSERT_EQ(0, result);
1055 int backup_stdio = HANDLE_EINTR(dup(STDOUT_FILENO));
1056 ASSERT_LE(0, backup_stdio);
1057 result = dup2(pipe_fds[1], STDOUT_FILENO);
1058 ASSERT_EQ(STDOUT_FILENO, result);
1059
1060 // Launch the test process, which should inherit our pipe stdio.
1061 LaunchOptions options;
1062 options.fds_to_remap.emplace_back(dev_null, dev_null);
1063 Process process = SpawnChildWithOptions("ProcessUtilsVerifyStdio", options);
1064 ASSERT_TRUE(process.IsValid());
1065
1066 // Restore stdio, so we can output stuff.
1067 result = dup2(backup_stdio, STDOUT_FILENO);
1068 ASSERT_EQ(STDOUT_FILENO, result);
1069
1070 // Close our copy of the write end of the pipe, so that the read()
1071 // from the other end will see EOF if it wasn't copied to the child.
1072 result = IGNORE_EINTR(close(pipe_fds[1]));
1073 ASSERT_EQ(0, result);
1074
1075 result = IGNORE_EINTR(close(backup_stdio));
1076 ASSERT_EQ(0, result);
1077 result = IGNORE_EINTR(close(dev_null));
1078 ASSERT_EQ(0, result);
1079
1080 // Read from the pipe to verify that it is connected to the child
1081 // process' stdio.
1082 char buf[16] = {};
1083 EXPECT_EQ(1, HANDLE_EINTR(read(pipe_fds[0], buf, sizeof(buf))));
1084 EXPECT_EQ(kPipeValue, buf[0]);
1085
1086 result = IGNORE_EINTR(close(pipe_fds[0]));
1087 ASSERT_EQ(0, result);
1088
1089 int exit_code;
1090 ASSERT_TRUE(
1091 process.WaitForExitWithTimeout(TimeDelta::FromSeconds(5), &exit_code));
1092 EXPECT_EQ(0, exit_code);
1093 }
1094
1095 #if defined(OS_FUCHSIA)
1096
1097 const uint16_t kStartupHandleId = 43;
MULTIPROCESS_TEST_MAIN(ProcessUtilsVerifyHandle)1098 MULTIPROCESS_TEST_MAIN(ProcessUtilsVerifyHandle) {
1099 zx_handle_t handle =
1100 zx_take_startup_handle(PA_HND(PA_USER0, kStartupHandleId));
1101 CHECK_NE(ZX_HANDLE_INVALID, handle);
1102
1103 // Write to the pipe so the parent process can observe output.
1104 size_t bytes_written = 0;
1105 zx_status_t result = zx_socket_write(handle, 0, &kPipeValue,
1106 sizeof(kPipeValue), &bytes_written);
1107 CHECK_EQ(ZX_OK, result);
1108 CHECK_EQ(1u, bytes_written);
1109
1110 CHECK_EQ(ZX_OK, zx_handle_close(handle));
1111 return 0;
1112 }
1113
TEST_F(ProcessUtilTest,LaunchWithHandleTransfer)1114 TEST_F(ProcessUtilTest, LaunchWithHandleTransfer) {
1115 // Create a pipe to pass to the child process.
1116 zx_handle_t handles[2];
1117 zx_status_t result =
1118 zx_socket_create(ZX_SOCKET_STREAM, &handles[0], &handles[1]);
1119 ASSERT_EQ(ZX_OK, result);
1120
1121 // Launch the test process, and pass it one end of the pipe.
1122 LaunchOptions options;
1123 options.handles_to_transfer.push_back(
1124 {PA_HND(PA_USER0, kStartupHandleId), handles[0]});
1125 Process process = SpawnChildWithOptions("ProcessUtilsVerifyHandle", options);
1126 ASSERT_TRUE(process.IsValid());
1127
1128 // Read from the pipe to verify that the child received it.
1129 zx_signals_t signals = 0;
1130 result = zx_object_wait_one(
1131 handles[1], ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
1132 (base::TimeTicks::Now() + TestTimeouts::action_timeout()).ToZxTime(),
1133 &signals);
1134 ASSERT_EQ(ZX_OK, result);
1135 ASSERT_TRUE(signals & ZX_SOCKET_READABLE);
1136
1137 size_t bytes_read = 0;
1138 char buf[16] = {0};
1139 result = zx_socket_read(handles[1], 0, buf, sizeof(buf), &bytes_read);
1140 EXPECT_EQ(ZX_OK, result);
1141 EXPECT_EQ(1u, bytes_read);
1142 EXPECT_EQ(kPipeValue, buf[0]);
1143
1144 CHECK_EQ(ZX_OK, zx_handle_close(handles[1]));
1145
1146 int exit_code;
1147 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_timeout(),
1148 &exit_code));
1149 EXPECT_EQ(0, exit_code);
1150 }
1151
1152 #endif // defined(OS_FUCHSIA)
1153
1154 namespace {
1155
TestLaunchProcess(const std::vector<std::string> & args,const EnvironmentMap & env_changes,const bool clear_environ,const int clone_flags)1156 std::string TestLaunchProcess(const std::vector<std::string>& args,
1157 const EnvironmentMap& env_changes,
1158 const bool clear_environ,
1159 const int clone_flags) {
1160 int fds[2];
1161 PCHECK(pipe(fds) == 0);
1162
1163 LaunchOptions options;
1164 options.wait = true;
1165 options.environ = env_changes;
1166 options.clear_environ = clear_environ;
1167 options.fds_to_remap.emplace_back(fds[1], 1);
1168 #if defined(OS_LINUX)
1169 options.clone_flags = clone_flags;
1170 #else
1171 CHECK_EQ(0, clone_flags);
1172 #endif // defined(OS_LINUX)
1173 EXPECT_TRUE(LaunchProcess(args, options).IsValid());
1174 PCHECK(IGNORE_EINTR(close(fds[1])) == 0);
1175
1176 char buf[512];
1177 const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
1178
1179 PCHECK(IGNORE_EINTR(close(fds[0])) == 0);
1180
1181 return std::string(buf, n);
1182 }
1183
1184 const char kLargeString[] =
1185 "0123456789012345678901234567890123456789012345678901234567890123456789"
1186 "0123456789012345678901234567890123456789012345678901234567890123456789"
1187 "0123456789012345678901234567890123456789012345678901234567890123456789"
1188 "0123456789012345678901234567890123456789012345678901234567890123456789"
1189 "0123456789012345678901234567890123456789012345678901234567890123456789"
1190 "0123456789012345678901234567890123456789012345678901234567890123456789"
1191 "0123456789012345678901234567890123456789012345678901234567890123456789";
1192
1193 } // namespace
1194
TEST_F(ProcessUtilTest,LaunchProcess)1195 TEST_F(ProcessUtilTest, LaunchProcess) {
1196 const int no_clone_flags = 0;
1197 const bool no_clear_environ = false;
1198 const char kBaseTest[] = "BASE_TEST";
1199 const std::vector<std::string> kPrintEnvCommand = {test_helper_path_.value(),
1200 "-e", kBaseTest};
1201
1202 EnvironmentMap env_changes;
1203 env_changes[kBaseTest] = "bar";
1204 EXPECT_EQ("bar", TestLaunchProcess(kPrintEnvCommand, env_changes,
1205 no_clear_environ, no_clone_flags));
1206 env_changes.clear();
1207
1208 EXPECT_EQ(0, setenv(kBaseTest, "testing", 1 /* override */));
1209 EXPECT_EQ("testing", TestLaunchProcess(kPrintEnvCommand, env_changes,
1210 no_clear_environ, no_clone_flags));
1211
1212 env_changes[kBaseTest] = std::string();
1213 EXPECT_EQ("", TestLaunchProcess(kPrintEnvCommand, env_changes,
1214 no_clear_environ, no_clone_flags));
1215
1216 env_changes[kBaseTest] = "foo";
1217 EXPECT_EQ("foo", TestLaunchProcess(kPrintEnvCommand, env_changes,
1218 no_clear_environ, no_clone_flags));
1219
1220 env_changes.clear();
1221 EXPECT_EQ(0, setenv(kBaseTest, kLargeString, 1 /* override */));
1222 EXPECT_EQ(std::string(kLargeString),
1223 TestLaunchProcess(kPrintEnvCommand, env_changes, no_clear_environ,
1224 no_clone_flags));
1225
1226 env_changes[kBaseTest] = "wibble";
1227 EXPECT_EQ("wibble", TestLaunchProcess(kPrintEnvCommand, env_changes,
1228 no_clear_environ, no_clone_flags));
1229
1230 #if defined(OS_LINUX)
1231 // Test a non-trival value for clone_flags.
1232 EXPECT_EQ("wibble", TestLaunchProcess(kPrintEnvCommand, env_changes,
1233 no_clear_environ, CLONE_FS));
1234
1235 EXPECT_EQ("wibble",
1236 TestLaunchProcess(kPrintEnvCommand, env_changes,
1237 true /* clear_environ */, no_clone_flags));
1238 env_changes.clear();
1239 EXPECT_EQ("", TestLaunchProcess(kPrintEnvCommand, env_changes,
1240 true /* clear_environ */, no_clone_flags));
1241 #endif // defined(OS_LINUX)
1242 }
1243
1244 // There's no such thing as a parent process id on Fuchsia.
1245 #if !defined(OS_FUCHSIA)
TEST_F(ProcessUtilTest,GetParentProcessId)1246 TEST_F(ProcessUtilTest, GetParentProcessId) {
1247 ProcessId ppid = GetParentProcessId(GetCurrentProcessHandle());
1248 EXPECT_EQ(ppid, static_cast<ProcessId>(getppid()));
1249 }
1250 #endif // !defined(OS_FUCHSIA)
1251
1252 #if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
1253 class WriteToPipeDelegate : public LaunchOptions::PreExecDelegate {
1254 public:
WriteToPipeDelegate(int fd)1255 explicit WriteToPipeDelegate(int fd) : fd_(fd) {}
1256 ~WriteToPipeDelegate() override = default;
RunAsyncSafe()1257 void RunAsyncSafe() override {
1258 RAW_CHECK(HANDLE_EINTR(write(fd_, &kPipeValue, 1)) == 1);
1259 RAW_CHECK(IGNORE_EINTR(close(fd_)) == 0);
1260 }
1261
1262 private:
1263 int fd_;
1264 DISALLOW_COPY_AND_ASSIGN(WriteToPipeDelegate);
1265 };
1266
TEST_F(ProcessUtilTest,PreExecHook)1267 TEST_F(ProcessUtilTest, PreExecHook) {
1268 int pipe_fds[2];
1269 ASSERT_EQ(0, pipe(pipe_fds));
1270
1271 ScopedFD read_fd(pipe_fds[0]);
1272 ScopedFD write_fd(pipe_fds[1]);
1273
1274 WriteToPipeDelegate write_to_pipe_delegate(write_fd.get());
1275 LaunchOptions options;
1276 options.fds_to_remap.emplace_back(write_fd.get(), write_fd.get());
1277 options.pre_exec_delegate = &write_to_pipe_delegate;
1278 Process process(SpawnChildWithOptions("SimpleChildProcess", options));
1279 ASSERT_TRUE(process.IsValid());
1280
1281 write_fd.reset();
1282 char c;
1283 ASSERT_EQ(1, HANDLE_EINTR(read(read_fd.get(), &c, 1)));
1284 EXPECT_EQ(c, kPipeValue);
1285
1286 int exit_code = 42;
1287 EXPECT_TRUE(process.WaitForExit(&exit_code));
1288 EXPECT_EQ(0, exit_code);
1289 }
1290 #endif // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
1291
1292 #endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
1293
1294 #if defined(OS_LINUX)
MULTIPROCESS_TEST_MAIN(CheckPidProcess)1295 MULTIPROCESS_TEST_MAIN(CheckPidProcess) {
1296 const pid_t kInitPid = 1;
1297 const pid_t pid = syscall(__NR_getpid);
1298 CHECK(pid == kInitPid);
1299 CHECK(getpid() == pid);
1300 return kSuccess;
1301 }
1302
1303 #if defined(CLONE_NEWUSER) && defined(CLONE_NEWPID)
TEST_F(ProcessUtilTest,CloneFlags)1304 TEST_F(ProcessUtilTest, CloneFlags) {
1305 if (!PathExists(FilePath("/proc/self/ns/user")) ||
1306 !PathExists(FilePath("/proc/self/ns/pid"))) {
1307 // User or PID namespaces are not supported.
1308 return;
1309 }
1310
1311 LaunchOptions options;
1312 options.clone_flags = CLONE_NEWUSER | CLONE_NEWPID;
1313
1314 Process process(SpawnChildWithOptions("CheckPidProcess", options));
1315 ASSERT_TRUE(process.IsValid());
1316
1317 int exit_code = 42;
1318 EXPECT_TRUE(process.WaitForExit(&exit_code));
1319 EXPECT_EQ(kSuccess, exit_code);
1320 }
1321 #endif // defined(CLONE_NEWUSER) && defined(CLONE_NEWPID)
1322
TEST(ForkWithFlagsTest,UpdatesPidCache)1323 TEST(ForkWithFlagsTest, UpdatesPidCache) {
1324 // Warm up the libc pid cache, if there is one.
1325 ASSERT_EQ(syscall(__NR_getpid), getpid());
1326
1327 pid_t ctid = 0;
1328 const pid_t pid = ForkWithFlags(SIGCHLD | CLONE_CHILD_SETTID, nullptr, &ctid);
1329 if (pid == 0) {
1330 // In child. Check both the raw getpid syscall and the libc getpid wrapper
1331 // (which may rely on a pid cache).
1332 RAW_CHECK(syscall(__NR_getpid) == ctid);
1333 RAW_CHECK(getpid() == ctid);
1334 _exit(kSuccess);
1335 }
1336
1337 ASSERT_NE(-1, pid);
1338 int status = 42;
1339 ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
1340 ASSERT_TRUE(WIFEXITED(status));
1341 EXPECT_EQ(kSuccess, WEXITSTATUS(status));
1342 }
1343
TEST_F(ProcessUtilTest,InvalidCurrentDirectory)1344 TEST_F(ProcessUtilTest, InvalidCurrentDirectory) {
1345 LaunchOptions options;
1346 options.current_directory = FilePath("/dev/null");
1347
1348 Process process(SpawnChildWithOptions("SimpleChildProcess", options));
1349 ASSERT_TRUE(process.IsValid());
1350
1351 int exit_code = kSuccess;
1352 EXPECT_TRUE(process.WaitForExit(&exit_code));
1353 EXPECT_NE(kSuccess, exit_code);
1354 }
1355 #endif // defined(OS_LINUX)
1356
1357 } // namespace base
1358