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"
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"
34 bool RootDirectoryIsEmpty() {
35 base::FilePath
root("/");
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
{
44 void TestProc(const std::string
& procname
) {
45 if (!Credentials::CanCreateProcessInNewUserNS()) {
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();
74 NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWPID
));
76 NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWNET
));
78 CHECK_EQ(1, getpid());
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());
95 // Temporarily disabled on ASAN due to crbug.com/451603.
96 TEST_F(NamespaceSandboxTest
, DISABLE_ON_ASAN(ChrootAndDropCapabilities
)) {
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
);
118 TEST_F(NamespaceSandboxTest
, NestedNamespaceSandbox
) {
119 TestProc("NestedNamespaceSandbox");
122 const int kNormalExitCode
= 0;
123 const int kSignalTerminationExitCode
= 255;
125 // Ensure that CHECK(false) is distinguishable from _exit(kNormalExitCode).
126 // Allowing noise since CHECK(false) will write a stack trace to stderr.
127 SANDBOX_TEST_ALLOW_NOISE(ForkInNewPidNamespace
, CheckDoesNotReturnZero
) {
128 if (!Credentials::CanCreateProcessInNewUserNS()) {
132 CHECK(sandbox::Credentials::MoveToNewUserNS());
133 const pid_t pid
= NamespaceSandbox::ForkInNewPidNamespace(
134 /*drop_capabilities_in_child=*/true);
139 _exit(kNormalExitCode
);
143 PCHECK(waitpid(pid
, &status
, 0) == pid
);
144 if (WIFEXITED(status
)) {
145 CHECK_NE(kNormalExitCode
, WEXITSTATUS(status
));
149 SANDBOX_TEST(ForkInNewPidNamespace
, BasicUsage
) {
150 if (!Credentials::CanCreateProcessInNewUserNS()) {
154 CHECK(sandbox::Credentials::MoveToNewUserNS());
155 const pid_t pid
= NamespaceSandbox::ForkInNewPidNamespace(
156 /*drop_capabilities_in_child=*/true);
160 CHECK_EQ(1, getpid());
161 CHECK(!Credentials::HasAnyCapability());
162 _exit(kNormalExitCode
);
166 PCHECK(waitpid(pid
, &status
, 0) == pid
);
167 CHECK(WIFEXITED(status
));
168 CHECK_EQ(kNormalExitCode
, WEXITSTATUS(status
));
171 SANDBOX_TEST(ForkInNewPidNamespace
, ExitWithSignal
) {
172 if (!Credentials::CanCreateProcessInNewUserNS()) {
176 CHECK(sandbox::Credentials::MoveToNewUserNS());
177 const pid_t pid
= NamespaceSandbox::ForkInNewPidNamespace(
178 /*drop_capabilities_in_child=*/true);
182 CHECK_EQ(1, getpid());
183 CHECK(!Credentials::HasAnyCapability());
184 CHECK(NamespaceSandbox::InstallTerminationSignalHandler(
185 SIGTERM
, kSignalTerminationExitCode
));
192 PCHECK(waitpid(pid
, &status
, 0) == pid
);
193 CHECK(WIFEXITED(status
));
194 CHECK_EQ(kSignalTerminationExitCode
, WEXITSTATUS(status
));
197 volatile sig_atomic_t signal_handler_called
;
198 void ExitSuccessfully(int sig
) {
199 signal_handler_called
= 1;
202 SANDBOX_TEST(InstallTerminationSignalHandler
, DoesNotOverrideExistingHandlers
) {
203 struct sigaction action
= {};
204 action
.sa_handler
= &ExitSuccessfully
;
205 PCHECK(sigaction(SIGUSR1
, &action
, nullptr) == 0);
207 NamespaceSandbox::InstallDefaultTerminationSignalHandlers();
208 CHECK(!NamespaceSandbox::InstallTerminationSignalHandler(
209 SIGUSR1
, kSignalTerminationExitCode
));
212 CHECK_EQ(1, signal_handler_called
);
217 } // namespace sandbox