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

Side by Side Diff: chrome_elf/blacklist/blacklist.cc

Issue 311893005: Can now adjust the number of retries before the blacklist is disabled. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: UMA_HISTOGRAM_COUNTS->UMA_HISTOGRAM_COUNTS_100 Created 6 years, 6 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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_elf/blacklist/blacklist.h" 5 #include "chrome_elf/blacklist/blacklist.h"
6 6
7 #include <assert.h> 7 #include <assert.h>
8 #include <string.h> 8 #include <string.h>
9 9
10 #include <vector> 10 #include <vector>
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 // an extra allocation at run time. 46 // an extra allocation at run time.
47 #pragma section(".crthunk",read,execute) 47 #pragma section(".crthunk",read,execute)
48 __declspec(allocate(".crthunk")) sandbox::ThunkData g_thunk_storage; 48 __declspec(allocate(".crthunk")) sandbox::ThunkData g_thunk_storage;
49 49
50 namespace { 50 namespace {
51 51
52 // Record if the blacklist was successfully initialized so processes can easily 52 // Record if the blacklist was successfully initialized so processes can easily
53 // determine if the blacklist is enabled for them. 53 // determine if the blacklist is enabled for them.
54 bool g_blacklist_initialized = false; 54 bool g_blacklist_initialized = false;
55 55
56 // Record that the thunk setup completed succesfully and close the registry 56 // Helper to set DWORD registry values.
57 // key handle since it is no longer needed. 57 DWORD SetDWValue(HKEY* key, const wchar_t* property, DWORD value) {
58 void RecordSuccessfulThunkSetup(HKEY* key) { 58 return ::RegSetValueEx(*key,
59 if (key != NULL) { 59 property,
60 DWORD blacklist_state = blacklist::BLACKLIST_SETUP_RUNNING; 60 0,
61 ::RegSetValueEx(*key, 61 REG_DWORD,
62 blacklist::kBeaconState, 62 reinterpret_cast<LPBYTE>(&value),
63 0, 63 sizeof(value));
64 REG_DWORD, 64 }
65 reinterpret_cast<LPBYTE>(&blacklist_state), 65
66 sizeof(blacklist_state)); 66 bool GenerateStateFromBeaconAndAttemptCount(HKEY* key, DWORD blacklist_state) {
67 ::RegCloseKey(*key); 67 LONG result;
robertshield 2014/06/16 13:56:54 = 0
krstnmnlsn 2014/06/16 17:37:43 Done.
68 key = NULL; 68 if (blacklist_state == blacklist::BLACKLIST_SETUP_RUNNING) {
69 // Some part of the blacklist setup failed last time. If this has occured
70 // blacklist::kBeaconMaxAttempts times in a row we switch the state to
71 // failed and skip setting up the blacklist.
72 DWORD attempt_count = 0;
73 DWORD attempt_count_size = sizeof(attempt_count);
74 result = ::RegQueryValueEx(*key,
75 blacklist::kBeaconAttemptCount,
76 0,
77 NULL,
78 reinterpret_cast<LPBYTE>(&attempt_count),
79 &attempt_count_size);
80
81 if (result == ERROR_FILE_NOT_FOUND)
82 attempt_count = 0;
83 else if (result != ERROR_SUCCESS)
84 return false;
85
86 ++attempt_count;
87 SetDWValue(key, blacklist::kBeaconAttemptCount, attempt_count);
88
89 if (attempt_count >= blacklist::kBeaconMaxAttempts) {
90 blacklist_state = blacklist::BLACKLIST_SETUP_FAILED;
91 SetDWValue(key, blacklist::kBeaconState, blacklist_state);
92 return false;
93 }
94 } else if (blacklist_state == blacklist::BLACKLIST_ENABLED) {
95 // If the blacklist succeeded on the previous run reset the failure
96 // counter.
97 result =
98 SetDWValue(key, blacklist::kBeaconAttemptCount, static_cast<DWORD>(0));
99 if (result != ERROR_SUCCESS) {
100 return false;
101 }
69 } 102 }
103 return true;
70 } 104 }
71 105
72 } // namespace 106 } // namespace
73 107
74 namespace blacklist { 108 namespace blacklist {
75 109
76 #if defined(_WIN64) 110 #if defined(_WIN64)
77 // Allocate storage for the pointer to the old NtMapViewOfSectionFunction. 111 // Allocate storage for the pointer to the old NtMapViewOfSectionFunction.
78 #pragma section(".oldntmap",write,read) 112 #pragma section(".oldntmap",write,read)
79 __declspec(allocate(".oldntmap")) 113 __declspec(allocate(".oldntmap"))
80 NtMapViewOfSectionFunction g_nt_map_view_of_section_func = NULL; 114 NtMapViewOfSectionFunction g_nt_map_view_of_section_func = NULL;
81 #endif 115 #endif
82 116
83 bool LeaveSetupBeacon() { 117 bool LeaveSetupBeacon() {
84 HKEY key = NULL; 118 HKEY key = NULL;
85 DWORD disposition = 0; 119 DWORD disposition = 0;
86 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER, 120 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
87 kRegistryBeaconPath, 121 kRegistryBeaconPath,
88 0, 122 0,
89 NULL, 123 NULL,
90 REG_OPTION_NON_VOLATILE, 124 REG_OPTION_NON_VOLATILE,
91 KEY_QUERY_VALUE | KEY_SET_VALUE, 125 KEY_QUERY_VALUE | KEY_SET_VALUE,
92 NULL, 126 NULL,
93 &key, 127 &key,
94 &disposition); 128 &disposition);
95 if (result != ERROR_SUCCESS) 129 if (result != ERROR_SUCCESS)
96 return false; 130 return false;
97 131
98 // Retrieve the current blacklist state. 132 // Retrieve the current blacklist state.
99 DWORD blacklist_state = BLACKLIST_DISABLED; 133 DWORD blacklist_state = BLACKLIST_STATE_MAX;
100 DWORD blacklist_state_size = sizeof(blacklist_state); 134 DWORD blacklist_state_size = sizeof(blacklist_state);
101 DWORD type = 0; 135 DWORD type = 0;
102 result = ::RegQueryValueEx(key, 136 result = ::RegQueryValueEx(key,
103 kBeaconState, 137 kBeaconState,
104 0, 138 0,
105 &type, 139 &type,
106 reinterpret_cast<LPBYTE>(&blacklist_state), 140 reinterpret_cast<LPBYTE>(&blacklist_state),
107 &blacklist_state_size); 141 &blacklist_state_size);
108 142
109 if (blacklist_state != BLACKLIST_ENABLED || 143 if (blacklist_state == BLACKLIST_DISABLED || result != ERROR_SUCCESS ||
110 result != ERROR_SUCCESS || type != REG_DWORD) { 144 type != REG_DWORD) {
111 ::RegCloseKey(key); 145 ::RegCloseKey(key);
112 return false; 146 return false;
113 } 147 }
114 148
115 // Mark the blacklist setup code as running so if it crashes the blacklist 149 if (!GenerateStateFromBeaconAndAttemptCount(&key, blacklist_state)) {
116 // won't be enabled for the next run. 150 ::RegCloseKey(key);
117 blacklist_state = BLACKLIST_SETUP_RUNNING; 151 return false;
118 result = ::RegSetValueEx(key, 152 }
119 kBeaconState, 153
120 0, 154 result = SetDWValue(&key, kBeaconState, BLACKLIST_SETUP_RUNNING);
121 REG_DWORD,
122 reinterpret_cast<LPBYTE>(&blacklist_state),
123 sizeof(blacklist_state));
124 ::RegCloseKey(key); 155 ::RegCloseKey(key);
125 156
126 return (result == ERROR_SUCCESS); 157 return (result == ERROR_SUCCESS);
127 } 158 }
128 159
129 bool ResetBeacon() { 160 bool ResetBeacon() {
130 HKEY key = NULL; 161 HKEY key = NULL;
131 DWORD disposition = 0; 162 DWORD disposition = 0;
132 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER, 163 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
133 kRegistryBeaconPath, 164 kRegistryBeaconPath,
134 0, 165 0,
135 NULL, 166 NULL,
136 REG_OPTION_NON_VOLATILE, 167 REG_OPTION_NON_VOLATILE,
137 KEY_QUERY_VALUE | KEY_SET_VALUE, 168 KEY_QUERY_VALUE | KEY_SET_VALUE,
138 NULL, 169 NULL,
139 &key, 170 &key,
140 &disposition); 171 &disposition);
141 if (result != ERROR_SUCCESS) 172 if (result != ERROR_SUCCESS)
142 return false; 173 return false;
143 174
144 DWORD blacklist_state = BLACKLIST_ENABLED; 175 DWORD blacklist_state = BLACKLIST_STATE_MAX;
145 result = ::RegSetValueEx(key, 176 DWORD blacklist_state_size = sizeof(blacklist_state);
146 kBeaconState, 177 DWORD type = 0;
147 0, 178 result = ::RegQueryValueEx(key,
148 REG_DWORD, 179 kBeaconState,
149 reinterpret_cast<LPBYTE>(&blacklist_state), 180 0,
150 sizeof(blacklist_state)); 181 &type,
182 reinterpret_cast<LPBYTE>(&blacklist_state),
183 &blacklist_state_size);
184
185 if (result != ERROR_SUCCESS || type != REG_DWORD) {
186 ::RegCloseKey(key);
187 return false;
188 }
189
190 // Reaching this point with the setup running state means the setup
191 // succeeded and so we reset to enabled. Any other state indicates that setup
192 // was skipped; in that case we leave the state alone for later recording.
193 if (blacklist_state == BLACKLIST_SETUP_RUNNING)
194 result = SetDWValue(&key, kBeaconState, BLACKLIST_ENABLED);
195
151 ::RegCloseKey(key); 196 ::RegCloseKey(key);
152
153 return (result == ERROR_SUCCESS); 197 return (result == ERROR_SUCCESS);
154 } 198 }
155 199
156 int BlacklistSize() { 200 int BlacklistSize() {
157 int size = -1; 201 int size = -1;
158 while (blacklist::g_troublesome_dlls[++size] != NULL) {} 202 while (blacklist::g_troublesome_dlls[++size] != NULL) {}
159 203
160 return size; 204 return size;
161 } 205 }
162 206
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 284
241 bool Initialize(bool force) { 285 bool Initialize(bool force) {
242 // Check to see that we found the functions we need in ntdll. 286 // Check to see that we found the functions we need in ntdll.
243 if (!InitializeInterceptImports()) 287 if (!InitializeInterceptImports())
244 return false; 288 return false;
245 289
246 // Check to see if this is a non-browser process, abort if so. 290 // Check to see if this is a non-browser process, abort if so.
247 if (IsNonBrowserProcess()) 291 if (IsNonBrowserProcess())
248 return false; 292 return false;
249 293
250 // Check to see if a beacon is present, abort if so. 294 // Check to see if the blacklist beacon is still set to running (indicating a
295 // failure) or disabled, and abort if so.
251 if (!force && !LeaveSetupBeacon()) 296 if (!force && !LeaveSetupBeacon())
252 return false; 297 return false;
253 298
254 // It is possible for other dlls to have already patched code by now and 299 // It is possible for other dlls to have already patched code by now and
255 // attempting to patch their code might result in crashes. 300 // attempting to patch their code might result in crashes.
256 const bool kRelaxed = false; 301 const bool kRelaxed = false;
257 302
258 // Create a thunk via the appropriate ServiceResolver instance. 303 // Create a thunk via the appropriate ServiceResolver instance.
259 sandbox::ServiceResolverThunk* thunk = GetThunk(kRelaxed); 304 sandbox::ServiceResolverThunk* thunk = GetThunk(kRelaxed);
260 305
261 // Don't try blacklisting on unsupported OS versions. 306 // Don't try blacklisting on unsupported OS versions.
262 if (!thunk) 307 if (!thunk)
263 return false; 308 return false;
264 309
265 // Record that we are starting the thunk setup code.
266 HKEY key = NULL;
267 DWORD disposition = 0;
268 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
269 kRegistryBeaconPath,
270 0,
271 NULL,
272 REG_OPTION_NON_VOLATILE,
273 KEY_QUERY_VALUE | KEY_SET_VALUE,
274 NULL,
275 &key,
276 &disposition);
277 if (result == ERROR_SUCCESS) {
278 DWORD blacklist_state = BLACKLIST_THUNK_SETUP;
279 ::RegSetValueEx(key,
280 kBeaconState,
281 0,
282 REG_DWORD,
283 reinterpret_cast<LPBYTE>(&blacklist_state),
284 sizeof(blacklist_state));
285 } else {
286 key = NULL;
287 }
288
289 BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_thunk_storage); 310 BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_thunk_storage);
290 311
291 // Mark the thunk storage as readable and writeable, since we 312 // Mark the thunk storage as readable and writeable, since we
292 // ready to write to it. 313 // ready to write to it.
293 DWORD old_protect = 0; 314 DWORD old_protect = 0;
294 if (!VirtualProtect(&g_thunk_storage, 315 if (!VirtualProtect(&g_thunk_storage,
295 sizeof(g_thunk_storage), 316 sizeof(g_thunk_storage),
296 PAGE_EXECUTE_READWRITE, 317 PAGE_EXECUTE_READWRITE,
297 &old_protect)) { 318 &old_protect)) {
298 RecordSuccessfulThunkSetup(&key);
299 return false; 319 return false;
300 } 320 }
301 321
302 thunk->AllowLocalPatches(); 322 thunk->AllowLocalPatches();
303 323
304 // We declare this early so it can be used in the 64-bit block below and 324 // We declare this early so it can be used in the 64-bit block below and
305 // still work on 32-bit build when referenced at the end of the function. 325 // still work on 32-bit build when referenced at the end of the function.
306 BOOL page_executable = false; 326 BOOL page_executable = false;
307 327
308 // Replace the default NtMapViewOfSection with our patched version. 328 // Replace the default NtMapViewOfSection with our patched version.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 360
341 // Record if we have initialized the blacklist. 361 // Record if we have initialized the blacklist.
342 g_blacklist_initialized = NT_SUCCESS(ret); 362 g_blacklist_initialized = NT_SUCCESS(ret);
343 363
344 // Mark the thunk storage as executable and prevent any future writes to it. 364 // Mark the thunk storage as executable and prevent any future writes to it.
345 page_executable = page_executable && VirtualProtect(&g_thunk_storage, 365 page_executable = page_executable && VirtualProtect(&g_thunk_storage,
346 sizeof(g_thunk_storage), 366 sizeof(g_thunk_storage),
347 PAGE_EXECUTE_READ, 367 PAGE_EXECUTE_READ,
348 &old_protect); 368 &old_protect);
349 369
350 RecordSuccessfulThunkSetup(&key);
351
352 AddDllsFromRegistryToBlacklist(); 370 AddDllsFromRegistryToBlacklist();
353 371
354 return NT_SUCCESS(ret) && page_executable; 372 return NT_SUCCESS(ret) && page_executable;
355 } 373 }
356 374
357 bool AddDllsFromRegistryToBlacklist() { 375 bool AddDllsFromRegistryToBlacklist() {
358 HKEY key = NULL; 376 HKEY key = NULL;
359 LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER, 377 LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER,
360 kRegistryFinchListPath, 378 kRegistryFinchListPath,
361 0, 379 0,
(...skipping 26 matching lines...) Expand all
388 } 406 }
389 407
390 // Delete the finch registry key to clear the values. 408 // Delete the finch registry key to clear the values.
391 result = ::RegDeleteKey(key, L""); 409 result = ::RegDeleteKey(key, L"");
392 410
393 ::RegCloseKey(key); 411 ::RegCloseKey(key);
394 return result == ERROR_SUCCESS; 412 return result == ERROR_SUCCESS;
395 } 413 }
396 414
397 } // namespace blacklist 415 } // namespace blacklist
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698