Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / sandbox / linux / services / namespace_sandbox_unittest.cc
blob3b22e84130e723afd89fa9c4ead304335f6c8cb6
1 // Copyright 2015 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.
5 #include "sandbox/linux/services/namespace_sandbox.h"
7 #include <signal.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
12 #include <string>
13 #include <utility>
15 #include "base/command_line.h"
16 #include "base/files/file_enumerator.h"
17 #include "base/files/file_path.h"
18 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/process/launch.h"
21 #include "base/process/process.h"
22 #include "base/test/multiprocess_test.h"
23 #include "sandbox/linux/services/credentials.h"
24 #include "sandbox/linux/services/namespace_utils.h"
25 #include "sandbox/linux/services/proc_util.h"
26 #include "sandbox/linux/tests/unit_tests.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "testing/multiprocess_func_list.h"
30 namespace sandbox {
32 namespace {
34 bool RootDirectoryIsEmpty() {
35 base::FilePath root("/");
36 int file_type =
37 base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES;
38 base::FileEnumerator enumerator_before(root, false, file_type);
39 return enumerator_before.Next().empty();
42 class NamespaceSandboxTest : public base::MultiProcessTest {
43 public:
44 void TestProc(const std::string& procname) {
45 if (!Credentials::CanCreateProcessInNewUserNS()) {
46 return;
49 base::FileHandleMappingVector fds_to_remap = {
50 std::make_pair(STDOUT_FILENO, STDOUT_FILENO),
51 std::make_pair(STDERR_FILENO, STDERR_FILENO),
53 base::LaunchOptions launch_options;
54 launch_options.fds_to_remap = &fds_to_remap;
56 base::Process process =
57 NamespaceSandbox::LaunchProcess(MakeCmdLine(procname), launch_options);
58 ASSERT_TRUE(process.IsValid());
60 const int kDummyExitCode = 42;
61 int exit_code = kDummyExitCode;
62 EXPECT_TRUE(process.WaitForExit(&exit_code));
63 EXPECT_EQ(0, exit_code);
67 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
68 scoped_ptr<base::Environment> env(base::Environment::Create());
69 bool in_user_ns = NamespaceSandbox::InNewUserNamespace();
70 bool in_pid_ns = NamespaceSandbox::InNewPidNamespace();
71 bool in_net_ns = NamespaceSandbox::InNewNetNamespace();
72 CHECK(in_user_ns);
73 CHECK_EQ(in_pid_ns,
74 NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWPID));
75 CHECK_EQ(in_net_ns,
76 NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWNET));
77 if (in_pid_ns) {
78 CHECK_EQ(1, getpid());
80 return 0;
83 TEST_F(NamespaceSandboxTest, BasicUsage) {
84 TestProc("SimpleChildProcess");
87 MULTIPROCESS_TEST_MAIN(ChrootMe) {
88 CHECK(!RootDirectoryIsEmpty());
89 CHECK(sandbox::Credentials::MoveToNewUserNS());
90 CHECK(sandbox::Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
91 CHECK(RootDirectoryIsEmpty());
92 return 0;
95 // Temporarily disabled on ASAN due to crbug.com/451603.
96 TEST_F(NamespaceSandboxTest, DISABLE_ON_ASAN(ChrootAndDropCapabilities)) {
97 TestProc("ChrootMe");
100 MULTIPROCESS_TEST_MAIN(NestedNamespaceSandbox) {
101 base::FileHandleMappingVector fds_to_remap = {
102 std::make_pair(STDOUT_FILENO, STDOUT_FILENO),
103 std::make_pair(STDERR_FILENO, STDERR_FILENO),
105 base::LaunchOptions launch_options;
106 launch_options.fds_to_remap = &fds_to_remap;
107 base::Process process = NamespaceSandbox::LaunchProcess(
108 base::CommandLine(base::FilePath("/bin/true")), launch_options);
109 CHECK(process.IsValid());
111 const int kDummyExitCode = 42;
112 int exit_code = kDummyExitCode;
113 CHECK(process.WaitForExit(&exit_code));
114 CHECK_EQ(0, exit_code);
115 return 0;
118 TEST_F(NamespaceSandboxTest, NestedNamespaceSandbox) {
119 TestProc("NestedNamespaceSandbox");
122 const int kNormalExitCode = 0;
124 // Ensure that CHECK(false) is distinguishable from _exit(kNormalExitCode).
125 // Allowing noise since CHECK(false) will write a stack trace to stderr.
126 SANDBOX_TEST_ALLOW_NOISE(ForkInNewPidNamespace, CheckDoesNotReturnZero) {
127 if (!Credentials::CanCreateProcessInNewUserNS()) {
128 return;
131 CHECK(sandbox::Credentials::MoveToNewUserNS());
132 const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
133 /*drop_capabilities_in_child=*/true);
134 CHECK_GE(pid, 0);
136 if (pid == 0) {
137 CHECK(false);
138 _exit(kNormalExitCode);
141 int status;
142 PCHECK(waitpid(pid, &status, 0) == pid);
143 if (WIFEXITED(status)) {
144 CHECK_NE(kNormalExitCode, WEXITSTATUS(status));
148 SANDBOX_TEST(ForkInNewPidNamespace, BasicUsage) {
149 if (!Credentials::CanCreateProcessInNewUserNS()) {
150 return;
153 CHECK(sandbox::Credentials::MoveToNewUserNS());
154 const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
155 /*drop_capabilities_in_child=*/true);
156 CHECK_GE(pid, 0);
158 if (pid == 0) {
159 CHECK_EQ(1, getpid());
160 CHECK(!Credentials::HasAnyCapability());
161 _exit(kNormalExitCode);
164 int status;
165 PCHECK(waitpid(pid, &status, 0) == pid);
166 CHECK(WIFEXITED(status));
167 CHECK_EQ(kNormalExitCode, WEXITSTATUS(status));
170 SANDBOX_TEST(ForkInNewPidNamespace, ExitWithSignal) {
171 if (!Credentials::CanCreateProcessInNewUserNS()) {
172 return;
175 CHECK(sandbox::Credentials::MoveToNewUserNS());
176 const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
177 /*drop_capabilities_in_child=*/true);
178 CHECK_GE(pid, 0);
180 if (pid == 0) {
181 CHECK_EQ(1, getpid());
182 CHECK(!Credentials::HasAnyCapability());
183 CHECK(NamespaceSandbox::InstallTerminationSignalHandler(
184 SIGTERM, NamespaceSandbox::SignalExitCode(SIGTERM)));
185 while (true) {
186 raise(SIGTERM);
190 int status;
191 PCHECK(waitpid(pid, &status, 0) == pid);
192 CHECK(WIFEXITED(status));
193 CHECK_EQ(NamespaceSandbox::SignalExitCode(SIGTERM), WEXITSTATUS(status));
196 volatile sig_atomic_t signal_handler_called;
197 void ExitSuccessfully(int sig) {
198 signal_handler_called = 1;
201 SANDBOX_TEST(InstallTerminationSignalHandler, DoesNotOverrideExistingHandlers) {
202 struct sigaction action = {};
203 action.sa_handler = &ExitSuccessfully;
204 PCHECK(sigaction(SIGUSR1, &action, nullptr) == 0);
206 NamespaceSandbox::InstallDefaultTerminationSignalHandlers();
207 CHECK(!NamespaceSandbox::InstallTerminationSignalHandler(
208 SIGUSR1, NamespaceSandbox::SignalExitCode(SIGUSR1)));
210 raise(SIGUSR1);
211 CHECK_EQ(1, signal_handler_called);
214 } // namespace
216 } // namespace sandbox