[email protected] | 5a54207 | 2014-02-24 02:12:09 | [diff] [blame] | 1 | // Copyright 2014 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 "chrome_elf/chrome_elf_util.h" |
| 6 | |
caitkp | c393a5b | 2015-05-14 19:56:33 | [diff] [blame] | 7 | #include <assert.h> |
[email protected] | 5a54207 | 2014-02-24 02:12:09 | [diff] [blame] | 8 | #include <windows.h> |
| 9 | |
| 10 | #include "base/macros.h" |
| 11 | #include "base/strings/string16.h" |
| 12 | |
caitkp | c393a5b | 2015-05-14 19:56:33 | [diff] [blame] | 13 | ProcessType g_process_type = ProcessType::UNINITIALIZED; |
| 14 | |
[email protected] | 5a54207 | 2014-02-24 02:12:09 | [diff] [blame] | 15 | namespace { |
| 16 | |
| 17 | const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState"; |
| 18 | const wchar_t kRegPathClientStateMedium[] = |
| 19 | L"Software\\Google\\Update\\ClientStateMedium"; |
| 20 | #if defined(GOOGLE_CHROME_BUILD) |
| 21 | const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Google\\Chrome"; |
| 22 | #else |
| 23 | const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Chromium"; |
| 24 | #endif // defined(GOOGLE_CHROME_BUILD) |
| 25 | |
| 26 | const wchar_t kRegValueUsageStats[] = L"usagestats"; |
| 27 | const wchar_t kUninstallArgumentsField[] = L"UninstallArguments"; |
| 28 | const wchar_t kMetricsReportingEnabled[] =L"MetricsReportingEnabled"; |
| 29 | |
| 30 | const wchar_t kAppGuidCanary[] = |
| 31 | L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}"; |
| 32 | const wchar_t kAppGuidGoogleChrome[] = |
| 33 | L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; |
| 34 | const wchar_t kAppGuidGoogleBinaries[] = |
| 35 | L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; |
| 36 | |
| 37 | bool ReadKeyValueString(bool system_install, const wchar_t* key_path, |
| 38 | const wchar_t* guid, const wchar_t* value_to_read, |
| 39 | base::string16* value_out) { |
| 40 | HKEY key = NULL; |
| 41 | value_out->clear(); |
| 42 | |
| 43 | base::string16 full_key_path(key_path); |
| 44 | full_key_path.append(1, L'\\'); |
| 45 | full_key_path.append(guid); |
| 46 | |
| 47 | if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, |
| 48 | full_key_path.c_str(), 0, |
| 49 | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) != |
| 50 | ERROR_SUCCESS) { |
| 51 | return false; |
| 52 | } |
| 53 | |
| 54 | const size_t kMaxStringLength = 1024; |
| 55 | wchar_t raw_value[kMaxStringLength] = {}; |
| 56 | DWORD size = sizeof(raw_value); |
| 57 | DWORD type = REG_SZ; |
| 58 | LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type, |
| 59 | reinterpret_cast<LPBYTE>(raw_value), &size); |
| 60 | |
| 61 | if (result == ERROR_SUCCESS) { |
| 62 | if (type != REG_SZ || (size & 1) != 0) { |
| 63 | result = ERROR_NOT_SUPPORTED; |
| 64 | } else if (size == 0) { |
| 65 | *raw_value = L'\0'; |
| 66 | } else if (raw_value[size / sizeof(wchar_t) - 1] != L'\0') { |
| 67 | if ((size / sizeof(wchar_t)) < kMaxStringLength) |
| 68 | raw_value[size / sizeof(wchar_t)] = L'\0'; |
| 69 | else |
| 70 | result = ERROR_MORE_DATA; |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | if (result == ERROR_SUCCESS) |
| 75 | *value_out = raw_value; |
| 76 | |
| 77 | ::RegCloseKey(key); |
| 78 | |
| 79 | return result == ERROR_SUCCESS; |
| 80 | } |
| 81 | |
| 82 | bool ReadKeyValueDW(bool system_install, const wchar_t* key_path, |
| 83 | base::string16 guid, const wchar_t* value_to_read, |
| 84 | DWORD* value_out) { |
| 85 | HKEY key = NULL; |
| 86 | *value_out = 0; |
| 87 | |
| 88 | base::string16 full_key_path(key_path); |
| 89 | full_key_path.append(1, L'\\'); |
| 90 | full_key_path.append(guid); |
| 91 | |
| 92 | if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, |
| 93 | full_key_path.c_str(), 0, |
| 94 | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) != |
| 95 | ERROR_SUCCESS) { |
| 96 | return false; |
| 97 | } |
| 98 | |
| 99 | DWORD size = sizeof(*value_out); |
| 100 | DWORD type = REG_DWORD; |
| 101 | LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type, |
| 102 | reinterpret_cast<BYTE*>(value_out), &size); |
| 103 | |
| 104 | ::RegCloseKey(key); |
| 105 | |
| 106 | return result == ERROR_SUCCESS && size == sizeof(*value_out); |
| 107 | } |
| 108 | |
| 109 | } // namespace |
| 110 | |
| 111 | bool IsCanary(const wchar_t* exe_path) { |
| 112 | return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL; |
| 113 | } |
| 114 | |
| 115 | bool IsSystemInstall(const wchar_t* exe_path) { |
| 116 | wchar_t program_dir[MAX_PATH] = {}; |
| 117 | DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, |
| 118 | arraysize(program_dir)); |
| 119 | if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret)) |
| 120 | return true; |
| 121 | |
| 122 | ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, |
| 123 | arraysize(program_dir)); |
| 124 | if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret)) |
| 125 | return true; |
| 126 | |
| 127 | return false; |
| 128 | } |
| 129 | |
| 130 | bool IsMultiInstall(bool is_system_install) { |
| 131 | base::string16 args; |
| 132 | if (!ReadKeyValueString(is_system_install, kRegPathClientState, |
| 133 | kAppGuidGoogleChrome, kUninstallArgumentsField, |
| 134 | &args)) { |
| 135 | return false; |
| 136 | } |
| 137 | return args.find(L"--multi-install") != base::string16::npos; |
| 138 | } |
| 139 | |
| 140 | bool AreUsageStatsEnabled(const wchar_t* exe_path) { |
| 141 | bool enabled = true; |
| 142 | bool controlled_by_policy = ReportingIsEnforcedByPolicy(&enabled); |
| 143 | |
| 144 | if (controlled_by_policy && !enabled) |
| 145 | return false; |
| 146 | |
| 147 | bool system_install = IsSystemInstall(exe_path); |
| 148 | base::string16 app_guid; |
| 149 | |
| 150 | if (IsCanary(exe_path)) { |
| 151 | app_guid = kAppGuidCanary; |
| 152 | } else { |
| 153 | app_guid = IsMultiInstall(system_install) ? kAppGuidGoogleBinaries : |
| 154 | kAppGuidGoogleChrome; |
| 155 | } |
| 156 | |
| 157 | DWORD out_value = 0; |
| 158 | if (system_install && |
| 159 | ReadKeyValueDW(system_install, kRegPathClientStateMedium, app_guid, |
| 160 | kRegValueUsageStats, &out_value)) { |
| 161 | return out_value == 1; |
| 162 | } |
| 163 | |
| 164 | return ReadKeyValueDW(system_install, kRegPathClientState, app_guid, |
| 165 | kRegValueUsageStats, &out_value) && out_value == 1; |
| 166 | } |
| 167 | |
| 168 | bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled) { |
| 169 | HKEY key = NULL; |
| 170 | DWORD value = 0; |
| 171 | BYTE* value_bytes = reinterpret_cast<BYTE*>(&value); |
| 172 | DWORD size = sizeof(value); |
| 173 | DWORD type = REG_DWORD; |
| 174 | |
| 175 | if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegPathChromePolicy, 0, |
| 176 | KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { |
| 177 | if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type, |
| 178 | value_bytes, &size) == ERROR_SUCCESS) { |
| 179 | *breakpad_enabled = value != 0; |
| 180 | } |
| 181 | ::RegCloseKey(key); |
| 182 | return size == sizeof(value); |
| 183 | } |
| 184 | |
| 185 | if (::RegOpenKeyEx(HKEY_CURRENT_USER, kRegPathChromePolicy, 0, |
| 186 | KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { |
| 187 | if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type, |
| 188 | value_bytes, &size) == ERROR_SUCCESS) { |
| 189 | *breakpad_enabled = value != 0; |
| 190 | } |
| 191 | ::RegCloseKey(key); |
| 192 | return size == sizeof(value); |
| 193 | } |
| 194 | |
| 195 | return false; |
| 196 | } |
[email protected] | 0884a31 | 2014-03-01 01:23:24 | [diff] [blame] | 197 | |
caitkp | c393a5b | 2015-05-14 19:56:33 | [diff] [blame] | 198 | void InitializeProcessType() { |
| 199 | assert(g_process_type == ProcessType::UNINITIALIZED); |
[email protected] | 0884a31 | 2014-03-01 01:23:24 | [diff] [blame] | 200 | typedef bool (*IsSandboxedProcessFunc)(); |
| 201 | IsSandboxedProcessFunc is_sandboxed_process_func = |
| 202 | reinterpret_cast<IsSandboxedProcessFunc>( |
| 203 | GetProcAddress(GetModuleHandle(NULL), "IsSandboxedProcess")); |
caitkp | c393a5b | 2015-05-14 19:56:33 | [diff] [blame] | 204 | if (is_sandboxed_process_func && is_sandboxed_process_func()) { |
| 205 | g_process_type = ProcessType::NON_BROWSER_PROCESS; |
| 206 | return; |
| 207 | } |
[email protected] | 0884a31 | 2014-03-01 01:23:24 | [diff] [blame] | 208 | |
caitkp | 88dc419 | 2015-05-12 19:58:56 | [diff] [blame] | 209 | // TODO(robertshield): Drop the command line check when we drop support for |
| 210 | // enabling chrome_elf in unsandboxed processes. |
caitkp | c393a5b | 2015-05-14 19:56:33 | [diff] [blame] | 211 | const wchar_t* command_line = GetCommandLine(); |
| 212 | if (command_line && wcsstr(command_line, L"--type")) { |
| 213 | g_process_type = ProcessType::NON_BROWSER_PROCESS; |
| 214 | return; |
| 215 | } |
[email protected] | 0884a31 | 2014-03-01 01:23:24 | [diff] [blame] | 216 | |
caitkp | c393a5b | 2015-05-14 19:56:33 | [diff] [blame] | 217 | g_process_type = ProcessType::BROWSER_PROCESS; |
| 218 | } |
| 219 | |
| 220 | bool IsNonBrowserProcess() { |
| 221 | assert(g_process_type != ProcessType::UNINITIALIZED); |
| 222 | return g_process_type == ProcessType::NON_BROWSER_PROCESS; |
[email protected] | 0884a31 | 2014-03-01 01:23:24 | [diff] [blame] | 223 | } |