Crash when navigating to another page immediately after initializing unity integration

Bug #1076350 reported by Chris Coulson
274
This bug affects 2 people
Affects Status Importance Assigned to Milestone
WebApps: unity-firefox-extension
Fix Committed
High
Maxim Ermilov
unity-firefox-extension (Ubuntu)
Fix Released
Critical
Ken VanDine
Quantal
Fix Released
Critical
Unassigned
Raring
Fix Released
Critical
Ken VanDine

Bug Description

Seb pinged me about a Firefox crash a couple of days ago. After some investigation, I've figured out a fairly trivial reproducer.

With a local test page:

1) Navigate manually to "http://localhost/test.html":

...test1.html:

<html>
<head></head>
<script>
    var unity = window.external.getUnityObject(1);
    unity.init({name: "Foo"});
    window.location = "http://localhost/test2.html";
</script>
</html>

...and test2.html:

<html>
<head></head>
<script>
    var unity = window.external.getUnityObject(1);
    unity.init({name: "Foo"});
</script>
</html>

2) Accept the integration
3) Close the browser tab

(Note, you might need to try this again after allowing the integration)

What happens is the website icon still appears in the Unity launcher after the tab is closed. Clicking it to refocus the non-existant tab will eventually cause Firefox to crash, presumably because it is calling a JS callback across ctypes which has been garbage collected. The traces will look something like this, although the top few frames will vary depending on what's now in the memory where the callback used to be:

Program received signal SIGILL, Illegal instruction.
0x00007f8a9b0000b8 in ?? ()
(gdb) bt
#0 0x00007f8a9b0000b8 in ?? ()
#1 0x00007f8a98c57ecc in ffi_call_unix64 () from /usr/lib/firefox/libxul.so
#2 0x00007f8a98c45e30 in ffi_call (cif=cif@entry=0x7fff67309230, fn=fn@entry=0x7f8a81aea700 <_raise_callback>, rvalue=0x7fff67309190, avalue=avalue@entry=0x7fff67309130)
    at /build/buildd/firefox-17.0~b4+build1/./js/src/ctypes/libffi/src/x86/ffi64.c:485
#3 0x00007f8a96700a9b in g_cclosure_marshal_generic (closure=0x7f8a71695260, return_gvalue=0x0, n_param_values=<optimised out>, param_values=<optimised out>, invocation_hint=<optimised out>, marshal_data=0x7f8a81aea700 <_raise_callback>)
    at /build/buildd/glib2.0-2.34.1/./gobject/gclosure.c:1454
#4 0x00007f8a96700140 in g_closure_invoke (closure=0x7f8a71695260, return_value=0x0, n_param_values=3, param_values=0x7f8a6d1ff420, invocation_hint=0x7fff67309410) at /build/buildd/glib2.0-2.34.1/./gobject/gclosure.c:777
#5 0x00007f8a96711550 in signal_emit_unlocked_R (node=node@entry=0x7f8a6ddc1520, detail=detail@entry=0, instance=instance@entry=0x7f8a72b8b3a0, emission_return=emission_return@entry=0x0,
    instance_and_params=instance_and_params@entry=0x7f8a6d1ff420) at /build/buildd/glib2.0-2.34.1/./gobject/gsignal.c:3551
#6 0x00007f8a967186ab in g_signal_emitv (instance_and_params=instance_and_params@entry=0x7f8a6d1ff420, signal_id=<optimised out>, detail=detail@entry=0, return_value=return_value@entry=0x0)
    at /build/buildd/glib2.0-2.34.1/./gobject/gsignal.c:3041
#7 0x00007f8a81ade833 in unity_webapps_gen_context_proxy_g_signal (proxy=<optimised out>, sender_name=<optimised out>, signal_name=<optimised out>, parameters=<optimised out>) at ../unity-webapps-gen-context.c:6301
#8 0x00007f8a98c57ecc in ffi_call_unix64 () from /usr/lib/firefox/libxul.so
#9 0x00007f8a98c45e30 in ffi_call (cif=cif@entry=0x7fff673097f0, fn=fn@entry=0x7f8a81ade720 <unity_webapps_gen_context_proxy_g_signal>, rvalue=0x7fff67309750, avalue=avalue@entry=0x7fff673096d0)
    at /build/buildd/firefox-17.0~b4+build1/./js/src/ctypes/libffi/src/x86/ffi64.c:485
#10 0x00007f8a96700a9b in g_cclosure_marshal_generic (closure=0x7f8a88b1bc20, return_gvalue=0x0, n_param_values=<optimised out>, param_values=<optimised out>, invocation_hint=<optimised out>,
    marshal_data=0x7f8a81ade720 <unity_webapps_gen_context_proxy_g_signal>) at /build/buildd/glib2.0-2.34.1/./gobject/gclosure.c:1454
#11 0x00007f8a96700140 in g_closure_invoke (closure=0x7f8a88b1bc20, return_value=0x0, n_param_values=4, param_values=0x7fff67309a30, invocation_hint=0x7fff673099d0) at /build/buildd/glib2.0-2.34.1/./gobject/gclosure.c:777
#12 0x00007f8a967112d0 in signal_emit_unlocked_R (node=node@entry=0x7f8a8de132c0, detail=detail@entry=0, instance=instance@entry=0x7f8a72b8b3a0, emission_return=emission_return@entry=0x0,
    instance_and_params=instance_and_params@entry=0x7fff67309a30) at /build/buildd/glib2.0-2.34.1/./gobject/gsignal.c:3589
#13 0x00007f8a967194af in g_signal_emit_valist (instance=0x7f8a72b8b3a0, signal_id=<optimised out>, detail=0, var_args=var_args@entry=0x7fff67309cb8) at /build/buildd/glib2.0-2.34.1/./gobject/gsignal.c:3300
#14 0x00007f8a96719642 in g_signal_emit (instance=instance@entry=0x7f8a72b8b3a0, signal_id=<optimised out>, detail=detail@entry=0) at /build/buildd/glib2.0-2.34.1/./gobject/gsignal.c:3356
#15 0x00007f8a94577b74 in on_signal_received (connection=<optimised out>, sender_name=0x7f8a72b97538 ":1.307", object_path=<optimised out>, interface_name=<optimised out>, signal_name=0x7f8a70432400 "RaiseRequested",
    parameters=0x7f8a6d1728b0, user_data=0x7f8a716a1430) at /build/buildd/glib2.0-2.34.1/./gio/gdbusproxy.c:927
#16 0x00007f8a945677f5 in emit_signal_instance_in_idle_cb (data=0x7f8a6d1ff290) at /build/buildd/glib2.0-2.34.1/./gio/gdbusconnection.c:3715
#17 0x00007f8a96440ab5 in g_main_dispatch (context=0x7f8a9af27be0) at /build/buildd/glib2.0-2.34.1/./glib/gmain.c:2715
#18 g_main_context_dispatch (context=context@entry=0x7f8a9af27be0) at /build/buildd/glib2.0-2.34.1/./glib/gmain.c:3219
#19 0x00007f8a96440de8 in g_main_context_iterate (context=context@entry=0x7f8a9af27be0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimised out>) at /build/buildd/glib2.0-2.34.1/./glib/gmain.c:3290
#20 0x00007f8a96440ea4 in g_main_context_iteration (context=0x7f8a9af27be0, may_block=1) at /build/buildd/glib2.0-2.34.1/./glib/gmain.c:3351
#21 0x00007f8a9845a226 in nsAppShell::ProcessNextNativeEvent (this=<optimised out>, mayWait=<optimised out>) at /build/buildd/firefox-17.0~b4+build1/widget/gtk2/nsAppShell.cpp:131
#22 0x00007f8a984701e1 in nsBaseAppShell::DoProcessNextNativeEvent (this=this@entry=0x7f8a88a510f0, mayWait=<optimised out>, recursionDepth=recursionDepth@entry=0)
    at /build/buildd/firefox-17.0~b4+build1/widget/xpwidgets/nsBaseAppShell.cpp:139
#23 0x00007f8a984702fa in nsBaseAppShell::OnProcessNextEvent (this=0x7f8a88a510f0, thr=0x7f8a9af251a0, mayWait=<optimised out>, recursionDepth=0) at /build/buildd/firefox-17.0~b4+build1/widget/xpwidgets/nsBaseAppShell.cpp:298
#24 0x00007f8a985f7631 in nsThread::ProcessNextEvent (this=0x7f8a9af251a0, mayWait=<optimised out>, result=0x7fff67309fef) at /build/buildd/firefox-17.0~b4+build1/xpcom/threads/nsThread.cpp:586
#25 0x00007f8a985cd666 in NS_ProcessNextEvent_P (thread=<optimised out>, mayWait=<optimised out>) at /build/buildd/firefox-17.0~b4+build1/obj-x86_64-linux-gnu/xpcom/build/nsThreadUtils.cpp:220
#26 0x00007f8a98515581 in mozilla::ipc::MessagePump::Run (this=0x7f8a8de67480, aDelegate=0x7f8a9afeef90) at /build/buildd/firefox-17.0~b4+build1/ipc/glue/MessagePump.cpp:117
#27 0x00007f8a98615fef in RunHandler (this=0x7f8a9afeef90) at /build/buildd/firefox-17.0~b4+build1/ipc/chromium/src/base/message_loop.cc:201
#28 MessageLoop::Run (this=0x7f8a9afeef90) at /build/buildd/firefox-17.0~b4+build1/ipc/chromium/src/base/message_loop.cc:175
#29 0x00007f8a9846fbd1 in nsBaseAppShell::Run (this=0x7f8a88a510f0) at /build/buildd/firefox-17.0~b4+build1/widget/xpwidgets/nsBaseAppShell.cpp:163
#30 0x00007f8a9834e063 in nsAppStartup::Run (this=0x7f8a88a56100) at /build/buildd/firefox-17.0~b4+build1/toolkit/components/startup/nsAppStartup.cpp:273
#31 0x00007f8a97b780cc in XREMain::XRE_mainRun (this=this@entry=0x7fff6730a220) at /build/buildd/firefox-17.0~b4+build1/toolkit/xre/nsAppRunner.cpp:3812
#32 0x00007f8a97b782be in XREMain::XRE_main (this=this@entry=0x7fff6730a220, argc=argc@entry=1, argv=argv@entry=0x7fff6730c608, aAppData=aAppData@entry=0x7f8a9c44c9f0 <sAppData>)
    at /build/buildd/firefox-17.0~b4+build1/toolkit/xre/nsAppRunner.cpp:3889
#33 0x00007f8a97b784fa in XRE_main (argc=1, argv=0x7fff6730c608, aAppData=0x7f8a9c44c9f0 <sAppData>, aFlags=<optimised out>) at /build/buildd/firefox-17.0~b4+build1/toolkit/xre/nsAppRunner.cpp:3965
#34 0x00007f8a9c23c8f1 in do_main (argv=0x7fff6730c608, argc=1) at /build/buildd/firefox-17.0~b4+build1/browser/app/nsBrowserApp.cpp:174
#35 main (argc=<optimised out>, argv=<optimised out>) at /build/buildd/firefox-17.0~b4+build1/browser/app/nsBrowserApp.cpp:279

I've seen it crash sometimes with SIGSEGV and sometimes with SIGILL. The SIGILL is probably enough to assume that this is potentially exploitable.

Related branches

CVE References

Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

This is CVE-2012-0960

Maxim Ermilov (zaspire)
Changed in unity-firefox-extension:
assignee: nobody → Maxim Ermilov (zaspire)
milestone: none → 2.4.2
Revision history for this message
Maxim Ermilov (zaspire) wrote :

It happens only with ff 17

Revision history for this message
Maxim Ermilov (zaspire) wrote :

I belive, it is ff 17 bug.
it doesn't emit pagehide event on test1->test2 redirect.

Changed in unity-firefox-extension:
status: New → Incomplete
Maxim Ermilov (zaspire)
Changed in unity-firefox-extension:
assignee: Maxim Ermilov (zaspire) → nobody
milestone: 2.4.2 → none
Revision history for this message
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in unity-firefox-extension (Ubuntu Quantal):
status: New → Confirmed
Changed in unity-firefox-extension (Ubuntu):
status: New → Confirmed
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

I definitely see pagehide here in gdb for the redirect (when navigating to my test case, nsDocument::DispatchPageTransition is called twice with aType=pagehide and twice with aType=pageshow)

Changed in unity-firefox-extension:
status: Incomplete → Confirmed
Changed in unity-firefox-extension (Ubuntu Quantal):
importance: Undecided → High
Changed in unity-firefox-extension (Ubuntu Raring):
importance: Undecided → High
Changed in unity-firefox-extension (Ubuntu Quantal):
importance: High → Critical
Changed in unity-firefox-extension (Ubuntu Raring):
importance: High → Critical
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Note that also doing this in a JS shell shows that pagehide fires twice when I load the testcase:

gBrowser.selectedBrowser.addEventListener("pagehide", function _onPageHide() { print("Got pagehide"); }, true);

Changed in unity-firefox-extension:
assignee: nobody → Maxim Ermilov (zaspire)
Revision history for this message
Maxim Ermilov (zaspire) wrote :

> Note that also doing this in a JS shell shows that pagehide fires twice when I load the testcase:
It doesn't emit pagehide during tab closing.

Maxim Ermilov (zaspire)
Changed in unity-firefox-extension:
status: Confirmed → Fix Committed
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

It does here.

If you're not getting a pagehide during tab closing, then you've got an addon leaking the document

Revision history for this message
Maxim Ermilov (zaspire) wrote :

Can reproduce it with extension from trunk?

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Some comments from IRC:

<ChrisCoulson> so, the addon doesn't get pagehide because it disconnects from it the first time anybody navigates away from the first page viewed in a tab
<ChrisCoulson> in case you hadn't figured it out already, it looks like the problem with webapps is that the UnityObject's are keyed by outer window rather than inner window (and outer windows are reused between page navigations). it looks like the webapps addon assumes they are not reused...

When you navigate to a new page in a tab, this returns the same UnityObject (which has since disconnected from "pagehide"):

http://bazaar.launchpad.net/~webapps/unity-firefox-extension/trunk/view/head:/unity-firefox-extension/content/unity-global-property-initializer.js#L486

Then if the new page uses the Unity API, the context isn't destroyed when the tab closes, because the pagehide handler was already disconnected.

New windows are handled from the "content-document-global-created" notification, which is dispatched from the outer window:

http://bazaar.launchpad.net/~webapps/unity-firefox-extension/trunk/view/head:/unity-firefox-extension/content/observer.js#L212

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

https://code.launchpad.net/~chrisccoulson/unity-firefox-extension/lp1076350 fixes it here. It does 2 things:

1) Keys UnityObject in a weak map with an object that's tied to the inner window (I don't think it's possible to get the inner window from an outer window), so each new page gets a new object.

2) Doesn't disconnect from "pagehide" unless the window is being destroyed (using the "dom-window-destroyed" notification). This fixes another issue similar to this one where navigating back to a page that previously used the Unity API and which gets recovered from the bfcache could cause a crash when the tab is closed, because its pagehide handler would have already been disconnected.

The behaviour of this API is pretty broken compared to any other DOM API though wrt page navigations though. When you navigate away from a page and it gets inserted in to the bfcache, its state should be frozen until it is recovered from the cache later on (unless it gets removed from the bfcache, in which case the page will be reloaded in a new inner window). However, the Unity API doesn't freeze the state - it actually destroys the context which means a page that is recovered from the bfcache has to reinitialize everything again.

I'm not sure if the changes I've done break anything else though. This whole thing seems really fragile.

Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

If someone from the webapps team can please test and give an official go-ahead, I'll push this fix as a security update. Thanks!

information type: Private Security → Public Security
Revision history for this message
Víctor R. Ruiz (vrruiz) wrote :

Regression tests

== Test 1 ==
- Step 1
1. Open Firefox
2. Go to http://launchpad.net/
3. Accept integration test.

Expected behavior
1. Launchpad icon should appear in the Launcher.

- Step 2 (continue from step 1)
1. Close tab.

Expected behavior
1. Launchpad icon should disappear from the Launcher.

== Test 2 ==
- Step 1
1. Open Firefox
2. Go to http://www.bbc.co.uk/news
3. Accept integration test.

Expected behavior
1. BBC icon must appear in the Launcher.

- Step 2 (continue from step 1)
1. In the same tab of BBC, go to http://launchpad.net/

Expected behavior
1. BBC icon must disappear from the Launcher and Launchpad one must show.

This has been tested with unity-firefox-extension trunk and Firefox 17. Go ahead.

Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package unity-firefox-extension - 2.4.1-0ubuntu1.1

---------------
unity-firefox-extension (2.4.1-0ubuntu1.1) quantal-security; urgency=low

  * SECURITY UPDATE: denial of service and possible code execution
    (LP: #1076350)
    - debian/patches/CVE-2012-0960.patch: improve logic in
      unity-firefox-extension/content/unity-global-property-initializer.js.
    - CVE-2012-0960
 -- Marc Deslauriers <email address hidden> Thu, 22 Nov 2012 10:12:53 -0500

Changed in unity-firefox-extension (Ubuntu Quantal):
status: Confirmed → Fix Released
Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package unity-firefox-extension - 2.4.1-0ubuntu3

---------------
unity-firefox-extension (2.4.1-0ubuntu3) raring; urgency=low

  * SECURITY UPDATE: denial of service and possible code execution
    (LP: #1076350)
    - debian/patches/CVE-2012-0960.patch: improve logic in
      unity-firefox-extension/content/unity-global-property-initializer.js.
    - CVE-2012-0960
 -- Marc Deslauriers <email address hidden> Thu, 22 Nov 2012 10:44:07 -0500

Changed in unity-firefox-extension (Ubuntu Raring):
status: Confirmed → Fix Released
Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

The fix for this got reverted in the raring 2.4.2-0ubuntu1 upload. Reopening bug.

Changed in unity-firefox-extension (Ubuntu Raring):
status: Fix Released → Confirmed
assignee: nobody → Ken VanDine (ken-vandine)
David King (amigadave)
Changed in unity-firefox-extension:
importance: Undecided → High
Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

Actually, the patch is clearly in the raring 2.4.2-0ubuntu1 package. I'm not sure why I though the fix got reverted. Apologies for the confusion. Closing bug.

Changed in unity-firefox-extension (Ubuntu Raring):
status: Confirmed → Fix Released
Revision history for this message
Chris Halse Rogers (raof) wrote : Please test proposed package

Hello Chris, or anyone else affected,

Accepted unity-firefox-extension into quantal-proposed. The package will build now and be available at http://launchpad.net/ubuntu/+source/unity-firefox-extension/2.4.4-0ubuntu0.1 in a few hours, and then in the -proposed repository.

Please help us by testing this new package. See https://wiki.ubuntu.com/Testing/EnableProposed for documentation how to enable and use -proposed. Your feedback will aid us getting this update out to other Ubuntu users.

If this package fixes the bug for you, please add a comment to this bug, mentioning the version of the package you tested, and change the tag from verification-needed to verification-done. If it does not fix the bug for you, please add a comment stating that, and change the tag to verification-failed. In either case, details of your testing will help us make a better decision.

Further information regarding the verification process can be found at https://wiki.ubuntu.com/QATeam/PerformingSRUVerification . Thank you in advance!

tags: added: verification-needed
Revision history for this message
Víctor R. Ruiz (vrruiz) wrote :

Regression tests

== Test 1 ==
- Step 1
1. Open Firefox
2. Go to http://launchpad.net/
3. Accept integration test.

Expected behavior
1. Launchpad icon should appear in the Launcher.

- Step 2 (continue from step 1)
1. Close tab.

Expected behavior
1. Launchpad icon should disappear from the Launcher.

== Test 2 ==
- Step 1
1. Open Firefox
2. Go to http://www.bbc.co.uk/news
3. Accept integration test.

Expected behavior
1. BBC icon must appear in the Launcher.

- Step 2 (continue from step 1)
1. In the same tab of BBC, go to http://launchpad.net/

Expected behavior
1. BBC icon must disappear from the Launcher and Launchpad one must show.

Tested with Firefox 19.0+build1-0ubuntu0.12.10.1 and xul-ext-unity 2.4.4-0ubuntu0.1. Works as expected.

To post a comment you must log in.
This report contains Public Security information  
Everyone can see this security related information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.