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

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

Powered by Google App Engine
This is Rietveld 408576698