WebAssembly: poison JS object's secrets
authorjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 6 Jan 2018 07:01:21 +0000 (07:01 +0000)
committerjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 6 Jan 2018 07:01:21 +0000 (07:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181339
<rdar://problem/36325001>

Reviewed by Mark Lam.

Source/JavaScriptCore:

Separating WebAssembly's JS objects from their non-JS
implementation means that all interesting information lives
outside of the JS object itself. This patch poisons each JS
object's pointer to non-JS implementation using the poisoning
mechanism and a unique key per JS object type origin.

* runtime/JSCPoison.h:
* wasm/js/JSToWasm.cpp:
(JSC::Wasm::createJSToWasmWrapper): JS -> wasm stores the JS
object in a stack slot when fast TLS is disabled. This requires
that we unpoison the Wasm::Instance.
* wasm/js/JSWebAssemblyCodeBlock.h:
* wasm/js/JSWebAssemblyInstance.h:
(JSC::JSWebAssemblyInstance::offsetOfPoisonedInstance): renamed to
be explicit that the pointer is poisoned.
* wasm/js/JSWebAssemblyMemory.h:
* wasm/js/JSWebAssemblyModule.h:
* wasm/js/JSWebAssemblyTable.h:

Source/WTF:

swapping a poisoned pointer with a non-poisoned one (as is done in
JSWebAssembyMemory::adopt) was missing.

* wtf/Poisoned.h:
(WTF::PoisonedImpl::swap):
(WTF::ConstExprPoisonedPtrTraits::swap):

Tools:

Update tests for swap(Poisoned<k, T>, T*)

* TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WTF/Poisoned.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WTF/PoisonedRef.cpp:
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@226485 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSCPoison.h
Source/JavaScriptCore/wasm/js/JSToWasm.cpp
Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h
Source/WTF/ChangeLog
Source/WTF/wtf/Poisoned.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp
Tools/TestWebKitAPI/Tests/WTF/Poisoned.cpp
Tools/TestWebKitAPI/Tests/WTF/PoisonedRef.cpp

index 1524c39..d57a57e 100644 (file)
@@ -1,3 +1,30 @@
+2018-01-05  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: poison JS object's secrets
+        https://bugs.webkit.org/show_bug.cgi?id=181339
+        <rdar://problem/36325001>
+
+        Reviewed by Mark Lam.
+
+        Separating WebAssembly's JS objects from their non-JS
+        implementation means that all interesting information lives
+        outside of the JS object itself. This patch poisons each JS
+        object's pointer to non-JS implementation using the poisoning
+        mechanism and a unique key per JS object type origin.
+
+        * runtime/JSCPoison.h:
+        * wasm/js/JSToWasm.cpp:
+        (JSC::Wasm::createJSToWasmWrapper): JS -> wasm stores the JS
+        object in a stack slot when fast TLS is disabled. This requires
+        that we unpoison the Wasm::Instance.
+        * wasm/js/JSWebAssemblyCodeBlock.h:
+        * wasm/js/JSWebAssemblyInstance.h:
+        (JSC::JSWebAssemblyInstance::offsetOfPoisonedInstance): renamed to
+        be explicit that the pointer is poisoned.
+        * wasm/js/JSWebAssemblyMemory.h:
+        * wasm/js/JSWebAssemblyModule.h:
+        * wasm/js/JSWebAssemblyTable.h:
+
 2018-01-05  Michael Saboff  <msaboff@apple.com>
 
         Add ability to disable indexed property masking for testing
index 4a1af24..085b438 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,11 @@ namespace JSC {
 
 enum Poison {
     NotPoisoned = 0,
+    JSWebAssemblyCodeBlockPoison,
+    JSWebAssemblyInstancePoison,
+    JSWebAssemblyMemoryPoison,
+    JSWebAssemblyModulePoison,
+    JSWebAssemblyTablePoison,
     TransitionMapPoison,
     WeakImplPoison,
 };
index 31c9c2b..10b46c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -117,7 +117,9 @@ std::unique_ptr<InternalFunction> createJSToWasmWrapper(CompilationContext& comp
         // Wasm::Context*'s instance.
         if (!Context::useFastTLS()) {
             jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmContextInstanceGPR);
-            jit.loadPtr(CCallHelpers::Address(wasmContextInstanceGPR, JSWebAssemblyInstance::offsetOfInstance()), wasmContextInstanceGPR);
+            jit.loadPtr(CCallHelpers::Address(wasmContextInstanceGPR, JSWebAssemblyInstance::offsetOfPoisonedInstance()), wasmContextInstanceGPR);
+            jit.move(CCallHelpers::TrustedImm64(makeConstExprPoison(JSWebAssemblyInstancePoison)), scratchReg);
+            jit.xor64(scratchReg, wasmContextInstanceGPR);
             jsOffset += sizeof(EncodedJSValue);
         }
 
index 77fe12f..e06baa5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "CallLinkInfo.h"
+#include "JSCPoison.h"
 #include "JSCell.h"
 #include "PromiseDeferredTimer.h"
 #include "Structure.h"
@@ -36,6 +37,7 @@
 #include "WasmFormat.h"
 #include "WasmModule.h"
 #include <wtf/Bag.h>
+#include <wtf/Ref.h>
 #include <wtf/Vector.h>
 
 namespace JSC {
@@ -90,7 +92,7 @@ private:
         void finalizeUnconditionally() override;
     };
 
-    Ref<Wasm::CodeBlock> m_codeBlock;
+    PoisonedRef<JSWebAssemblyCodeBlockPoison, Wasm::CodeBlock> m_codeBlock;
     Vector<MacroAssemblerCodeRef> m_wasmToJSExitStubs;
     UnconditionalFinalizer m_unconditionalFinalizer;
     Bag<CallLinkInfo> m_callLinkInfos;
index cbdac04..d25bbcd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "JSCPoison.h"
 #include "JSDestructibleObject.h"
 #include "JSObject.h"
 #include "JSWebAssemblyCodeBlock.h"
 #include "JSWebAssemblyMemory.h"
 #include "JSWebAssemblyTable.h"
 #include "WasmInstance.h"
+#include <wtf/Ref.h>
 
 namespace JSC {
 
@@ -74,7 +76,7 @@ public:
         instance().setTable(makeRef(*table()->table()));
     }
 
-    static size_t offsetOfInstance() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_instance); }
+    static size_t offsetOfPoisonedInstance() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_instance); }
     static size_t offsetOfCallee() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_callee); }
 
 protected:
@@ -86,7 +88,7 @@ protected:
 private:
     JSWebAssemblyModule* module() const { return m_module.get(); }
 
-    Ref<Wasm::Instance> m_instance;
+    PoisonedRef<JSWebAssemblyInstancePoison, Wasm::Instance> m_instance;
 
     WriteBarrier<JSWebAssemblyModule> m_module;
     WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlock;
index e03e7b0..8e12022 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "JSCPoison.h"
 #include "JSDestructibleObject.h"
 #include "JSObject.h"
 #include "WasmMemory.h"
+#include <wtf/Ref.h>
 #include <wtf/RefPtr.h>
 
 namespace JSC {
@@ -65,9 +67,9 @@ private:
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    Ref<Wasm::Memory> m_memory;
+    PoisonedRef<JSWebAssemblyMemoryPoison, Wasm::Memory> m_memory;
     WriteBarrier<JSArrayBuffer> m_bufferWrapper;
-    RefPtr<ArrayBuffer> m_buffer;
+    PoisonedRefPtr<JSWebAssemblyMemoryPoison, ArrayBuffer> m_buffer;
 };
 
 } // namespace JSC
index 8fec6a0..207d03b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "JSCPoison.h"
 #include "JSDestructibleObject.h"
 #include "JSObject.h"
 #include "UnconditionalFinalizer.h"
@@ -34,6 +35,7 @@
 #include <wtf/Bag.h>
 #include <wtf/Expected.h>
 #include <wtf/Forward.h>
+#include <wtf/Ref.h>
 #include <wtf/text/WTFString.h>
 
 namespace JSC {
@@ -79,7 +81,7 @@ private:
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    Ref<Wasm::Module> m_module;
+    PoisonedRef<JSWebAssemblyModulePoison, Wasm::Module> m_module;
     WriteBarrier<SymbolTable> m_exportSymbolTable;
     WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlocks[Wasm::NumberOfMemoryModes];
     WriteBarrier<WebAssemblyToJSCallee> m_callee;
index 4487530..6964158 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "JSCPoison.h"
 #include "JSDestructibleObject.h"
 #include "JSObject.h"
 #include "WasmLimits.h"
@@ -34,6 +35,7 @@
 #include "WebAssemblyWrapperFunction.h"
 #include "WebAssemblyFunction.h"
 #include <wtf/MallocPtr.h>
+#include <wtf/Ref.h>
 
 namespace JSC {
 
@@ -63,7 +65,7 @@ private:
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    Ref<Wasm::Table> m_table;
+    PoisonedRef<JSWebAssemblyTablePoison, Wasm::Table> m_table;
     MallocPtr<WriteBarrier<JSObject>> m_jsFunctions;
 };
 
index ce5989c..dced0b3 100644 (file)
@@ -1,3 +1,18 @@
+2018-01-05  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: poison JS object's secrets
+        https://bugs.webkit.org/show_bug.cgi?id=181339
+        <rdar://problem/36325001>
+
+        Reviewed by Mark Lam.
+
+        swapping a poisoned pointer with a non-poisoned one (as is done in
+        JSWebAssembyMemory::adopt) was missing.
+
+        * wtf/Poisoned.h:
+        (WTF::PoisonedImpl::swap):
+        (WTF::ConstExprPoisonedPtrTraits::swap):
+
 2018-01-05  David Kilzer  <ddkilzer@apple.com>
 
         Re-enable -Wcast-qual in WebCore for Apple ports
index 4460230..1f68d1b 100644 (file)
@@ -182,6 +182,13 @@ public:
         o = t2;
     }
 
+    void swap(T& t2)
+    {
+        T t1 = this->unpoisoned();
+        std::swap(t1, t2);
+        m_poisonedBits = poison(t1);
+    }
+
     template<class U>
     T exchange(U&& newValue)
     {
@@ -212,6 +219,12 @@ inline void swap(PoisonedImpl<K1, k1, T1>& a, PoisonedImpl<K2, k2, T2>& b)
     a.swap(b);
 }
 
+template<typename K1, K1 k1, typename T1>
+inline void swap(PoisonedImpl<K1, k1, T1>& a, T1& b)
+{
+    a.swap(b);
+}
+
 WTF_EXPORT_PRIVATE uintptr_t makePoison();
 
 inline constexpr uintptr_t makeConstExprPoison(uint32_t key)
@@ -241,6 +254,9 @@ struct ConstExprPoisonedPtrTraits {
 
     template<class U> static ALWAYS_INLINE T* exchange(StorageType& ptr, U&& newValue) { return ptr.exchange(newValue); }
 
+    template<typename K1, K1 k1, typename T1>
+    static ALWAYS_INLINE void swap(PoisonedImpl<K1, k1, T1>& a, T1& b) { a.swap(b); }
+
     template<typename K1, K1 k1, typename T1, typename K2, K2 k2, typename T2>
     static ALWAYS_INLINE void swap(PoisonedImpl<K1, k1, T1>& a, PoisonedImpl<K2, k2, T2>& b) { a.swap(b); }
 
@@ -252,5 +268,5 @@ struct ConstExprPoisonedPtrTraits {
 using WTF::ConstExprPoisoned;
 using WTF::Poisoned;
 using WTF::PoisonedBits;
+using WTF::makeConstExprPoison;
 using WTF::makePoison;
-
index ae6d6a1..a75f22b 100644 (file)
@@ -1,3 +1,20 @@
+2018-01-05  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: poison JS object's secrets
+        https://bugs.webkit.org/show_bug.cgi?id=181339
+        <rdar://problem/36325001>
+
+        Reviewed by Mark Lam.
+
+        Update tests for swap(Poisoned<k, T>, T*)
+
+        * TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WTF/Poisoned.cpp:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WTF/PoisonedRef.cpp:
+        (TestWebKitAPI::TEST):
+
 2018-01-05  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         REGRESSION(r226396) DataInteractionTests: ContentEditableToContentEditable and ContentEditableToTextarea are failing
index 3110eb5..153d974 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -337,6 +337,30 @@ TEST(WTF_ConstExprPoisoned, Swap)
         ASSERT_TRUE(p1.bits() == p3.bits());
         ASSERT_TRUE(p2.bits() != p4.bits());
     }
+
+    {
+        ConstExprPoisoned<PoisonA, RefLogger*> p1(&a);
+        RefLogger* p2(&b);
+        ASSERT_EQ(&a, p1.unpoisoned());
+        ASSERT_EQ(&b, p2);
+        swap(p1, p2);
+        ASSERT_EQ(&b, p1.unpoisoned());
+        ASSERT_EQ(&a, p2);
+
+        ASSERT_TRUE(p1.bits() != bitwise_cast<uintptr_t>(p2));
+    }
+
+    {
+        ConstExprPoisoned<PoisonA, RefLogger*> p1(&a);
+        RefLogger* p2(&b);
+        ASSERT_EQ(&a, p1.unpoisoned());
+        ASSERT_EQ(&b, p2);
+        p1.swap(p2);
+        ASSERT_EQ(&b, p1.unpoisoned());
+        ASSERT_EQ(&a, p2);
+
+        ASSERT_TRUE(p1.bits() != bitwise_cast<uintptr_t>(p2));
+    }
 }
 
 static ConstExprPoisoned<PoisonA, RefLogger*> poisonedPtrFoo(RefLogger& logger)
index 8b14233..1c52155 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -376,6 +376,32 @@ TEST(WTF_Poisoned, Swap)
         ASSERT_TRUE(p2.bits() != p4.bits());
 #endif
     }
+
+#if ENABLE(MIXED_POISON)
+    {
+        Poisoned<g_testPoisonA, RefLogger*> p1(&a);
+        RefLogger* p2(&b);
+        ASSERT_EQ(&a, p1.unpoisoned());
+        ASSERT_EQ(&b, p2);
+        swap(p1, p2);
+        ASSERT_EQ(&b, p1.unpoisoned());
+        ASSERT_EQ(&a, p2);
+
+        ASSERT_TRUE(p1.bits() != bitwise_cast<uintptr_t>(p2));
+    }
+
+    {
+        Poisoned<g_testPoisonA, RefLogger*> p1(&a);
+        RefLogger* p2(&b);
+        ASSERT_EQ(&a, p1.unpoisoned());
+        ASSERT_EQ(&b, p2);
+        p1.swap(p2);
+        ASSERT_EQ(&b, p1.unpoisoned());
+        ASSERT_EQ(&a, p2);
+
+        ASSERT_TRUE(p1.bits() != bitwise_cast<uintptr_t>(p2));
+    }
+#endif
 }
 
 static Poisoned<g_testPoisonA, RefLogger*> poisonedPtrFoo(RefLogger& logger)
index 9b09f15..a9f4195 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -194,6 +194,32 @@ TEST(WTF_PoisonedRef, Swap)
         log() << "| ";
     }
     EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
+
+    {
+        PoisonedRef<PoisonF, RefLogger> p1(a);
+        Ref<RefLogger> p2(b);
+        log() << "| ";
+        EXPECT_EQ(&a, p1.ptr());
+        EXPECT_EQ(&b, p2.ptr());
+        swap(p1, p2);
+        EXPECT_EQ(&b, p1.ptr());
+        EXPECT_EQ(&a, p2.ptr());
+        log() << "| ";
+    }
+    EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
+
+    {
+        PoisonedRef<PoisonF, RefLogger> p1(a);
+        Ref<RefLogger> p2(b);
+        log() << "| ";
+        EXPECT_EQ(&a, p1.ptr());
+        EXPECT_EQ(&b, p2.ptr());
+        p1.swap(p2);
+        EXPECT_EQ(&b, p1.ptr());
+        EXPECT_EQ(&a, p2.ptr());
+        log() << "| ";
+    }
+    EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
 }
 
 struct PoisonedRefCheckingRefLogger : RefLogger {