Title: [213599] trunk/Source/_javascript_Core
Revision
213599
Author
[email protected]
Date
2017-03-08 14:50:51 -0800 (Wed, 08 Mar 2017)

Log Message

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:

Modified Paths

Diff

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)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to