Home | History | Annotate | Download | only in sandbox_poc
      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