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

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: Corrected code so that it actually works as intended. Updated unit tests. 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 "base/basictypes.h" 10 #include "base/basictypes.h"
(...skipping 28 matching lines...) Expand all
39 // an extra allocation at run time. 39 // an extra allocation at run time.
40 #pragma section(".crthunk",read,execute) 40 #pragma section(".crthunk",read,execute)
41 __declspec(allocate(".crthunk")) sandbox::ThunkData g_thunk_storage; 41 __declspec(allocate(".crthunk")) sandbox::ThunkData g_thunk_storage;
42 42
43 namespace { 43 namespace {
44 44
45 // Record if the blacklist was successfully initialized so processes can easily 45 // Record if the blacklist was successfully initialized so processes can easily
46 // determine if the blacklist is enabled for them. 46 // determine if the blacklist is enabled for them.
47 bool g_blacklist_initialized = false; 47 bool g_blacklist_initialized = false;
48 48
49 // Record that the thunk setup completed succesfully and close the registry 49 // Helper to set DWORD registry values. Closes the key on failure.
csharp 2014/06/10 14:07:02 Closing the key only value seems an odd thing to d
krstnmnlsn 2014/06/10 22:03:27 Half done :)
50 // key handle since it is no longer needed. 50 DWORD SetDWValue(HKEY* key, const wchar_t* property, DWORD value) {
51 void RecordSuccessfulThunkSetup(HKEY* key) { 51 DWORD result = ::RegSetValueEx(*key,
52 if (key != NULL) { 52 property,
53 DWORD blacklist_state = blacklist::BLACKLIST_SETUP_RUNNING; 53 0,
54 ::RegSetValueEx(*key, 54 REG_DWORD,
55 blacklist::kBeaconState, 55 reinterpret_cast<LPBYTE>(&value),
56 0, 56 sizeof(value));
57 REG_DWORD, 57 if (result != ERROR_SUCCESS)
58 reinterpret_cast<LPBYTE>(&blacklist_state),
59 sizeof(blacklist_state));
60 ::RegCloseKey(*key); 58 ::RegCloseKey(*key);
61 key = NULL; 59 return result;
62 }
63 } 60 }
64 61
65 } // namespace 62 } // namespace
66 63
67 namespace blacklist { 64 namespace blacklist {
68 65
69 #if defined(_WIN64) 66 #if defined(_WIN64)
70 // Allocate storage for the pointer to the old NtMapViewOfSectionFunction. 67 // Allocate storage for the pointer to the old NtMapViewOfSectionFunction.
71 #pragma section(".oldntmap",write,read) 68 #pragma section(".oldntmap",write,read)
72 __declspec(allocate(".oldntmap")) 69 __declspec(allocate(".oldntmap"))
73 NtMapViewOfSectionFunction g_nt_map_view_of_section_func = NULL; 70 NtMapViewOfSectionFunction g_nt_map_view_of_section_func = NULL;
74 #endif 71 #endif
75 72
76 bool LeaveSetupBeacon() { 73 bool LeaveSetupBeacon() {
77 HKEY key = NULL; 74 HKEY key = NULL;
78 DWORD disposition = 0; 75 DWORD disposition = 0;
79 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER, 76 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
80 kRegistryBeaconPath, 77 kRegistryBeaconPath,
81 0, 78 0,
82 NULL, 79 NULL,
83 REG_OPTION_NON_VOLATILE, 80 REG_OPTION_NON_VOLATILE,
84 KEY_QUERY_VALUE | KEY_SET_VALUE, 81 KEY_QUERY_VALUE | KEY_SET_VALUE,
85 NULL, 82 NULL,
86 &key, 83 &key,
87 &disposition); 84 &disposition);
88 if (result != ERROR_SUCCESS) 85 if (result != ERROR_SUCCESS)
89 return false; 86 return false;
90 87
91 // Retrieve the current blacklist state. 88 // Retrieve the current blacklist state.
92 DWORD blacklist_state = BLACKLIST_DISABLED; 89 DWORD blacklist_state = BLACKLIST_STATE_MAX;
93 DWORD blacklist_state_size = sizeof(blacklist_state); 90 DWORD blacklist_state_size = sizeof(blacklist_state);
94 DWORD type = 0; 91 DWORD type = 0;
95 result = ::RegQueryValueEx(key, 92 result = ::RegQueryValueEx(key,
96 kBeaconState, 93 kBeaconState,
97 0, 94 0,
98 &type, 95 &type,
99 reinterpret_cast<LPBYTE>(&blacklist_state), 96 reinterpret_cast<LPBYTE>(&blacklist_state),
100 &blacklist_state_size); 97 &blacklist_state_size);
101 98
102 if (blacklist_state != BLACKLIST_ENABLED || 99 if (blacklist_state == BLACKLIST_DISABLED || result != ERROR_SUCCESS ||
103 result != ERROR_SUCCESS || type != REG_DWORD) { 100 type != REG_DWORD) {
104 ::RegCloseKey(key); 101 ::RegCloseKey(key);
105 return false; 102 return false;
106 } 103 }
107 104
108 // Mark the blacklist setup code as running so if it crashes the blacklist 105 if (blacklist_state == BLACKLIST_SETUP_RUNNING) {
109 // won't be enabled for the next run. 106 // Some part of the blacklist setup failed last time. If this has occured
csharp 2014/06/10 14:07:02 Could you move the code in this if statement into
krstnmnlsn 2014/06/10 22:03:27 Done.
110 blacklist_state = BLACKLIST_SETUP_RUNNING; 107 // some minimum number of times in a row we switch the state to failed and
111 result = ::RegSetValueEx(key, 108 // skip setting up the blacklist.
112 kBeaconState, 109 DWORD attempt_count = 0;
113 0, 110 DWORD attempt_count_size = sizeof(attempt_count);
114 REG_DWORD, 111 DWORD attempt_count_type = 0;
115 reinterpret_cast<LPBYTE>(&blacklist_state), 112 result = ::RegQueryValueEx(key,
116 sizeof(blacklist_state)); 113 kBeaconAttemptCount,
114 0,
115 &attempt_count_type,
116 reinterpret_cast<LPBYTE>(&attempt_count),
117 &attempt_count_size);
118
119 if (result == ERROR_FILE_NOT_FOUND) {
120 attempt_count = 0;
121 attempt_count_type = REG_DWORD;
122 result = SetDWValue(&key, kBeaconAttemptCount, attempt_count);
123 }
124
125 if (result != ERROR_SUCCESS || attempt_count_type != REG_DWORD) {
126 ::RegCloseKey(key);
127 return false;
128 }
129
130 attempt_count = attempt_count + 1;
131 result = SetDWValue(&key, kBeaconAttemptCount, attempt_count);
132 if (result != ERROR_SUCCESS)
133 return false;
134
135 if (attempt_count >= blacklist::kBeaconMaxAttempts) {
136 blacklist_state = BLACKLIST_SETUP_FAILED;
137 SetDWValue(&key, kBeaconState, blacklist_state);
138 ::RegCloseKey(key);
139 return false;
140 }
141 }
142
143 // If the blacklist succeeded on the previous run, reset the failure counter.
144 if (blacklist_state == BLACKLIST_ENABLED)
csharp 2014/06/10 14:07:02 This should probably be join via else with the abo
krstnmnlsn 2014/06/10 22:03:27 Done.
145 SetDWValue(&key, kBeaconAttemptCount, static_cast<DWORD>(0));
146
147 result = SetDWValue(&key, kBeaconState, BLACKLIST_SETUP_RUNNING);
117 ::RegCloseKey(key); 148 ::RegCloseKey(key);
118 149
119 return (result == ERROR_SUCCESS); 150 return (result == ERROR_SUCCESS);
120 } 151 }
121 152
122 bool ResetBeacon() { 153 bool ResetBeacon() {
123 HKEY key = NULL; 154 HKEY key = NULL;
124 DWORD disposition = 0; 155 DWORD disposition = 0;
125 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER, 156 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
126 kRegistryBeaconPath, 157 kRegistryBeaconPath,
127 0, 158 0,
128 NULL, 159 NULL,
129 REG_OPTION_NON_VOLATILE, 160 REG_OPTION_NON_VOLATILE,
130 KEY_QUERY_VALUE | KEY_SET_VALUE, 161 KEY_QUERY_VALUE | KEY_SET_VALUE,
131 NULL, 162 NULL,
132 &key, 163 &key,
133 &disposition); 164 &disposition);
134 if (result != ERROR_SUCCESS) 165 if (result != ERROR_SUCCESS)
135 return false; 166 return false;
136 167
137 DWORD blacklist_state = BLACKLIST_ENABLED; 168 DWORD blacklist_state = BLACKLIST_STATE_MAX;
138 result = ::RegSetValueEx(key, 169 DWORD blacklist_state_size = sizeof(blacklist_state);
139 kBeaconState, 170 DWORD type = 0;
140 0, 171 result = ::RegQueryValueEx(key,
141 REG_DWORD, 172 kBeaconState,
142 reinterpret_cast<LPBYTE>(&blacklist_state), 173 0,
143 sizeof(blacklist_state)); 174 &type,
175 reinterpret_cast<LPBYTE>(&blacklist_state),
176 &blacklist_state_size);
177
178 if (result != ERROR_SUCCESS || type != REG_DWORD) {
179 ::RegCloseKey(key);
180 return false;
181 }
182
183 if (blacklist_state == BLACKLIST_SETUP_RUNNING)
csharp 2014/06/10 14:07:02 Please add a comment explaining why we only reset
krstnmnlsn 2014/06/10 22:03:27 Done.
184 result = SetDWValue(&key, kBeaconState, BLACKLIST_ENABLED);
185
144 ::RegCloseKey(key); 186 ::RegCloseKey(key);
145
146 return (result == ERROR_SUCCESS); 187 return (result == ERROR_SUCCESS);
147 } 188 }
148 189
149 int BlacklistSize() { 190 int BlacklistSize() {
150 int size = -1; 191 int size = -1;
151 while (blacklist::g_troublesome_dlls[++size] != NULL) {} 192 while (blacklist::g_troublesome_dlls[++size] != NULL) {}
152 193
153 return size; 194 return size;
154 } 195 }
155 196
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 274
234 bool Initialize(bool force) { 275 bool Initialize(bool force) {
235 // Check to see that we found the functions we need in ntdll. 276 // Check to see that we found the functions we need in ntdll.
236 if (!InitializeInterceptImports()) 277 if (!InitializeInterceptImports())
237 return false; 278 return false;
238 279
239 // Check to see if this is a non-browser process, abort if so. 280 // Check to see if this is a non-browser process, abort if so.
240 if (IsNonBrowserProcess()) 281 if (IsNonBrowserProcess())
241 return false; 282 return false;
242 283
243 // Check to see if a beacon is present, abort if so. 284 // Check to see if the blacklist beacon is still set to running (indicating a
285 // failure) or disabled and abort if so.
csharp 2014/06/10 14:07:02 nit: disabled -> disabled,
krstnmnlsn 2014/06/10 22:03:27 Done.
244 if (!force && !LeaveSetupBeacon()) 286 if (!force && !LeaveSetupBeacon())
245 return false; 287 return false;
246 288
247 // It is possible for other dlls to have already patched code by now and 289 // It is possible for other dlls to have already patched code by now and
248 // attempting to patch their code might result in crashes. 290 // attempting to patch their code might result in crashes.
249 const bool kRelaxed = false; 291 const bool kRelaxed = false;
250 292
251 // Create a thunk via the appropriate ServiceResolver instance. 293 // Create a thunk via the appropriate ServiceResolver instance.
252 sandbox::ServiceResolverThunk* thunk = GetThunk(kRelaxed); 294 sandbox::ServiceResolverThunk* thunk = GetThunk(kRelaxed);
253 295
254 // Don't try blacklisting on unsupported OS versions. 296 // Don't try blacklisting on unsupported OS versions.
255 if (!thunk) 297 if (!thunk)
256 return false; 298 return false;
257 299
258 // Record that we are starting the thunk setup code.
259 HKEY key = NULL;
260 DWORD disposition = 0;
261 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
262 kRegistryBeaconPath,
263 0,
264 NULL,
265 REG_OPTION_NON_VOLATILE,
266 KEY_QUERY_VALUE | KEY_SET_VALUE,
267 NULL,
268 &key,
269 &disposition);
270 if (result == ERROR_SUCCESS) {
271 DWORD blacklist_state = BLACKLIST_THUNK_SETUP;
272 ::RegSetValueEx(key,
273 kBeaconState,
274 0,
275 REG_DWORD,
276 reinterpret_cast<LPBYTE>(&blacklist_state),
277 sizeof(blacklist_state));
278 } else {
279 key = NULL;
280 }
281
282 BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_thunk_storage); 300 BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_thunk_storage);
283 301
284 // Mark the thunk storage as readable and writeable, since we 302 // Mark the thunk storage as readable and writeable, since we
285 // ready to write to it. 303 // ready to write to it.
286 DWORD old_protect = 0; 304 DWORD old_protect = 0;
287 if (!VirtualProtect(&g_thunk_storage, 305 if (!VirtualProtect(&g_thunk_storage,
288 sizeof(g_thunk_storage), 306 sizeof(g_thunk_storage),
289 PAGE_EXECUTE_READWRITE, 307 PAGE_EXECUTE_READWRITE,
290 &old_protect)) { 308 &old_protect)) {
291 RecordSuccessfulThunkSetup(&key);
292 return false; 309 return false;
293 } 310 }
294 311
295 thunk->AllowLocalPatches(); 312 thunk->AllowLocalPatches();
296 313
297 // We declare this early so it can be used in the 64-bit block below and 314 // We declare this early so it can be used in the 64-bit block below and
298 // still work on 32-bit build when referenced at the end of the function. 315 // still work on 32-bit build when referenced at the end of the function.
299 BOOL page_executable = false; 316 BOOL page_executable = false;
300 317
301 // Replace the default NtMapViewOfSection with our patched version. 318 // Replace the default NtMapViewOfSection with our patched version.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 350
334 // Record if we have initialized the blacklist. 351 // Record if we have initialized the blacklist.
335 g_blacklist_initialized = NT_SUCCESS(ret); 352 g_blacklist_initialized = NT_SUCCESS(ret);
336 353
337 // Mark the thunk storage as executable and prevent any future writes to it. 354 // Mark the thunk storage as executable and prevent any future writes to it.
338 page_executable = page_executable && VirtualProtect(&g_thunk_storage, 355 page_executable = page_executable && VirtualProtect(&g_thunk_storage,
339 sizeof(g_thunk_storage), 356 sizeof(g_thunk_storage),
340 PAGE_EXECUTE_READ, 357 PAGE_EXECUTE_READ,
341 &old_protect); 358 &old_protect);
342 359
343 RecordSuccessfulThunkSetup(&key);
344
345 return NT_SUCCESS(ret) && page_executable; 360 return NT_SUCCESS(ret) && page_executable;
346 } 361 }
347 362
348 } // namespace blacklist 363 } // namespace blacklist
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698