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:
Jim Chen 2018-06-15 04:24:10 -04:00
parent fbbbabafe4
commit 9d10605784

View File

@ -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); });
}
}