Title: [223670] branches/safari-604-branch/Source/_javascript_Core
Revision
223670
Author
[email protected]
Date
2017-10-18 22:14:44 -0700 (Wed, 18 Oct 2017)

Log Message

Cherry-pick r223409. rdar://problem/34792148

Modified Paths

Diff

Modified: branches/safari-604-branch/Source/_javascript_Core/ChangeLog (223669 => 223670)


--- branches/safari-604-branch/Source/_javascript_Core/ChangeLog	2017-10-19 05:14:42 UTC (rev 223669)
+++ branches/safari-604-branch/Source/_javascript_Core/ChangeLog	2017-10-19 05:14:44 UTC (rev 223670)
@@ -1,5 +1,43 @@
 2017-10-18  Jason Marcell  <[email protected]>
 
+        Cherry-pick r223409. rdar://problem/34792148
+
+    2017-10-16  JF Bastien  <[email protected]>
+
+            JSRunLoopTimer: reduce likely race when used improperly
+            https://bugs.webkit.org/show_bug.cgi?id=178298
+            <rdar://problem/32899816>
+
+            Reviewed by Saam Barati.
+
+            If an API user sets a timer on JSRunLoopTimer, and then racily
+            destroys the JSRunLoopTimer while the timer is firing then it's
+            possible for timerDidFire to cause a use-after-free and / or crash
+            because e.g. m_apiLock becomes a nullptr while timerDidFire is
+            executing. That results from an invalid use of JSRunLoopTimer, but
+            we should try to be more resilient for that type of misuse because
+            it's not necessarily easy to catch by inspection.
+
+            With this change the only remaining race is if the timer fires,
+            and then only timerDidFire's prologue executes, but not the load
+            of the m_apiLock pointer from `this`. It's a much smaller race.
+
+            Separately, I'll reach out to API users who are seemingly misusing
+            the API.
+
+            * runtime/JSRunLoopTimer.cpp:
+            (JSC::JSRunLoopTimer::timerDidFire): put m_apiLock on the stack,
+            and checks for nullptr. This prevents loading it twice off of
+            `this` and turns a nullptr deref into "just" a use-after-free.
+            (JSC::JSRunLoopTimer::~JSRunLoopTimer): acquire m_apiLock before
+            calling m_vm->unregisterRunLoopTimer(this), which in turn does
+            CFRunLoopRemoveTimer / CFRunLoopTimerInvalidate. This prevents
+            timerDidFire from doing much while the timers are un-registered.
+            ~JSRunLoopTimer also needs to set m_apiLock to nullptr before
+            releasing the lock, so it needs its own local copy.
+
+2017-10-18  Jason Marcell  <[email protected]>
+
         Cherry-pick r223614. rdar://problem/34920288
 
     2017-10-18  Mark Lam  <[email protected]>

Modified: branches/safari-604-branch/Source/_javascript_Core/runtime/JSRunLoopTimer.cpp (223669 => 223670)


--- branches/safari-604-branch/Source/_javascript_Core/runtime/JSRunLoopTimer.cpp	2017-10-19 05:14:42 UTC (rev 223669)
+++ branches/safari-604-branch/Source/_javascript_Core/runtime/JSRunLoopTimer.cpp	2017-10-19 05:14:44 UTC (rev 223670)
@@ -40,6 +40,8 @@
 #include <wtf/glib/RunLoopSourcePriority.h>
 #endif
 
+#include <mutex>
+
 namespace JSC {
 
 const Seconds JSRunLoopTimer::s_decade { 60 * 60 * 24 * 365 * 10 };
@@ -46,21 +48,20 @@
 
 void JSRunLoopTimer::timerDidFire()
 {
-    m_apiLock->lock();
+    JSLock* apiLock = m_apiLock.get();
+    if (!apiLock) {
+        // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed.
+        return;
+    }
 
-    RefPtr<VM> vm = m_apiLock->vm();
+    std::lock_guard<JSLock> lock(*apiLock);
+    RefPtr<VM> vm = apiLock->vm();
     if (!vm) {
         // The VM has been destroyed, so we should just give up.
-        m_apiLock->unlock();
         return;
     }
 
-    {
-        JSLockHolder locker(vm.get());
-        doWork();
-    }
-
-    m_apiLock->unlock();
+    doWork();
 }
 
 #if USE(CF)
@@ -92,7 +93,10 @@
 
 JSRunLoopTimer::~JSRunLoopTimer()
 {
+    JSLock* apiLock = m_apiLock.get();
+    std::lock_guard<JSLock> lock(*apiLock);
     m_vm->unregisterRunLoopTimer(this);
+    m_apiLock = nullptr;
 }
 
 void JSRunLoopTimer::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to