Closed Bug 1290975 Opened 8 years ago Closed 8 years ago

mozilla::ipc::MessageChannel is using WeakReference on more than one thread

Categories

(Core :: IPC, defect)

defect
Not set
critical

Tracking

()

RESOLVED FIXED
mozilla51
Tracking Status
firefox51 --- fixed

People

(Reporter: mayhemer, Assigned: mayhemer)

References

Details

(Keywords: csectype-race)

Attachments

(1 file, 2 obsolete files)

This is based on using patch from bug 956338 that adds run-time thread safety checks into our weak references.

I'm getting the following assertion failure short after startup with patch v1 from bug 956338 applied:

 	xul.dll!mozilla::detail::WeakReference<mozilla::ipc::MessageListener>::get() Line 130	C++
 	xul.dll!mozilla::WeakPtr<mozilla::ipc::MessageListener>::operator->() Line 245	C++
>	xul.dll!mozilla::ipc::MessageChannel::EnteredCxxStack() Line 341	C++
 	xul.dll!mozilla::ipc::MessageChannel::CxxStackFrame::CxxStackFrame({...}, IN_MESSAGE, 0x0e8ff9a4) Line 234	C++
 	xul.dll!mozilla::ipc::MessageChannel::DispatchMessageW({...}) Line 1592	C++
 	xul.dll!mozilla::ipc::MessageChannel::OnMaybeDequeueOne() Line 1568	C++
 	xul.dll!mozilla::detail::RunnableMethodArguments<>::applyImpl<mozilla::ipc::MessageChannel,bool (__thiscall mozilla::ipc::MessageChannel::*)(void)>(0x0e6f6038, 0x0f2522b1, {...}, {...}) Line 730	C++
 	xul.dll!mozilla::detail::RunnableMethodArguments<>::apply<mozilla::ipc::MessageChannel,bool (__thiscall mozilla::ipc::MessageChannel::*)(void)>(0x0e6f6038, 0x0f2522b1) Line 735	C++
 	xul.dll!mozilla::detail::RunnableMethodImpl<bool (__thiscall mozilla::ipc::MessageChannel::*)(void),0,1>::Run() Line 766	C++
 	xul.dll!mozilla::ipc::MessageChannel::RefCountedTask::Run() Line 550	C++
 	xul.dll!mozilla::ipc::MessageChannel::DequeueTask::Run() Line 571	C++
 	xul.dll!nsThread::ProcessNextEvent(true, 0x0e8ffaf1) Line 1068	C++
 	xul.dll!NS_ProcessNextEvent(0x0e534840, true) Line 290	C++
 	xul.dll!mozilla::ipc::MessagePumpForNonMainThreads::Run(0x0dfbad90) Line 384	C++
 	xul.dll!MessageLoop::RunInternal() Line 233	C++
 	xul.dll!MessageLoop::RunHandler() Line 226	C++
 	xul.dll!MessageLoop::Run() Line 206	C++
 	xul.dll!nsThread::ThreadFunc(0x0e534840) Line 465	C++
 	nss3.dll!_PR_NativeRunThread(0x0e2d13a0) Line 397	C


The WeakReference object involved was created on a different thread (the main thread) than it's being read now (IPDL Background).  This is known to be unsafe, unless there is an absolute certainty the object can't die - but then why using weak ref?

Reporting rather as a sec bug, this might be exploitable.
Josh, you are the one who originally changed mListener to be weak ptr proxy in bug 857152.  This has later been merged to MessageChannel in bug 901789.  Now we are using MessageChannel on multiple threads and using the WeakPtr is then unsafe.

Can you check on this please or reach to other people that could?

Maybe bent could have some insight too.
Blocks: 857152
Flags: needinfo?(josh)
Flags: needinfo?(bent.mozilla)
This was jlebar's work; I only changed the use of chromium atomics to NSPR. https://bugzilla.mozilla.org/show_bug.cgi?id=857152#c3 is all I know about this, so I recommend billm instead.
Flags: needinfo?(josh) → needinfo?(wmccloskey)
Yeah, it's been a while since I looked at this code in detail. Bill is a much better bet here!
Flags: needinfo?(bent.mozilla)
Group: core-security → dom-core-security
Keywords: csectype-race
Sounds potentially bad, so I'm marking it sec-high. Feel free to adjust as appropriate.
Keywords: sec-high
I'm not totally convinced that this is actually a bug. We often create IPC objects on the main thread and then move them to the thread that they'll be used on. After that, all activity must be on that thread (including destruction). As long as get() and detach() are always called on the same thread, it seems like we're safe. Maybe I'm wrong though.

However, I'm not sure why we need a WeakPtr here. Justin said in his comment, "This allows us to keep the mListener reference around longer, whereas before we cleared it in AsyncChannel::Clear." That sort of makes sense (although I would expect mChannelState to be not connected, so Send would err out before examining mListener). But I don't see how mListener would go away before the MessageChannel. There's even a comment here:
http://searchfox.org/mozilla-central/rev/d9a04f71630ce4203ff0a5e26722723045d035b5/ipc/glue/MessageChannel.cpp#624-625

Anyway, I think it would be fine to convert this to a raw pointer. We could also consider nulling out mListener in Clear(), but that would probably be a bit more work.
Flags: needinfo?(wmccloskey)
Honza, do you want to convert to a raw pointer for your assertion checking patches?
Flags: needinfo?(honzab.moz)
I'll lower the rating, then.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Keywords: sec-highsec-moderate
(In reply to Bill McCloskey (:billm) from comment #6)
> Honza, do you want to convert to a raw pointer for your assertion checking
> patches?

That is probably the way.  According the explanation, the channel's listener is ensured to live longer than the channel itself or can be easily notified about the listener's destruction - all is moved and further happens only on a single (background) thread.

Who will write the patch?  I can do that, but I don't know the code at all.
Flags: needinfo?(honzab.moz)
> Who will write the patch?  I can do that, but I don't know the code at all.

Do you mind writing it? If you run into any trouble, feel free to pass it to me.
(In reply to Bill McCloskey (:billm) from comment #9)
> > Who will write the patch?  I can do that, but I don't know the code at all.
> 
> Do you mind writing it? If you run into any trouble, feel free to pass it to
> me.

OK, taking it.
Assignee: nobody → honzab.moz
Status: NEW → ASSIGNED
(In reply to Bill McCloskey (:billm) from comment #5)
> "This allows us to keep the mListener reference around longer,
> whereas before we cleared it in AsyncChannel::Clear." That sort of makes
> sense (although I would expect mChannelState to be not connected, so Send
> would err out before examining mListener). But I don't see how mListener
> would go away before the MessageChannel. There's even a comment here:
> http://searchfox.org/mozilla-central/rev/
> d9a04f71630ce4203ff0a5e26722723045d035b5/ipc/glue/MessageChannel.cpp#624-625

I've found this, but it's probably a leftover, explained below:

https://dxr.mozilla.org/mozilla-central/rev/763fe887c37cee5fcfe0f00e94fdffc84a41ea1c/ipc/glue/MessageChannel.cpp#260

        // mListener could have gone away if Close() was called while
        // MessageChannel code was still on the stack
        if (!mThat.mListener)
            return;

Introduced here https://hg.mozilla.org/mozilla-central/rev/dbfb36b8b381, bug 545455.  In times that bug has been added, mListener was declared in AsyncChannel (later merged) and was only a raw ptr.  WeakPtr has been introduced in https://hg.mozilla.org/mozilla-central/rev/c97f19dc7f7f, bug 857152 and this places might have been omitted from update.

Fingers crossed.
Flags: needinfo?(wmccloskey)
Blocks: 956338
See Also: 956338
Attached patch v1 (obsolete) — Splinter Review
Roughly tested only, but the main idea is clear.

https://treeherder.mozilla.org/#/jobs?repo=try&revision=53d7f6bbd51b
Attachment #8778898 - Flags: review?(wmccloskey)
Please don't make mListener Atomic. After initialization, it's always accessed on the channel's worker thread.
Flags: needinfo?(wmccloskey)
Also, that CxxStackFrame test is no longer useful since we no longer clear mListener in Clear(). So it can be removed.
(In reply to Bill McCloskey (:billm) from comment #14)
> Also, that CxxStackFrame test is no longer useful since we no longer clear
> mListener in Clear(). So it can be removed.

I don't follow, I'm already removing it in the patch, or what do you mean?
Flags: needinfo?(wmccloskey)
Do you mean this hunk?

 void
 MessageChannel::ExitedCxxStack()
 {
-    mListener->OnExitedCxxStack();
+    if (mListener) {
+        mListener->OnExitedCxxStack();
+    }
     if (mSawInterruptOutMsg) {
Attached patch v1.1 (obsolete) — Splinter Review
Attachment #8778898 - Attachment is obsolete: true
Attachment #8778898 - Flags: review?(wmccloskey)
Attachment #8779306 - Flags: review?(wmccloskey)
Daniel, can you please remove this bug from the " Security-Sensitive DOM Bug "?  I don't have the permission for that group.  

According the findings, this is not a security bug or anything exploitable.  Thanks.
Flags: needinfo?(dveditz)
Group: dom-core-security
Flags: needinfo?(dveditz)
Keywords: sec-moderate
(In reply to Honza Bambas (:mayhemer) from comment #15)
> (In reply to Bill McCloskey (:billm) from comment #14)
> > Also, that CxxStackFrame test is no longer useful since we no longer clear
> > mListener in Clear(). So it can be removed.
> 
> I don't follow, I'm already removing it in the patch, or what do you mean?

I was trying to answer the needinfo in comment 11. I meant the hunk that you already removed.
Flags: needinfo?(wmccloskey)
Comment on attachment 8779306 [details] [diff] [review]
v1.1

Review of attachment 8779306 [details] [diff] [review]:
-----------------------------------------------------------------

Thanks!

::: ipc/glue/MessageChannel.cpp
@@ +2079,5 @@
>  
>      // Oops, error!  Let the listener know about it.
>      mChannelState = ChannelError;
>  
> +    // After this, the channel may be deleted.  Based on the premiss that

premise

@@ +2081,5 @@
>      mChannelState = ChannelError;
>  
> +    // After this, the channel may be deleted.  Based on the premiss that
> +    // mListener owns this channel, any calls back to this class that may
> +    // work with mListner should still work on living objects.

mListener
Attachment #8779306 - Flags: review?(wmccloskey) → review+
Keywords: crash
Keywords: crashcheckin-needed
Grr... needs an update first!
Keywords: checkin-needed
Attached patch v1.1.1Splinter Review
https://treeherder.mozilla.org/#/jobs?repo=try&revision=cfc312760e8c4c6103e05b80db1b192d64fe337b

(ignore Android 4.3 API15+ opt failures, that is a different patch)
Attachment #8779306 - Attachment is obsolete: true
Attachment #8779805 - Flags: review+
Keywords: checkin-needed
https://hg.mozilla.org/mozilla-central/rev/71f49b7f44b6
Status: ASSIGNED → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla51
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: