Modified: trunk/Source/_javascript_Core/ChangeLog (213598 => 213599)
--- trunk/Source/_javascript_Core/ChangeLog 2017-03-08 22:44:42 UTC (rev 213598)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-03-08 22:50:51 UTC (rev 213599)
@@ -1,3 +1,23 @@
+2017-03-08 Keith Miller <[email protected]>
+
+ WebAssembly: Make OOB for fast memory do an extra safety check by ensuring the faulting address is in the range we allocated for fast memory
+ https://bugs.webkit.org/show_bug.cgi?id=169290
+
+ Reviewed by Saam Barati.
+
+ This patch adds an extra sanity check by ensuring that the the memory address we faulting trying to load is in range
+ of some wasm fast memory.
+
+ * wasm/WasmFaultSignalHandler.cpp:
+ (JSC::Wasm::trapHandler):
+ (JSC::Wasm::enableFastMemory):
+ * wasm/WasmMemory.cpp:
+ (JSC::Wasm::activeFastMemories):
+ (JSC::Wasm::viewActiveFastMemories):
+ (JSC::Wasm::tryGetFastMemory):
+ (JSC::Wasm::releaseFastMemory):
+ * wasm/WasmMemory.h:
+
2017-03-07 Dean Jackson <[email protected]>
Some platforms won't be able to create a GPUDevice
Modified: trunk/Source/_javascript_Core/wasm/WasmFaultSignalHandler.cpp (213598 => 213599)
--- trunk/Source/_javascript_Core/wasm/WasmFaultSignalHandler.cpp 2017-03-08 22:44:42 UTC (rev 213598)
+++ trunk/Source/_javascript_Core/wasm/WasmFaultSignalHandler.cpp 2017-03-08 22:50:51 UTC (rev 213599)
@@ -31,6 +31,7 @@
#include "ExecutableAllocator.h"
#include "VM.h"
#include "WasmExceptionType.h"
+#include "WasmMemory.h"
#include <signal.h>
#include <wtf/Lock.h>
@@ -79,7 +80,7 @@
#endif
-static void trapHandler(int signal, siginfo_t*, void* ucontext)
+static void trapHandler(int signal, siginfo_t* sigInfo, void* ucontext)
{
mcontext_t& context = static_cast<ucontext_t*>(ucontext)->uc_mcontext;
void* faultingInstruction = reinterpret_cast<void*>(InstructionPointerGPR);
@@ -91,25 +92,42 @@
if (reinterpret_cast<void*>(startOfFixedExecutableMemoryPool) <= faultingInstruction
&& faultingInstruction < reinterpret_cast<void*>(endOfFixedExecutableMemoryPool)) {
- LockHolder locker(codeLocationsLock);
- for (auto range : codeLocations.get()) {
- VM* vm;
- void* start;
- void* end;
- std::tie(vm, start, end) = range;
- dataLogLnIf(verbose, "function start: ", RawPointer(start), " end: ", RawPointer(end));
- if (start <= faultingInstruction && faultingInstruction < end) {
- dataLogLnIf(verbose, "found match");
- MacroAssemblerCodeRef exceptionStub = vm->jitStubs->existingCTIStub(throwExceptionFromWasmThunkGenerator);
- // If for whatever reason we don't have a stub then we should just treat this like a regular crash.
- if (!exceptionStub)
+ bool faultedInActiveFastMemory = false;
+ {
+ void* faultingAddress = sigInfo->si_addr;
+ dataLogLnIf(verbose, "checking faulting address: ", RawPointer(faultingAddress), " is in an active fast memory");
+ LockHolder locker(memoryLock);
+ auto& activeFastMemories = viewActiveFastMemories(locker);
+ for (void* activeMemory : activeFastMemories) {
+ dataLogLnIf(verbose, "checking fast memory at: ", RawPointer(activeMemory));
+ if (activeMemory <= faultingAddress && faultingAddress < static_cast<char*>(activeMemory) + fastMemoryMappedBytes) {
+ faultedInActiveFastMemory = true;
break;
- dataLogLnIf(verbose, "found stub: ", RawPointer(exceptionStub.code().executableAddress()));
- FirstArgumentGPR = static_cast<uint64_t>(ExceptionType::OutOfBoundsMemoryAccess);
- InstructionPointerGPR = reinterpret_cast<uint64_t>(exceptionStub.code().executableAddress());
- return;
+ }
}
}
+ if (faultedInActiveFastMemory) {
+ dataLogLnIf(verbose, "found active fast memory for faulting address");
+ LockHolder locker(codeLocationsLock);
+ for (auto range : codeLocations.get()) {
+ VM* vm;
+ void* start;
+ void* end;
+ std::tie(vm, start, end) = range;
+ dataLogLnIf(verbose, "function start: ", RawPointer(start), " end: ", RawPointer(end));
+ if (start <= faultingInstruction && faultingInstruction < end) {
+ dataLogLnIf(verbose, "found match");
+ MacroAssemblerCodeRef exceptionStub = vm->jitStubs->existingCTIStub(throwExceptionFromWasmThunkGenerator);
+ // If for whatever reason we don't have a stub then we should just treat this like a regular crash.
+ if (!exceptionStub)
+ break;
+ dataLogLnIf(verbose, "found stub: ", RawPointer(exceptionStub.code().executableAddress()));
+ FirstArgumentGPR = static_cast<uint64_t>(ExceptionType::OutOfBoundsMemoryAccess);
+ InstructionPointerGPR = reinterpret_cast<uint64_t>(exceptionStub.code().executableAddress());
+ return;
+ }
+ }
+ }
}
// Since we only use fast memory in processes we control, if we restore we will just fall back to the default handler.
@@ -159,10 +177,10 @@
// Thus, we must not fail in the following attempts.
int ret = 0;
ret = sigaction(SIGBUS, &action, &oldSigBusHandler);
- ASSERT_UNUSED(ret, !ret);
+ RELEASE_ASSERT(!ret);
ret = sigaction(SIGSEGV, &action, &oldSigSegvHandler);
- ASSERT_UNUSED(ret, !ret);
+ RELEASE_ASSERT(!ret);
codeLocations.construct();
fastHandlerInstalled = true;
Modified: trunk/Source/_javascript_Core/wasm/WasmMemory.cpp (213598 => 213599)
--- trunk/Source/_javascript_Core/wasm/WasmMemory.cpp 2017-03-08 22:44:42 UTC (rev 213598)
+++ trunk/Source/_javascript_Core/wasm/WasmMemory.cpp 2017-03-08 22:50:51 UTC (rev 213599)
@@ -65,12 +65,9 @@
return lastAllocatedMemoryMode;
}
-static_assert(sizeof(uint64_t) == sizeof(size_t), "We rely on allowing the maximum size of Memory we map to be 2^33 which is larger than fits in a 32-bit integer that we'd pass to mprotect if this didn't hold.");
-
-static const size_t fastMemoryMappedBytes = (static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 1) * 2; // pointer max + offset max. This is all we need since a load straddling readable memory will trap.
static const unsigned maxFastMemories = 4;
static unsigned allocatedFastMemories { 0 };
-static StaticLock memoryLock;
+StaticLock memoryLock;
inline Deque<void*, maxFastMemories>& availableFastMemories(const LockHolder&)
{
static NeverDestroyed<Deque<void*, maxFastMemories>> availableFastMemories;
@@ -77,6 +74,17 @@
return availableFastMemories;
}
+inline HashSet<void*>& activeFastMemories(const LockHolder&)
+{
+ static NeverDestroyed<HashSet<void*>> activeFastMemories;
+ return activeFastMemories;
+}
+
+const HashSet<void*>& viewActiveFastMemories(const LockHolder& locker)
+{
+ return activeFastMemories(locker);
+}
+
inline bool tryGetFastMemory(VM& vm, void*& memory, size_t& mappedCapacity, Memory::Mode& mode)
{
// We might GC here so we should be holding the API lock.
@@ -95,6 +103,8 @@
LockHolder locker(memoryLock);
if (!availableFastMemories(locker).isEmpty()) {
memory = availableFastMemories(locker).takeFirst();
+ auto result = activeFastMemories(locker).add(memory);
+ ASSERT_UNUSED(result, result.isNewEntry);
mappedCapacity = fastMemoryMappedBytes;
mode = Memory::Signaling;
return true;
@@ -117,6 +127,9 @@
mappedCapacity = fastMemoryMappedBytes;
mode = Memory::Signaling;
allocatedFastMemories++;
+ LockHolder locker(memoryLock);
+ auto result = activeFastMemories(locker).add(memory);
+ ASSERT_UNUSED(result, result.isNewEntry);
}
return memory;
}
@@ -134,6 +147,8 @@
CRASH();
LockHolder locker(memoryLock);
+ bool result = activeFastMemories(locker).remove(memory);
+ ASSERT_UNUSED(result, result);
ASSERT(availableFastMemories(locker).size() < allocatedFastMemories);
availableFastMemories(locker).append(memory);
memory = nullptr;
Modified: trunk/Source/_javascript_Core/wasm/WasmMemory.h (213598 => 213599)
--- trunk/Source/_javascript_Core/wasm/WasmMemory.h 2017-03-08 22:44:42 UTC (rev 213598)
+++ trunk/Source/_javascript_Core/wasm/WasmMemory.h 2017-03-08 22:50:51 UTC (rev 213599)
@@ -29,6 +29,7 @@
#include "WasmPageCount.h"
+#include <wtf/HashSet.h>
#include <wtf/Optional.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
@@ -93,6 +94,12 @@
Mode m_mode { Mode::BoundsChecking };
};
+static_assert(sizeof(uint64_t) == sizeof(size_t), "We rely on allowing the maximum size of Memory we map to be 2^33 which is larger than fits in a 32-bit integer that we'd pass to mprotect if this didn't hold.");
+
+const size_t fastMemoryMappedBytes = (static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 1) * 2; // pointer max + offset max. This is all we need since a load straddling readable memory will trap.
+extern StaticLock memoryLock;
+const HashSet<void*>& viewActiveFastMemories(const LockHolder&);
+
} } // namespace JSC::Wasm
#endif // ENABLE(WEBASSEMLY)