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