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

Side by Side Diff: third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp

Issue 937813002: Close a window for a race with the system linker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update for more review comments Created 5 years, 10 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 | « third_party/android_crazy_linker/src/src/crazy_linker_rdebug.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 "crazy_linker_rdebug.h" 5 #include "crazy_linker_rdebug.h"
6 6
7 #include <elf.h> 7 #include <elf.h>
8 #include <inttypes.h> 8 #include <inttypes.h>
9 #include <pthread.h> 9 #include <pthread.h>
10 #include <sys/mman.h> 10 #include <sys/mman.h>
11 #include <unistd.h> 11 #include <unistd.h>
12 12
13 #include "crazy_linker_debug.h" 13 #include "crazy_linker_debug.h"
14 #include "crazy_linker_globals.h"
14 #include "crazy_linker_proc_maps.h" 15 #include "crazy_linker_proc_maps.h"
15 #include "crazy_linker_util.h" 16 #include "crazy_linker_util.h"
16 #include "crazy_linker_system.h" 17 #include "crazy_linker_system.h"
17 #include "elf_traits.h" 18 #include "elf_traits.h"
18 19
19 namespace crazy { 20 namespace crazy {
20 21
21 namespace { 22 namespace {
22 23
23 // Find the full path of the current executable. On success return true 24 // Find the full path of the current executable. On success return true
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 (void*)*dynamic_size); 149 (void*)*dynamic_size);
149 return true; 150 return true;
150 } 151 }
151 152
152 LOG("%s: Executable is not mapped in current process.\n", __FUNCTION__); 153 LOG("%s: Executable is not mapped in current process.\n", __FUNCTION__);
153 return false; 154 return false;
154 } 155 }
155 156
156 // Helper class to temporarily remap a page to readable+writable until 157 // Helper class to temporarily remap a page to readable+writable until
157 // scope exit. 158 // scope exit.
158 class ScopedPageMapper { 159 class ScopedPageReadWriteRemapper {
159 public: 160 public:
160 ScopedPageMapper() : page_address_(0), page_prot_(0) {} 161 ScopedPageReadWriteRemapper(void* address);
161 void MapReadWrite(void* address); 162 ~ScopedPageReadWriteRemapper();
162 ~ScopedPageMapper(); 163
164 // Releases the page so that the destructor does not undo the remapping.
165 void Release();
163 166
164 private: 167 private:
165 static const uintptr_t kPageSize = 4096; 168 static const uintptr_t kPageSize = 4096;
166 uintptr_t page_address_; 169 uintptr_t page_address_;
167 int page_prot_; 170 int page_prot_;
168 }; 171 };
169 172
170 void ScopedPageMapper::MapReadWrite(void* address) { 173 ScopedPageReadWriteRemapper::ScopedPageReadWriteRemapper(void* address) {
171 page_address_ = reinterpret_cast<uintptr_t>(address) & ~(kPageSize - 1); 174 page_address_ = reinterpret_cast<uintptr_t>(address) & ~(kPageSize - 1);
172 page_prot_ = 0; 175 page_prot_ = 0;
173 if (!FindProtectionFlagsForAddress(address, &page_prot_) || 176 if (!FindProtectionFlagsForAddress(address, &page_prot_)) {
174 (page_prot_ & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) { 177 LOG("Could not find protection flags for %p\n", address);
175 // If the address is invalid, or if the page is already read+write,
176 // no need to do anything here.
177 page_address_ = 0; 178 page_address_ = 0;
178 return; 179 return;
179 } 180 }
181
182 // Note: page_prot_ may already indicate read/write, but because of
183 // possible races with the system linker we cannot be confident that
184 // this is reliable. So we always set read/write here.
185 //
186 // See commentary in WriteLinkMapField for more.
180 int new_page_prot = page_prot_ | PROT_READ | PROT_WRITE; 187 int new_page_prot = page_prot_ | PROT_READ | PROT_WRITE;
181 int ret = mprotect( 188 int ret = mprotect(
182 reinterpret_cast<void*>(page_address_), kPageSize, new_page_prot); 189 reinterpret_cast<void*>(page_address_), kPageSize, new_page_prot);
183 if (ret < 0) { 190 if (ret < 0) {
184 LOG_ERRNO("Could not remap page to read/write"); 191 LOG_ERRNO("Could not remap page to read/write");
185 page_address_ = 0; 192 page_address_ = 0;
186 } 193 }
187 } 194 }
188 195
189 ScopedPageMapper::~ScopedPageMapper() { 196 ScopedPageReadWriteRemapper::~ScopedPageReadWriteRemapper() {
190 if (page_address_) { 197 if (page_address_) {
191 int ret = 198 int ret =
192 mprotect(reinterpret_cast<void*>(page_address_), kPageSize, page_prot_); 199 mprotect(reinterpret_cast<void*>(page_address_), kPageSize, page_prot_);
193 if (ret < 0) 200 if (ret < 0)
194 LOG_ERRNO("Could not remap page to old protection flags"); 201 LOG_ERRNO("Could not remap page to old protection flags");
195 } 202 }
196 } 203 }
197 204
205 void ScopedPageReadWriteRemapper::Release() {
206 page_address_ = 0;
207 page_prot_ = 0;
208 }
209
198 } // namespace 210 } // namespace
199 211
200 bool RDebug::Init() { 212 bool RDebug::Init() {
201 // The address of '_r_debug' is in the DT_DEBUG entry of the current 213 // The address of '_r_debug' is in the DT_DEBUG entry of the current
202 // executable. 214 // executable.
203 init_ = true; 215 init_ = true;
204 216
205 size_t dynamic_addr = 0; 217 size_t dynamic_addr = 0;
206 size_t dynamic_size = 0; 218 size_t dynamic_size = 0;
207 String path; 219 String path;
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 LOG("%s: Posted for later execution, runnable=%p\n", __FUNCTION__, runnable); 387 LOG("%s: Posted for later execution, runnable=%p\n", __FUNCTION__, runnable);
376 388
377 if (is_blocking) { 389 if (is_blocking) {
378 RDebugRunnable::WaitForCallback(runnable); 390 RDebugRunnable::WaitForCallback(runnable);
379 LOG("%s: Completed execution, runnable=%p\n", __FUNCTION__, runnable); 391 LOG("%s: Completed execution, runnable=%p\n", __FUNCTION__, runnable);
380 } 392 }
381 393
382 return true; 394 return true;
383 } 395 }
384 396
397 // Helper function for AddEntryImpl and DelEntryImpl.
398 // Sets *link_pointer to entry. link_pointer is either an 'l_prev' or an
399 // 'l_next' field in a neighbouring linkmap_t. If link_pointer is in a
400 // page that is mapped readonly, the page is remapped to be writable before
401 // assignment.
402 void RDebug::WriteLinkMapField(link_map_t** link_pointer, link_map_t* entry) {
403 ScopedPageReadWriteRemapper mapper(link_pointer);
404 LOG("%s: Remapped page for %p for read/write\n", __FUNCTION__, link_pointer);
405
406 *link_pointer = entry;
407
408 // We always mprotect the page containing link_pointer to read/write,
409 // then write the entry. The page may already be read/write, but on
410 // recent Android release is most likely readonly. Because of the way
411 // the system linker operates we cannot tell with certainty what its
412 // correct setting should be.
413 //
414 // Now, we always leave the page read/write. Here is why. If we set it
415 // back to readonly at the point between where the system linker sets
416 // it to read/write and where it writes to the address, this will cause
417 // the system linker to crash. Clearly that is undesirable. From
418 // observations this occurs most frequently on the gpu process.
419 //
420 // TODO(simonb): Revisit this, details in:
421 // https://code.google.com/p/chromium/issues/detail?id=450659
422 // https://code.google.com/p/chromium/issues/detail?id=458346
423 mapper.Release();
424 LOG("%s: Released mapper, leaving page read/write\n", __FUNCTION__);
425 }
426
385 void RDebug::AddEntryImpl(link_map_t* entry) { 427 void RDebug::AddEntryImpl(link_map_t* entry) {
428 ScopedGlobalLock lock;
386 LOG("%s: Adding: %s\n", __FUNCTION__, entry->l_name); 429 LOG("%s: Adding: %s\n", __FUNCTION__, entry->l_name);
387 if (!init_) 430 if (!init_)
388 Init(); 431 Init();
389 432
390 if (!r_debug_) { 433 if (!r_debug_) {
391 LOG("%s: Nothing to do\n", __FUNCTION__); 434 LOG("%s: Nothing to do\n", __FUNCTION__);
392 return; 435 return;
393 } 436 }
394 437
395 // Tell GDB the list is going to be modified. 438 // Tell GDB the list is going to be modified.
(...skipping 30 matching lines...) Expand all
426 link_map_t* after = before->l_next; 469 link_map_t* after = before->l_next;
427 470
428 // Prepare the new entry. 471 // Prepare the new entry.
429 entry->l_prev = before; 472 entry->l_prev = before;
430 entry->l_next = after; 473 entry->l_next = after;
431 474
432 // IMPORTANT: Before modifying the previous and next entries in the 475 // IMPORTANT: Before modifying the previous and next entries in the
433 // list, ensure that they are writable. This avoids crashing when 476 // list, ensure that they are writable. This avoids crashing when
434 // updating the 'l_prev' or 'l_next' fields of a system linker entry, 477 // updating the 'l_prev' or 'l_next' fields of a system linker entry,
435 // which are mapped read-only. 478 // which are mapped read-only.
436 { 479 WriteLinkMapField(&before->l_next, entry);
437 ScopedPageMapper mapper; 480 WriteLinkMapField(&after->l_prev, entry);
438 if (readonly_entries_)
439 mapper.MapReadWrite(before);
440 before->l_next = entry;
441 }
442
443 {
444 ScopedPageMapper mapper;
445 if (readonly_entries_)
446 mapper.MapReadWrite(after);
447 after->l_prev = entry;
448 }
449 481
450 // Tell GDB that the list modification has completed. 482 // Tell GDB that the list modification has completed.
451 r_debug_->r_state = RT_CONSISTENT; 483 r_debug_->r_state = RT_CONSISTENT;
452 r_debug_->r_brk(); 484 r_debug_->r_brk();
453 } 485 }
454 486
455 void RDebug::DelEntryImpl(link_map_t* entry) { 487 void RDebug::DelEntryImpl(link_map_t* entry) {
488 ScopedGlobalLock lock;
456 LOG("%s: Deleting: %s\n", __FUNCTION__, entry->l_name); 489 LOG("%s: Deleting: %s\n", __FUNCTION__, entry->l_name);
457 if (!r_debug_) 490 if (!r_debug_)
458 return; 491 return;
459 492
460 // Tell GDB the list is going to be modified. 493 // Tell GDB the list is going to be modified.
461 r_debug_->r_state = RT_DELETE; 494 r_debug_->r_state = RT_DELETE;
462 r_debug_->r_brk(); 495 r_debug_->r_brk();
463 496
464 // IMPORTANT: Before modifying the previous and next entries in the 497 // IMPORTANT: Before modifying the previous and next entries in the
465 // list, ensure that they are writable. See comment above for more 498 // list, ensure that they are writable. See comment above for more
466 // details. 499 // details.
467 if (entry->l_prev) { 500 if (entry->l_prev)
468 ScopedPageMapper mapper; 501 WriteLinkMapField(&entry->l_prev->l_next, entry->l_next);
469 if (readonly_entries_) 502 if (entry->l_next)
470 mapper.MapReadWrite(entry->l_prev); 503 WriteLinkMapField(&entry->l_next->l_prev, entry->l_prev);
471 entry->l_prev->l_next = entry->l_next;
472 }
473
474 if (entry->l_next) {
475 ScopedPageMapper mapper;
476 if (readonly_entries_)
477 mapper.MapReadWrite(entry->l_next);
478 entry->l_next->l_prev = entry->l_prev;
479 }
480 504
481 if (r_debug_->r_map == entry) 505 if (r_debug_->r_map == entry)
482 r_debug_->r_map = entry->l_next; 506 r_debug_->r_map = entry->l_next;
483 507
484 entry->l_prev = NULL; 508 entry->l_prev = NULL;
485 entry->l_next = NULL; 509 entry->l_next = NULL;
486 510
487 // Tell GDB the list modification has completed. 511 // Tell GDB the list modification has completed.
488 r_debug_->r_state = RT_CONSISTENT; 512 r_debug_->r_state = RT_CONSISTENT;
489 r_debug_->r_brk(); 513 r_debug_->r_brk();
490 } 514 }
491 515
492 } // namespace crazy 516 } // namespace crazy
OLDNEW
« no previous file with comments | « third_party/android_crazy_linker/src/src/crazy_linker_rdebug.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698