| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 #include "base/base_switches.h" | |
| 6 #include "base/command_line.h" | |
| 7 #include "base/files/file_path.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/rand_util.h" | |
| 10 #include "base/strings/string_number_conversions.h" | |
| 11 #include "base/strings/stringprintf.h" | |
| 12 #include "base/test/multiprocess_test.h" | |
| 13 #include "base/win/win_util.h" | |
| 14 #include "content/public/common/sandbox_init.h" | |
| 15 #include "content/public/common/sandboxed_process_launcher_delegate.h" | |
| 16 #include "sandbox/win/src/sandbox_factory.h" | |
| 17 #include "sandbox/win/src/security_level.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 #include "testing/multiprocess_func_list.h" | |
| 20 | |
| 21 namespace content { | |
| 22 namespace { | |
| 23 | |
| 24 const size_t kMaxMessageLength = 64; | |
| 25 const char kTestMessage1Switch[] = "sandbox-test-message-1"; | |
| 26 const char kTestMessage2Switch[] = "sandbox-test-message-2"; | |
| 27 const char kInheritedHandle1Switch[] = "inherited-handle-1"; | |
| 28 const char kInheritedHandle2Switch[] = "inherited-handle-2"; | |
| 29 | |
| 30 void InitializeTestSandbox() { | |
| 31 sandbox::SandboxInterfaceInfo info = {0}; | |
| 32 info.broker_services = sandbox::SandboxFactory::GetBrokerServices(); | |
| 33 if (!info.broker_services) | |
| 34 info.target_services = sandbox::SandboxFactory::GetTargetServices(); | |
| 35 CHECK(info.broker_services || info.target_services); | |
| 36 CHECK(InitializeSandbox(&info)); | |
| 37 } | |
| 38 | |
| 39 class SandboxInitializer { | |
| 40 public: | |
| 41 SandboxInitializer() { InitializeTestSandbox(); } | |
| 42 }; | |
| 43 | |
| 44 base::LazyInstance<SandboxInitializer> g_sandbox_initializer; | |
| 45 | |
| 46 HANDLE GetHandleFromCommandLine(const char* switch_name) { | |
| 47 unsigned handle_id; | |
| 48 CHECK(base::StringToUint( | |
| 49 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name), | |
| 50 &handle_id)); | |
| 51 CHECK(handle_id); | |
| 52 return reinterpret_cast<HANDLE>(handle_id); | |
| 53 } | |
| 54 | |
| 55 std::string ReadMessageFromPipe(HANDLE pipe) { | |
| 56 char buffer[kMaxMessageLength]; | |
| 57 DWORD bytes_read = 0; | |
| 58 BOOL result = | |
| 59 ::ReadFile(pipe, buffer, kMaxMessageLength, &bytes_read, nullptr); | |
| 60 PCHECK(result); | |
| 61 return std::string(buffer, bytes_read); | |
| 62 } | |
| 63 | |
| 64 void WriteMessageToPipe(HANDLE pipe, const base::StringPiece& message) { | |
| 65 DWORD bytes_written = 0; | |
| 66 BOOL result = ::WriteFile(pipe, message.data(), message.size(), | |
| 67 &bytes_written, nullptr); | |
| 68 CHECK_EQ(message.size(), static_cast<size_t>(bytes_written)); | |
| 69 PCHECK(result); | |
| 70 } | |
| 71 | |
| 72 // Does what MultiProcessTest::MakeCmdLine does, plus ensures ".exe" extension | |
| 73 // on Program. | |
| 74 base::CommandLine MakeCmdLineWithExtension(const std::string& testTarget) { | |
| 75 base::CommandLine cmd_line = base::GetMultiProcessTestChildBaseCommandLine(); | |
| 76 cmd_line.AppendSwitchASCII(switches::kTestChildProcess, testTarget); | |
| 77 | |
| 78 base::FilePath program = cmd_line.GetProgram(); | |
| 79 cmd_line.SetProgram(program.ReplaceExtension(L"exe")); | |
| 80 return cmd_line; | |
| 81 } | |
| 82 | |
| 83 class SandboxWinTest : public base::MultiProcessTest { | |
| 84 public: | |
| 85 SandboxWinTest() {} | |
| 86 ~SandboxWinTest() override {} | |
| 87 | |
| 88 void SetUp() override { | |
| 89 // Ensure the sandbox broker services are initialized exactly once in the | |
| 90 // parent test process. | |
| 91 g_sandbox_initializer.Get(); | |
| 92 } | |
| 93 | |
| 94 protected: | |
| 95 // Creates a new pipe for synchronous IO. The client handle is created in a | |
| 96 // non-inheritable state. | |
| 97 void CreatePipe(base::win::ScopedHandle* server, | |
| 98 base::win::ScopedHandle* client) { | |
| 99 std::string pipe_name = base::StringPrintf( | |
| 100 "\\\\.\\pipe\\sandbox_win_test.%I64u", base::RandUint64()); | |
| 101 server->Set(CreateNamedPipeA( | |
| 102 pipe_name.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | | |
| 103 FILE_FLAG_FIRST_PIPE_INSTANCE, | |
| 104 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 4096, 4096, 5000, nullptr)); | |
| 105 CHECK(server->IsValid()); | |
| 106 | |
| 107 client->Set(CreateFileA( | |
| 108 pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, | |
| 109 OPEN_EXISTING, SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, nullptr)); | |
| 110 CHECK(client->IsValid()); | |
| 111 } | |
| 112 | |
| 113 base::Process LaunchTestClient( | |
| 114 base::CommandLine* cmd_line, | |
| 115 bool sandboxed, | |
| 116 const base::HandlesToInheritVector& handles_to_inherit) { | |
| 117 TestLauncherDelegate delegate(sandboxed); | |
| 118 base::Process process = StartSandboxedProcess( | |
| 119 &delegate, cmd_line, handles_to_inherit); | |
| 120 CHECK(process.IsValid()); | |
| 121 return process; | |
| 122 } | |
| 123 | |
| 124 class TestLauncherDelegate : public SandboxedProcessLauncherDelegate { | |
| 125 public: | |
| 126 explicit TestLauncherDelegate(bool should_sandbox) | |
| 127 : should_sandbox_(should_sandbox) {} | |
| 128 ~TestLauncherDelegate() override {} | |
| 129 | |
| 130 // SandboxedProcessLauncherDelegate: | |
| 131 bool ShouldSandbox() override { return should_sandbox_; } | |
| 132 | |
| 133 bool PreSpawnTarget(sandbox::TargetPolicy* policy) override { | |
| 134 policy->SetTokenLevel(sandbox::USER_INTERACTIVE, sandbox::USER_LOCKDOWN); | |
| 135 return true; | |
| 136 } | |
| 137 | |
| 138 SandboxType GetSandboxType() override { return SANDBOX_TYPE_RENDERER; } | |
| 139 | |
| 140 private: | |
| 141 bool should_sandbox_; | |
| 142 }; | |
| 143 }; | |
| 144 | |
| 145 // ----------------------------------------------------------------------------- | |
| 146 // Tests follow: single-handle inheritance. | |
| 147 // ----------------------------------------------------------------------------- | |
| 148 | |
| 149 MULTIPROCESS_TEST_MAIN(ReadPipe) { | |
| 150 InitializeTestSandbox(); | |
| 151 | |
| 152 // Expects a message and pipe handle to be passed in, and expects to read the | |
| 153 // same message from that pipe. Exits with 0 on success, 1 on failure. | |
| 154 | |
| 155 base::win::ScopedHandle pipe( | |
| 156 GetHandleFromCommandLine(kInheritedHandle1Switch)); | |
| 157 std::string message = ReadMessageFromPipe(pipe.Get()); | |
| 158 | |
| 159 if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 160 kTestMessage1Switch) != message) { | |
| 161 return 1; | |
| 162 } | |
| 163 | |
| 164 return 0; | |
| 165 } | |
| 166 | |
| 167 TEST_F(SandboxWinTest, InheritSingleHandleUnsandboxed) { | |
| 168 base::CommandLine cmd_line = MakeCmdLineWithExtension("ReadPipe"); | |
| 169 | |
| 170 base::win::ScopedHandle server, client; | |
| 171 CreatePipe(&server, &client); | |
| 172 | |
| 173 base::HandlesToInheritVector handles; | |
| 174 handles.push_back(client.Get()); | |
| 175 | |
| 176 // Pass a test message and the pipe handle ID on the command line. | |
| 177 const std::string kTestMessage = "Hello, world!"; | |
| 178 cmd_line.AppendSwitchASCII(kTestMessage1Switch, kTestMessage); | |
| 179 cmd_line.AppendSwitchASCII( | |
| 180 kInheritedHandle1Switch, | |
| 181 base::UintToString(base::win::HandleToUint32(client.Get()))); | |
| 182 | |
| 183 base::Process child_process = | |
| 184 LaunchTestClient(&cmd_line, false /* sandboxed */, handles); | |
| 185 | |
| 186 WriteMessageToPipe(server.Get(), kTestMessage); | |
| 187 | |
| 188 int exit_code = 0; | |
| 189 child_process.WaitForExit(&exit_code); | |
| 190 EXPECT_EQ(0, exit_code); | |
| 191 } | |
| 192 | |
| 193 TEST_F(SandboxWinTest, InheritSingleHandleSandboxed) { | |
| 194 base::CommandLine cmd_line = MakeCmdLineWithExtension("ReadPipe"); | |
| 195 | |
| 196 base::win::ScopedHandle server, client; | |
| 197 CreatePipe(&server, &client); | |
| 198 | |
| 199 base::HandlesToInheritVector handles; | |
| 200 handles.push_back(client.Get()); | |
| 201 | |
| 202 // Pass a test message and the pipe handle ID on the command line. | |
| 203 const std::string kTestMessage = "Hello, world!"; | |
| 204 cmd_line.AppendSwitchASCII(kTestMessage1Switch, kTestMessage); | |
| 205 cmd_line.AppendSwitchASCII( | |
| 206 kInheritedHandle1Switch, | |
| 207 base::UintToString(base::win::HandleToUint32(client.Get()))); | |
| 208 | |
| 209 base::Process child_process = | |
| 210 LaunchTestClient(&cmd_line, true /* sandboxed */, handles); | |
| 211 | |
| 212 WriteMessageToPipe(server.Get(), kTestMessage); | |
| 213 | |
| 214 int exit_code = 0; | |
| 215 child_process.WaitForExit(&exit_code); | |
| 216 EXPECT_EQ(0, exit_code); | |
| 217 } | |
| 218 | |
| 219 // ----------------------------------------------------------------------------- | |
| 220 // Tests follow: multi-handle inheritance. | |
| 221 // ----------------------------------------------------------------------------- | |
| 222 | |
| 223 MULTIPROCESS_TEST_MAIN(ReadMultiPipes) { | |
| 224 InitializeTestSandbox(); | |
| 225 | |
| 226 // Expects two messages and two pipe handles to be passed in, and expects to | |
| 227 // read each message from its respective pipe. Exits with 0 on success, 1 on | |
| 228 // failure. | |
| 229 | |
| 230 base::win::ScopedHandle pipe1( | |
| 231 GetHandleFromCommandLine(kInheritedHandle1Switch)); | |
| 232 std::string message1 = ReadMessageFromPipe(pipe1.Get()); | |
| 233 | |
| 234 if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 235 kTestMessage1Switch) != message1) { | |
| 236 return 1; | |
| 237 } | |
| 238 | |
| 239 base::win::ScopedHandle pipe2( | |
| 240 GetHandleFromCommandLine(kInheritedHandle2Switch)); | |
| 241 std::string message2 = ReadMessageFromPipe(pipe2.Get()); | |
| 242 | |
| 243 if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 244 kTestMessage2Switch) != message2) { | |
| 245 return 1; | |
| 246 } | |
| 247 | |
| 248 return 0; | |
| 249 } | |
| 250 | |
| 251 TEST_F(SandboxWinTest, InheritMultipleHandlesUnsandboxed) { | |
| 252 base::CommandLine cmd_line = MakeCmdLineWithExtension("ReadMultiPipes"); | |
| 253 | |
| 254 base::win::ScopedHandle server1, client1; | |
| 255 CreatePipe(&server1, &client1); | |
| 256 | |
| 257 base::win::ScopedHandle server2, client2; | |
| 258 CreatePipe(&server2, &client2); | |
| 259 | |
| 260 base::HandlesToInheritVector handles; | |
| 261 handles.push_back(client1.Get()); | |
| 262 handles.push_back(client2.Get()); | |
| 263 | |
| 264 // Pass each pipe handle ID and a message for each on the command line. | |
| 265 const std::string kTestMessage1 = "Hello, world!"; | |
| 266 const std::string kTestMessage2 = "Goodbye, world!"; | |
| 267 | |
| 268 cmd_line.AppendSwitchASCII(kTestMessage1Switch, kTestMessage1); | |
| 269 cmd_line.AppendSwitchASCII( | |
| 270 kInheritedHandle1Switch, | |
| 271 base::UintToString(base::win::HandleToUint32(client1.Get()))); | |
| 272 | |
| 273 cmd_line.AppendSwitchASCII(kTestMessage2Switch, kTestMessage2); | |
| 274 cmd_line.AppendSwitchASCII( | |
| 275 kInheritedHandle2Switch, | |
| 276 base::UintToString(base::win::HandleToUint32(client2.Get()))); | |
| 277 | |
| 278 base::Process child_process = | |
| 279 LaunchTestClient(&cmd_line, false /* sandboxed */, handles); | |
| 280 | |
| 281 WriteMessageToPipe(server1.Get(), kTestMessage1); | |
| 282 WriteMessageToPipe(server2.Get(), kTestMessage2); | |
| 283 | |
| 284 int exit_code = 0; | |
| 285 child_process.WaitForExit(&exit_code); | |
| 286 EXPECT_EQ(0, exit_code); | |
| 287 } | |
| 288 | |
| 289 TEST_F(SandboxWinTest, InheritMultipleHandlesSandboxed) { | |
| 290 base::CommandLine cmd_line = MakeCmdLineWithExtension("ReadMultiPipes"); | |
| 291 | |
| 292 base::win::ScopedHandle server1, client1; | |
| 293 CreatePipe(&server1, &client1); | |
| 294 | |
| 295 base::win::ScopedHandle server2, client2; | |
| 296 CreatePipe(&server2, &client2); | |
| 297 | |
| 298 base::HandlesToInheritVector handles; | |
| 299 handles.push_back(client1.Get()); | |
| 300 handles.push_back(client2.Get()); | |
| 301 | |
| 302 // Pass each pipe handle ID and a message for each on the command line. | |
| 303 const std::string kTestMessage1 = "Hello, world!"; | |
| 304 const std::string kTestMessage2 = "Goodbye, world!"; | |
| 305 | |
| 306 cmd_line.AppendSwitchASCII(kTestMessage1Switch, kTestMessage1); | |
| 307 cmd_line.AppendSwitchASCII( | |
| 308 kInheritedHandle1Switch, | |
| 309 base::UintToString(base::win::HandleToUint32(client1.Get()))); | |
| 310 | |
| 311 cmd_line.AppendSwitchASCII(kTestMessage2Switch, kTestMessage2); | |
| 312 cmd_line.AppendSwitchASCII( | |
| 313 kInheritedHandle2Switch, | |
| 314 base::UintToString(base::win::HandleToUint32(client2.Get()))); | |
| 315 | |
| 316 base::Process child_process = | |
| 317 LaunchTestClient(&cmd_line, true /* sandboxed */, handles); | |
| 318 | |
| 319 WriteMessageToPipe(server1.Get(), kTestMessage1); | |
| 320 WriteMessageToPipe(server2.Get(), kTestMessage2); | |
| 321 | |
| 322 int exit_code = 0; | |
| 323 child_process.WaitForExit(&exit_code); | |
| 324 EXPECT_EQ(0, exit_code); | |
| 325 } | |
| 326 | |
| 327 } // namespace | |
| 328 } // namespace | |
| OLD | NEW |