Close a window for a race with the system linker
Lock globals at the head of Add/DelEntryImpl() callback handlers.
The crazy linker exports updates to _r_debug pages to the UI thread
if a callback poster function has been supplied. At the time the
callback is posted, the crazy linker holds the globals lock, used to
prevent other threads from loading libraries (in particular through
::dlopen(), used for system libraries). When the callback is
received on a different thread the receiving code needs to reacquire
the lock.
Make the globals lock reentrant.
If there is no callback poster function then the updates to _r_debug
pages happen immediately on the current thread. Here the globals
lock is already held. Reentrancy ensures that we do not deadlock
in that case.
Fix potential inaccuracy when looking for the page to mprotect.
The addresses checked for writability are currently the start of the
object being modified. This is 12 or 16 bytes (on arm, 24 or 32
bytes on arm64) below the address that will actually be written, and
not guaranteed to be in the same memory page where the object
crosses a page boundary.
Workround for races with the system linker over _r_debug protections.
There is no way to safely and accurately sense whether _r_debug is
in a readonly page -- we might read while the system linker is in
the process of writing to it, and conclude that it is not readonly
when it is. Similarly, we may set it read/write, update pointers,
and then set it readonly between the system linker setting it to
read/write and updating pointers. To work round this, we always map
it to read/write, no matter its apparent initial state, and never
map it back to readonly. This may leave a small security hole, but
it is better than the alternatives (typically, a crash).
BUG=450659,458346
Review URL: https://codereview.chromium.org/
937813002
Cr-Commit-Position: refs/heads/master@{#317314}