Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: chrome_frame/chrome_launcher.cc

Issue 2278003: Rewrite of chrome_launcher.exe. ETW-based perf tests suggest that this is on ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome_frame/chrome_launcher.h ('k') | chrome_frame/chrome_launcher_main.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome_frame/chrome_launcher.h" 5 #include "chrome_frame/chrome_launcher.h"
6 6
7 #include "base/base_switches.h" 7 #include <windows.h>
8 #include "base/command_line.h" 8 #include <shellapi.h>
9 #include "base/file_util.h" 9 #include <shlwapi.h>
10 #include "base/logging.h" 10
11 #include "base/path_service.h" 11 // Herein lies stuff selectively stolen from Chrome. We don't pull it in
12 #include "base/win_util.h" 12 // directly because all of it results in many things we don't want being
13 #include "chrome/common/chrome_constants.h" 13 // included as well.
14 #include "chrome/common/chrome_switches.h" 14 namespace {
15 #include "chrome_frame/chrome_frame_automation.h"
16 #include "chrome_frame/chrome_frame_reporting.h"
17
18 namespace chrome_launcher {
19
20 const wchar_t kLauncherExeBaseName[] = L"chrome_launcher.exe";
21 15
22 // These are the switches we will allow (along with their values) in the 16 // These are the switches we will allow (along with their values) in the
23 // safe-for-Low-Integrity version of the Chrome command line. 17 // safe-for-Low-Integrity version of the Chrome command line.
24 const char* kAllowedSwitches[] = { 18 // Including the chrome switch files pulls in a bunch of dependencies sadly, so
25 switches::kAutomationClientChannelID, 19 // we redefine things here:
26 switches::kChromeFrame, 20 const wchar_t* kAllowedSwitches[] = {
27 switches::kEnableRendererAccessibility, 21 L"automation-channel",
28 switches::kEnableExperimentalExtensionApis, 22 L"chrome-frame",
29 switches::kNoDefaultBrowserCheck, 23 L"enable-renderer-accessibility",
30 switches::kNoErrorDialogs, 24 L"enable-experimental-extension-apis",
31 switches::kNoFirstRun, 25 L"no-default-browser-check",
32 switches::kUserDataDir, 26 L"noerrdialogs",
33 switches::kDisablePopupBlocking, 27 L"no-first-run",
34 switches::kFullMemoryCrashReport, 28 L"user-data-dir",
29 L"disable-popup-blocking",
30 L"full-memory-crash-report",
35 }; 31 };
36 32
37 CommandLine* CreateLaunchCommandLine() { 33 const wchar_t kWhitespaceChars[] = {
38 // Shortcut for OS versions that don't need the integrity broker. 34 0x0009, /* <control-0009> to <control-000D> */
39 if (win_util::GetWinVersion() < win_util::WINVERSION_VISTA) { 35 0x000A,
40 return new CommandLine(GetChromeExecutablePath()); 36 0x000B,
41 } 37 0x000C,
42 38 0x000D,
43 // The launcher EXE will be in the same directory as the Chrome Frame DLL, 39 0x0020, /* Space */
44 // so create a full path to it based on this assumption. Since our unit 40 0x0085, /* <control-0085> */
45 // tests also use this function, and live in the directory above, we test 41 0x00A0, /* No-Break Space */
46 // existence of the file and try the path that includes the /servers/ 42 0x1680, /* Ogham Space Mark */
47 // directory if needed. 43 0x180E, /* Mongolian Vowel Separator */
48 FilePath module_path; 44 0x2000, /* En Quad to Hair Space */
49 if (PathService::Get(base::FILE_MODULE, &module_path)) { 45 0x2001,
50 FilePath current_dir = module_path.DirName(); 46 0x2002,
51 FilePath same_dir_path = current_dir.Append(kLauncherExeBaseName); 47 0x2003,
52 if (file_util::PathExists(same_dir_path)) { 48 0x2004,
53 return new CommandLine(same_dir_path); 49 0x2005,
54 } else { 50 0x2006,
55 FilePath servers_path = 51 0x2007,
56 current_dir.Append(L"servers").Append(kLauncherExeBaseName); 52 0x2008,
57 DCHECK(file_util::PathExists(servers_path)) << 53 0x2009,
58 "What module is this? It's not in 'servers' or main output dir."; 54 0x200A,
59 return new CommandLine(servers_path); 55 0x200C, /* Zero Width Non-Joiner */
60 } 56 0x2028, /* Line Separator */
61 } else { 57 0x2029, /* Paragraph Separator */
62 NOTREACHED(); 58 0x202F, /* Narrow No-Break Space */
63 return NULL; 59 0x205F, /* Medium Mathematical Space */
64 } 60 0x3000, /* Ideographic Space */
65 } 61 0
66 62 };
67 void SanitizeCommandLine(const CommandLine& original, CommandLine* sanitized) { 63
68 size_t num_sanitized_switches = 0; 64 const wchar_t kLauncherExeBaseName[] = L"chrome_launcher.exe";
65 const wchar_t kBrowserProcessExecutableName[] = L"chrome.exe";
66
67 } // end namespace
68
69
70 namespace chrome_launcher {
71
72 std::wstring TrimWhiteSpace(const wchar_t* input_str) {
73 std::wstring output;
74 if (input_str != NULL) {
75 std::wstring str(input_str);
76
77 const std::wstring::size_type first_good_char =
78 str.find_first_not_of(kWhitespaceChars);
79 const std::wstring::size_type last_good_char =
80 str.find_last_not_of(kWhitespaceChars);
81
82 if (first_good_char != std::wstring::npos &&
83 last_good_char != std::wstring::npos &&
84 last_good_char >= first_good_char) {
85 // + 1 because find_last_not_of returns the index, and we want the count
86 output = str.substr(first_good_char,
87 last_good_char - first_good_char + 1);
88 }
89 }
90
91 return output;
92 }
93
94 bool IsValidArgument(const std::wstring& arg) {
95 if (arg.length() < 2) {
96 return false;
97 }
98
69 for (int i = 0; i < arraysize(kAllowedSwitches); ++i) { 99 for (int i = 0; i < arraysize(kAllowedSwitches); ++i) {
70 const char* current_switch = kAllowedSwitches[i]; 100 size_t arg_length = lstrlenW(kAllowedSwitches[i]);
71 if (original.HasSwitch(current_switch)) { 101 if (arg.find(kAllowedSwitches[i], 2) == 2) {
72 ++num_sanitized_switches; 102 // The argument starts off right, now it must either end here, or be
73 std::wstring switch_value = original.GetSwitchValue(current_switch); 103 // followed by an equals sign.
74 if (0 == switch_value.length()) { 104 if (arg.length() == (arg_length + 2) ||
75 sanitized->AppendSwitch(current_switch); 105 (arg.length() > (arg_length + 2) && arg[arg_length+2] == L'=')) {
106 return true;
107 }
108 }
109 }
110
111 return false;
112 }
113
114 bool IsValidCommandLine(const wchar_t* command_line) {
115 if (command_line == NULL) {
116 return false;
117 }
118
119 int num_args = 0;
120 wchar_t** args = NULL;
121 args = CommandLineToArgvW(command_line, &num_args);
122
123 bool success = true;
124 // Note that we skip args[0] since that is just our executable name and
125 // doesn't get passed through to Chrome.
126 for (int i = 1; i < num_args; ++i) {
127 std::wstring trimmed_arg = TrimWhiteSpace(args[i]);
128 if (!IsValidArgument(trimmed_arg.c_str())) {
129 success = false;
130 break;
131 }
132 }
133
134 return success;
135 }
136
137 bool SanitizeAndLaunchChrome(const wchar_t* command_line) {
138 bool success = false;
139 if (IsValidCommandLine(command_line)) {
140 std::wstring chrome_path;
141 if (GetChromeExecutablePath(&chrome_path)) {
142 const wchar_t* args = PathGetArgs(command_line);
143 if (args != NULL) {
144 chrome_path += L" ";
145 chrome_path += args;
146 }
147
148 STARTUPINFO startup_info = {0};
149 startup_info.cb = sizeof(startup_info);
150 startup_info.dwFlags = STARTF_USESHOWWINDOW;
151 startup_info.wShowWindow = SW_SHOW;
152 PROCESS_INFORMATION process_info = {0};
153 if (CreateProcess(NULL, &chrome_path[0],
154 NULL, NULL, FALSE, 0, NULL, NULL,
155 &startup_info, &process_info)) {
156 // Close handles.
157 CloseHandle(process_info.hThread);
158 CloseHandle(process_info.hProcess);
159 success = true;
76 } else { 160 } else {
77 sanitized->AppendSwitchWithValue(current_switch, switch_value); 161 _ASSERT(FALSE);
78 } 162 }
79 } 163 }
80 } 164 }
81 if (num_sanitized_switches != original.GetSwitchCount()) { 165
82 NOTREACHED(); 166 return success;
83 LOG(ERROR) << "Original command line from Low Integrity had switches " 167 }
84 << "that are not on our whitelist."; 168
85 } 169 bool GetChromeExecutablePath(std::wstring* chrome_path) {
86 } 170 _ASSERT(chrome_path);
87 171
88 bool SanitizeAndLaunchChrome(const wchar_t* command_line) { 172 wchar_t cur_path[MAX_PATH * 4] = {0};
89 std::wstring command_line_with_program(L"dummy.exe "); 173 // Assume that we are always built into an exe.
90 command_line_with_program += command_line; 174 GetModuleFileName(NULL, cur_path, arraysize(cur_path) / 2);
91 CommandLine original = CommandLine::FromString(command_line_with_program); 175
92 CommandLine sanitized(GetChromeExecutablePath()); 176 PathRemoveFileSpec(cur_path);
93 SanitizeCommandLine(original, &sanitized); 177
94 178 bool success = false;
95 DLOG(INFO) << sanitized.command_line_string(); 179 if (PathAppend(cur_path, kBrowserProcessExecutableName)) {
96 sanitized.AppendSwitchWithValue("log-level", "0"); 180 if (!PathFileExists(cur_path)) {
97 181 // The installation model for Chrome places the DLLs in a versioned
98 return base::LaunchApp(sanitized.command_line_string(), false, false, NULL); 182 // sub-folder one down from the Chrome executable. If we fail to find
99 } 183 // chrome.exe in the current path, try looking one up and launching that
100 184 // instead. In practice, that means we back up two and append the
101 FilePath GetChromeExecutablePath() { 185 // executable name again.
102 FilePath cur_path; 186 PathRemoveFileSpec(cur_path);
103 PathService::Get(base::DIR_MODULE, &cur_path); 187 PathRemoveFileSpec(cur_path);
104 cur_path = cur_path.Append(chrome::kBrowserProcessExecutableName); 188 PathAppend(cur_path, kBrowserProcessExecutableName);
105 189 }
106 // The installation model for Chrome places the DLLs in a versioned 190
107 // sub-folder one down from the Chrome executable. If we fail to find 191 if (PathFileExists(cur_path)) {
108 // chrome.exe in the current path, try looking one up and launching that 192 *chrome_path = cur_path;
109 // instead. 193 success = true;
110 if (!file_util::PathExists(cur_path)) { 194 }
111 PathService::Get(base::DIR_MODULE, &cur_path); 195 }
112 cur_path = cur_path.DirName().Append(chrome::kBrowserProcessExecutableName); 196
113 } 197 return success;
114
115 return cur_path;
116 } 198 }
117 199
118 } // namespace chrome_launcher 200 } // namespace chrome_launcher
119
120 // Entrypoint that implements the logic of chrome_launcher.exe.
121 int CALLBACK CfLaunchChrome() {
122 int result = ERROR_OPEN_FAILED;
123
124 if (chrome_launcher::SanitizeAndLaunchChrome(::GetCommandLine())) {
125 result = ERROR_SUCCESS;
126 }
127
128 // Regardless of what just happened, shut down crash reporting now to avoid a
129 // hang when we are unloaded.
130 ShutdownCrashReporting();
131
132 return result;
133 }
134
135 // Compile-time check to see that the type CfLaunchChromeProc is correct.
136 #ifndef NODEBUG
137 namespace {
138 chrome_launcher::CfLaunchChromeProc cf_launch_chrome = CfLaunchChrome;
139 } // namespace
140 #endif // NODEBUG
OLDNEW
« no previous file with comments | « chrome_frame/chrome_launcher.h ('k') | chrome_frame/chrome_launcher_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698