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