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.
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"
14 // Prototype allowed for functions to be called in the POC
15 typedef void(__cdecl
*lpfnInit
)(HANDLE
);
17 bool ParseCommandLine(wchar_t * command_line
,
18 std::string
* dll_name
,
19 std::string
* entry_point
,
20 base::string16
* log_file
) {
24 if (!dll_name
|| !entry_point
|| !log_file
)
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) {
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];
44 // Free memory allocated for CommandLineToArgvW arguments.
50 int APIENTRY
_tWinMain(HINSTANCE instance
, HINSTANCE
, wchar_t* command_line
,
52 UNREFERENCED_PARAMETER(command_line
);
54 sandbox::BrokerServices
* broker_service
=
55 sandbox::SandboxFactory::GetBrokerServices();
56 sandbox::ResultCode result
;
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.
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
);
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
);
84 // The CreateMainWindowAndLoop() call will not return until the user closes
85 // the application window (or selects File\Exit).
87 window
.CreateMainWindowAndLoop(instance
,
93 // Cannot exit until we have cleaned up after all the targets we have
95 broker_service
->WaitForAllTargets();
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();
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
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
122 if (sandbox::SBOX_ALL_OK
!= (result
= target_service
->Init())) {
123 // TODO(finnur): write the initialization error to the log file
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(),
134 // TODO(finnur): write the failure to the log file
138 // Open the pipe to transfert the log output
139 HANDLE pipe
= ::CreateFile(log_file
.c_str(),
141 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
142 NULL
, // Default security attributes.
144 FILE_ATTRIBUTE_NORMAL
,
145 NULL
); // No template
147 if (INVALID_HANDLE_VALUE
== pipe
) {
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
158 // Initialization is finished, so we can enter lock-down mode
159 target_service
->LowerToken();
161 lpfnInit init_function
=
162 (lpfnInit
) ::GetProcAddress(dll_module
, entry_point
.c_str());
164 if (!init_function
) {
165 // TODO(finnur): write the failure to the log file
166 ::FreeLibrary(dll_module
);
171 // Transfer control to the entry point in the DLL requested
175 Sleep(1000); // Give a change to the debug output to arrive before the
176 // end of the process
178 ::FreeLibrary(dll_module
);