mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1460989 - Hold system linker lock while modifying debug map. r=glandium, a=RyanVM
When we modify the debug map, we could be racing with the system linker, either when we modify the entries or when we change page protection flags. To fix the race, we need to take the system linker's internal lock when we perform any kind of modification on the debug map. One way to hold the system linker lock is to call dl_iterate_phdr, and perform our actions inside the callback, which is invoked with the lock being held. However, dl_iterate_phdr is only present on Android 5.0+, and even then, dl_iterate_phdr is only protected by the linker lock on Android 6.0+. This means that with this patch, we can only safely modify the debug map on Android 6.0+, which I think is acceptable for an operation that only benefits a debugger. MozReview-Commit-ID: BowBEO8tu8Z --HG-- extra : amend_source : 837631dfc2ef17b24ffe5778bcb70dc29b7dfc66
This commit is contained in:
parent
fbbbabafe4
commit
9d10605784
@ -26,6 +26,7 @@ Atomic<size_t, ReleaseAcquire> gPageSize;
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/system_properties.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <android/api-level.h>
|
||||
@ -311,6 +312,56 @@ LeafName(const char *path)
|
||||
return path;
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
/**
|
||||
* Return the current Android version, or 0 on failure.
|
||||
*/
|
||||
int
|
||||
GetAndroidSDKVersion() {
|
||||
static int version = 0;
|
||||
if (version) {
|
||||
return version;
|
||||
}
|
||||
|
||||
char version_string[PROP_VALUE_MAX] = {'\0'};
|
||||
int len = __system_property_get("ro.build.version.sdk", version_string);
|
||||
if (len) {
|
||||
version = static_cast<int>(strtol(version_string, nullptr, 10));
|
||||
}
|
||||
return version;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Run the given lambda while holding the internal lock of the system linker.
|
||||
* To take the lock, we call the system dl_iterate_phdr and invoke the lambda
|
||||
* from the callback, which is called while the lock is held. Return true on
|
||||
* success.
|
||||
*/
|
||||
template<class Lambda>
|
||||
static bool
|
||||
RunWithSystemLinkerLock(Lambda&& aLambda) {
|
||||
if (!dl_iterate_phdr) {
|
||||
// No dl_iterate_phdr support.
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
if (GetAndroidSDKVersion() < 23) {
|
||||
// dl_iterate_phdr is _not_ protected by a lock on Android < 23.
|
||||
// Also return false here if we failed to get the version.
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
dl_iterate_phdr([] (dl_phdr_info*, size_t, void* lambda) -> int {
|
||||
(*static_cast<Lambda*>(lambda))();
|
||||
// Return 1 to stop iterating.
|
||||
return 1;
|
||||
}, &aLambda);
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* Anonymous namespace */
|
||||
|
||||
/**
|
||||
@ -576,7 +627,9 @@ ElfLoader::Register(CustomElf *handle)
|
||||
{
|
||||
Register(static_cast<LibHandle *>(handle));
|
||||
if (dbg) {
|
||||
dbg.Add(handle);
|
||||
// We could race with the system linker when modifying the debug map, so
|
||||
// only do so while holding the system linker's internal lock.
|
||||
RunWithSystemLinkerLock([this, handle] { dbg.Add(handle); });
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,7 +656,9 @@ ElfLoader::Forget(CustomElf *handle)
|
||||
{
|
||||
Forget(static_cast<LibHandle *>(handle));
|
||||
if (dbg) {
|
||||
dbg.Remove(handle);
|
||||
// We could race with the system linker when modifying the debug map, so
|
||||
// only do so while holding the system linker's internal lock.
|
||||
RunWithSystemLinkerLock([this, handle] { dbg.Remove(handle); });
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user