1 // Copyright (c) 2006-2010 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 <windows.h> 6 #include <tchar.h> 7 #include <shellapi.h> 8 #include "sandbox/win/sandbox_poc/sandbox.h" 9 #include "base/logging.h" 10 #include "sandbox/win/sandbox_poc/main_ui_window.h" 11 #include "sandbox/win/src/sandbox.h" 12 #include "sandbox/win/src/sandbox_factory.h" 13 14 // Prototype allowed for functions to be called in the POC 15 typedef void(__cdecl *lpfnInit)(HANDLE); 16 17 bool ParseCommandLine(wchar_t * command_line, 18 std::string * dll_name, 19 std::string * entry_point, 20 base::string16 * log_file) { 21 DCHECK(dll_name); 22 DCHECK(entry_point); 23 DCHECK(log_file); 24 if (!dll_name || !entry_point || !log_file) 25 return false; 26 27 LPWSTR *arg_list; 28 int arg_count; 29 30 // We expect the command line to contain: EntryPointName "DLLPath" "LogPath" 31 // NOTE: Double quotes are required, even if long path name not used 32 // NOTE: LogPath can be blank, but still requires the double quotes 33 arg_list = CommandLineToArgvW(command_line, &arg_count); 34 if (NULL == arg_list || arg_count < 4) { 35 return false; 36 } 37 38 base::string16 entry_point_wide = arg_list[1]; 39 base::string16 dll_name_wide = arg_list[2]; 40 *entry_point = std::string(entry_point_wide.begin(), entry_point_wide.end()); 41 *dll_name = std::string(dll_name_wide.begin(), dll_name_wide.end()); 42 *log_file = arg_list[3]; 43 44 // Free memory allocated for CommandLineToArgvW arguments. 45 LocalFree(arg_list); 46 47 return true; 48 } 49 50 int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, wchar_t* command_line, 51 int show_command) { 52 UNREFERENCED_PARAMETER(command_line); 53 54 sandbox::BrokerServices* broker_service = 55 sandbox::SandboxFactory::GetBrokerServices(); 56 sandbox::ResultCode result; 57 58 // This application starts as the broker; an application with a UI that 59 // spawns an instance of itself (called a 'target') inside the sandbox. 60 // Before spawning a hidden instance of itself, the application will have 61 // asked the user which DLL the spawned instance should load and passes 62 // that as command line argument to the spawned instance. 63 // 64 // We check here to see if we can retrieve a pointer to the BrokerServices, 65 // which is not possible if we are running inside the sandbox under a 66 // restricted token so it also tells us which mode we are in. If we can 67 // retrieve the pointer, then we are the broker, otherwise we are the target 68 // that the broker launched. 69 if (NULL != broker_service) { 70 // Yes, we are the broker so we need to initialize and show the UI 71 if (0 != (result = broker_service->Init())) { 72 ::MessageBox(NULL, L"Failed to initialize the BrokerServices object", 73 L"Error during initialization", MB_ICONERROR); 74 return 1; 75 } 76 77 wchar_t exe_name[MAX_PATH]; 78 if (0 == GetModuleFileName(NULL, exe_name, MAX_PATH - 1)) { 79 ::MessageBox(NULL, L"Failed to get name of current EXE", 80 L"Error during initialization", MB_ICONERROR); 81 return 1; 82 } 83 84 // The CreateMainWindowAndLoop() call will not return until the user closes 85 // the application window (or selects File\Exit). 86 MainUIWindow window; 87 window.CreateMainWindowAndLoop(instance, 88 exe_name, 89 show_command, 90 broker_service); 91 92 93 // Cannot exit until we have cleaned up after all the targets we have 94 // created 95 broker_service->WaitForAllTargets(); 96 } else { 97 // This is an instance that has been spawned inside the sandbox by the 98 // broker, so we need to parse the command line to figure out which DLL to 99 // load and what entry point to call 100 sandbox::TargetServices* target_service 101 = sandbox::SandboxFactory::GetTargetServices(); 102 103 if (NULL == target_service) { 104 // TODO(finnur): write the failure to the log file 105 // We cannot display messageboxes inside the sandbox unless access to 106 // the desktop handle has been granted to us, and we don't have a 107 // console window to write to. Therefore we need to have the broker 108 // grant us access to a handle to a logfile and write the error that 109 // occurred into the log before continuing 110 return -1; 111 } 112 113 // Debugging the spawned application can be tricky, because DebugBreak() 114 // and _asm int 3 cause the app to terminate (due to a flag in the job 115 // object), MessageBoxes() will not be displayed unless we have been granted 116 // that privilege and the target finishes its business so quickly we cannot 117 // attach to it quickly enough. Therefore, you can uncomment the 118 // following line and attach (w. msdev or windbg) as the target is sleeping 119 120 // Sleep(10000); 121 122 if (sandbox::SBOX_ALL_OK != (result = target_service->Init())) { 123 // TODO(finnur): write the initialization error to the log file 124 return -2; 125 } 126 127 // Parse the command line to find out what we need to call 128 std::string dll_name, entry_point; 129 base::string16 log_file; 130 if (!ParseCommandLine(GetCommandLineW(), 131 &dll_name, 132 &entry_point, 133 &log_file)) { 134 // TODO(finnur): write the failure to the log file 135 return -3; 136 } 137 138 // Open the pipe to transfert the log output 139 HANDLE pipe = ::CreateFile(log_file.c_str(), 140 GENERIC_WRITE, 141 FILE_SHARE_READ | FILE_SHARE_WRITE, 142 NULL, // Default security attributes. 143 CREATE_ALWAYS, 144 FILE_ATTRIBUTE_NORMAL, 145 NULL); // No template 146 147 if (INVALID_HANDLE_VALUE == pipe) { 148 return -4; 149 } 150 151 // We now know what we should load, so load it 152 HMODULE dll_module = ::LoadLibraryA(dll_name.c_str()); 153 if (dll_module == NULL) { 154 // TODO(finnur): write the failure to the log file 155 return -5; 156 } 157 158 // Initialization is finished, so we can enter lock-down mode 159 target_service->LowerToken(); 160 161 lpfnInit init_function = 162 (lpfnInit) ::GetProcAddress(dll_module, entry_point.c_str()); 163 164 if (!init_function) { 165 // TODO(finnur): write the failure to the log file 166 ::FreeLibrary(dll_module); 167 CloseHandle(pipe); 168 return -6; 169 } 170 171 // Transfer control to the entry point in the DLL requested 172 init_function(pipe); 173 174 CloseHandle(pipe); 175 Sleep(1000); // Give a change to the debug output to arrive before the 176 // end of the process 177 178 ::FreeLibrary(dll_module); 179 } 180 181 return 0; 182 } 183