Bug 200920 - Unsafe usage of CookieStorageObserver from a background thread
Summary: Unsafe usage of CookieStorageObserver from a background thread
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit2 (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Chris Dumez
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-08-20 08:32 PDT by Chris Dumez
Modified: 2019-08-20 11:57 PDT (History)
6 users (show)

See Also:


Attachments
Patch (8.01 KB, patch)
2019-08-20 08:36 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (8.02 KB, patch)
2019-08-20 09:06 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2019-08-20 08:32:37 PDT
Unsafe usage of CookieStorageObserver from a background thread. CookieStorageObserver gets constructed / destructed on the main thread. However, CookieStorageObserver::cookiesDidChange() gets called on a background thread and tries to ref |this|. Even though CookieStorageObserver is ThreadSafeRefCounted, this is still unsafe because the CookieStorageObserver may already be running on the main thread when CookieStorageObserver::cookiesDidChange() gets called on the background thread. This could lead to a double free.
Comment 1 Chris Dumez 2019-08-20 08:36:20 PDT
Created attachment 376770 [details]
Patch
Comment 2 Alex Christensen 2019-08-20 08:40:44 PDT
Comment on attachment 376770 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=376770&action=review

> Source/WebCore/ChangeLog:11
> +        is ThreadSafeRefCounted, this is still unsafe because the CookieStorageObserver may already be

Did you forget "destructor" here?  I don't understand what is different about CookieStorageObserver.  Couldn't this happen with any ThreadSafeRefCounted type?
Comment 3 Chris Dumez 2019-08-20 08:58:18 PDT
Comment on attachment 376770 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=376770&action=review

>> Source/WebCore/ChangeLog:11
>> +        is ThreadSafeRefCounted, this is still unsafe because the CookieStorageObserver may already be
> 
> Did you forget "destructor" here?  I don't understand what is different about CookieStorageObserver.  Couldn't this happen with any ThreadSafeRefCounted type?

Yes, I forgot destructor :/

Yes, this could happen with any ThreadSafeRefCounted type. It is almost always unsafe to create a Ref<> / RefPtr<> from a raw pointer for a ThreadSafeRefCounted type from a thread that is not the thread that owns the object. Brady suggest adding a ThreadSafeRefCounted::tryRef() for this and I think this is a nice idea but I'd rather keep this patch small (cherry-pickable).
Not that usually, we do not have this problem since we pass a RefPtr<> or Ref<> from the owner thread to another thread. It is not common that we create the Ref<> / RefPtr<> from a non-owner thread.
Comment 4 Alex Christensen 2019-08-20 09:00:00 PDT
Comment on attachment 376770 [details]
Patch

Sounds like we should add some assertions to ThreadSafeRefCounted, too.  The name implies that you can't run into problems like this.  I'll bet there are other double frees out there.
Comment 5 Chris Dumez 2019-08-20 09:00:42 PDT
Comment on attachment 376770 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=376770&action=review

>>> Source/WebCore/ChangeLog:11
>>> +        is ThreadSafeRefCounted, this is still unsafe because the CookieStorageObserver may already be
>> 
>> Did you forget "destructor" here?  I don't understand what is different about CookieStorageObserver.  Couldn't this happen with any ThreadSafeRefCounted type?
> 
> Yes, I forgot destructor :/
> 
> Yes, this could happen with any ThreadSafeRefCounted type. It is almost always unsafe to create a Ref<> / RefPtr<> from a raw pointer for a ThreadSafeRefCounted type from a thread that is not the thread that owns the object. Brady suggest adding a ThreadSafeRefCounted::tryRef() for this and I think this is a nice idea but I'd rather keep this patch small (cherry-pickable).
> Not that usually, we do not have this problem since we pass a RefPtr<> or Ref<> from the owner thread to another thread. It is not common that we create the Ref<> / RefPtr<> from a non-owner thread.

Also note that the CookieStorageObserver only stops observing notifications in its destructor, which is why this is an issue. I decided to fix it with a WeakPtr<> but another way to fix this would have been a 2-step destruction, requiring the caller to call a CookieStorageObserver::stopListingForNotifications() method on the main thread *before* destroying the CookieStorageObserver object. The WeakPtr approach is a bit less error-prone IMO though.
Comment 6 Chris Dumez 2019-08-20 09:06:15 PDT
Created attachment 376774 [details]
Patch
Comment 7 Radar WebKit Bug Importer 2019-08-20 09:06:52 PDT
<rdar://problem/54513840>
Comment 8 WebKit Commit Bot 2019-08-20 09:53:27 PDT
Comment on attachment 376774 [details]
Patch

Clearing flags on attachment: 376774

Committed r248902: <https://trac.webkit.org/changeset/248902>
Comment 9 WebKit Commit Bot 2019-08-20 09:53:29 PDT
All reviewed patches have been landed.  Closing bug.
Comment 10 Geoffrey Garen 2019-08-20 10:49:48 PDT
Comment on attachment 376774 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=376774&action=review

> Source/WebCore/platform/network/cocoa/CookieStorageObserver.mm:78
> +    : m_weakThis(makeWeakPtr(*this))

Similar to my comment in bug 200925, I think we should remove this data member, and just use makeWeakPtr(*this).
Comment 11 Chris Dumez 2019-08-20 11:29:05 PDT
Comment on attachment 376774 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=376774&action=review

>> Source/WebCore/platform/network/cocoa/CookieStorageObserver.mm:78
>> +    : m_weakThis(makeWeakPtr(*this))
> 
> Similar to my comment in bug 200925, I think we should remove this data member, and just use makeWeakPtr(*this).

MakeWeakPtr() is not currently safe to call from another thread though...
Comment 12 Chris Dumez 2019-08-20 11:57:51 PDT
(In reply to Chris Dumez from comment #11)
> Comment on attachment 376774 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=376774&action=review
> 
> >> Source/WebCore/platform/network/cocoa/CookieStorageObserver.mm:78
> >> +    : m_weakThis(makeWeakPtr(*this))
> > 
> > Similar to my comment in bug 200925, I think we should remove this data member, and just use makeWeakPtr(*this).
> 
> MakeWeakPtr() is not currently safe to call from another thread though...

Oh, I now see your other comment about initializing the WeakPtrFactory in the constructor on the main thread to work around the thread-safety problem. I will look into this.