Bug 833935 - Warn when child is about to issue illegal IPDL request. r=jdm
authorJason Duell <jduell.mcbugs@gmail.com>
Thu, 24 Jan 2013 19:24:00 +0000
changeset 130522 eddbffde391870c763cdd95b406d95bc724edfa7
parent 130521 b662c6940cf45601fe8f4105873cdacfad457dcc
child 130523 cd471ce8fd8e14bf9b80b67e7793b6a0810ba041
push id317
push userbbajaj@mozilla.com
push dateTue, 07 May 2013 01:20:33 +0000
treeherdermozilla-release@159a10910249 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
bugs833935
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 833935 - Warn when child is about to issue illegal IPDL request. r=jdm
netwerk/cookie/CookieServiceChild.cpp
netwerk/ipc/NeckoCommon.h
netwerk/ipc/RemoteOpenFileChild.cpp
netwerk/protocol/ftp/FTPChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/websocket/WebSocketChannelChild.cpp
netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
uriloader/prefetch/OfflineCacheUpdateChild.cpp
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -119,16 +119,19 @@ CookieServiceChild::GetCookieStringInter
 
   nsCOMPtr<nsITabChild> iTabChild;
   mozilla::dom::TabChild* tabChild = nullptr;
   if (aChannel) {
     NS_QueryNotificationCallbacks(aChannel, iTabChild);
     if (iTabChild) {
       tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
     }
+    if (MissingRequiredTabChild(tabChild, "cookie")) {
+      return NS_ERROR_ILLEGAL_VALUE;
+    }
   }
 
   // Synchronously call the parent.
   nsAutoCString result;
   SendGetCookieString(uriParams, !!isForeign, aFromHttp,
                       IPC::SerializedLoadContext(aChannel), tabChild, &result);
   if (!result.IsEmpty())
     *aCookieString = ToNewCString(result);
@@ -161,16 +164,19 @@ CookieServiceChild::SetCookieStringInter
 
   nsCOMPtr<nsITabChild> iTabChild;
   mozilla::dom::TabChild* tabChild = nullptr;
   if (aChannel) {
     NS_QueryNotificationCallbacks(aChannel, iTabChild);
     if (iTabChild) {
       tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
     }
+    if (MissingRequiredTabChild(tabChild, "cookie")) {
+      return NS_ERROR_ILLEGAL_VALUE;
+    }
   }
 
   // Synchronously call the parent.
   SendSetCookieString(uriParams, !!isForeign, cookieString, serverTime,
                       aFromHttp, IPC::SerializedLoadContext(aChannel), tabChild);
   return NS_OK;
 }
 
--- a/netwerk/ipc/NeckoCommon.h
+++ b/netwerk/ipc/NeckoCommon.h
@@ -8,16 +8,20 @@
 #ifndef mozilla_net_NeckoCommon_h
 #define mozilla_net_NeckoCommon_h
 
 #include "nsXULAppAPI.h"
 #include "prenv.h"
 #include "nsPrintfCString.h"
 #include "mozilla/Preferences.h"
 
+namespace mozilla { namespace dom {
+class TabChild;
+}}
+
 #if defined(DEBUG) || defined(ENABLE_TESTS)
 # define NECKO_ERRORS_ARE_FATAL_DEFAULT true
 #else
 # define NECKO_ERRORS_ARE_FATAL_DEFAULT false
 #endif 
 
 // TODO: Eventually remove NECKO_MAYBE_ABORT and DROP_DEAD (bug 575494).
 // Still useful for catching listener interfaces we don't yet support across
@@ -106,15 +110,34 @@ UsingNeckoIPCSecurity()
   if (!registeredBool) {
     Preferences::AddBoolVarCache(&securityDisabled,
                                  "network.disable.ipc.security");
     registeredBool = true;
   }
   return !securityDisabled;
 }
 
+inline bool
+MissingRequiredTabChild(mozilla::dom::TabChild* tabChild,
+                        const char* context)
+{
+  if (UsingNeckoIPCSecurity()) {
+    // Bug 833935: during navigation away from page some loads may lack
+    // TabParent: we don't want to kill browser for that.  Doesn't happen in
+    // test harness, so fail in debug mode so we can catch new code that fails
+    // to pass security info.
+    MOZ_ASSERT(tabChild);
+
+    if (!tabChild) {
+      printf_stderr("WARNING: child tried to open %s IPDL channel w/o "
+                    "security info\n", context);
+      return true;
+    }
+  }
+  return false;
+}
 
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_NeckoCommon_h
 
--- a/netwerk/ipc/RemoteOpenFileChild.cpp
+++ b/netwerk/ipc/RemoteOpenFileChild.cpp
@@ -101,16 +101,19 @@ RemoteOpenFileChild::AsyncRemoteFileOpen
   if (aFlags != PR_RDONLY) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   mozilla::dom::TabChild* tabChild = nullptr;
   if (aTabChild) {
     tabChild = static_cast<mozilla::dom::TabChild*>(aTabChild);
   }
+  if (MissingRequiredTabChild(tabChild, "remoteopenfile")) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
 
 #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
   // Windows/OSX desktop builds skip remoting, and just open file in child
   // process when asked for NSPR handle
   aListener->OnRemoteFileOpenComplete(NS_OK);
   mAsyncOpenCalled = true;
   return NS_OK;
 #else
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -160,16 +160,19 @@ FTPChannelChild::AsyncOpen(::nsIStreamLi
   nsCOMPtr<nsITabChild> iTabChild;
   NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
                                 NS_GET_IID(nsITabChild),
                                 getter_AddRefs(iTabChild));
   GetCallback(iTabChild);
   if (iTabChild) {
     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   }
+  if (MissingRequiredTabChild(tabChild, "ftp")) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
 
   // FIXME: like bug 558623, merge constructor+SendAsyncOpen into 1 IPC msg
   gNeckoChild->SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this));
   mListener = listener;
   mListenerContext = aContext;
 
   // add ourselves to the load group. 
   if (mLoadGroup)
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -801,16 +801,19 @@ NS_IMETHODIMP
 HttpChannelChild::ConnectParent(uint32_t id)
 {
   mozilla::dom::TabChild* tabChild = nullptr;
   nsCOMPtr<nsITabChild> iTabChild;
   GetCallback(iTabChild);
   if (iTabChild) {
     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   }
+  if (MissingRequiredTabChild(tabChild, "http")) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
 
   // The socket transport in the chrome process now holds a logical ref to us
   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   AddIPDLReference();
 
   if (!gNeckoChild->SendPHttpChannelConstructor(
                       this, tabChild, IPC::SerializedLoadContext(this))) {
     return NS_ERROR_FAILURE;
@@ -1039,16 +1042,19 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
   // FIXME: bug 558623: Combine constructor and SendAsyncOpen into one IPC msg
 
   mozilla::dom::TabChild* tabChild = nullptr;
   nsCOMPtr<nsITabChild> iTabChild;
   GetCallback(iTabChild);
   if (iTabChild) {
     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   }
+  if (MissingRequiredTabChild(tabChild, "http")) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
 
   // The socket transport in the chrome process now holds a logical ref to us
   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   AddIPDLReference();
 
   gNeckoChild->SendPHttpChannelConstructor(this, tabChild,
                                            IPC::SerializedLoadContext(this));
 
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -326,16 +326,19 @@ WebSocketChannelChild::AsyncOpen(nsIURI 
   mozilla::dom::TabChild* tabChild = nullptr;
   nsCOMPtr<nsITabChild> iTabChild;
   NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
                                 NS_GET_IID(nsITabChild),
                                 getter_AddRefs(iTabChild));
   if (iTabChild) {
     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   }
+  if (MissingRequiredTabChild(tabChild, "websocket")) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
 
   URIParams uri;
   SerializeURI(aURI, uri);
 
   // Corresponding release in DeallocPWebSocket
   AddIPDLReference();
 
   gNeckoChild->SendPWebSocketConstructor(this, tabChild,
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -598,16 +598,20 @@ WyciwygChannelChild::AsyncOpen(nsIStream
 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nullptr);
 
   URIParams originalURI;
   SerializeURI(mOriginalURI, originalURI);
 
   mozilla::dom::TabChild* tabChild = GetTabChild(this);
+  if (MissingRequiredTabChild(tabChild, "wyciwyg")) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
   SendAsyncOpen(originalURI, mLoadFlags, IPC::SerializedLoadContext(this), tabChild);
 
   mSentAppData = true;
   mState = WCC_OPENED;
 
   return NS_OK;
 }
 
--- a/uriloader/prefetch/OfflineCacheUpdateChild.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateChild.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "OfflineCacheUpdateChild.h"
 #include "nsOfflineCacheUpdate.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/ipc/URIUtils.h"
+#include "mozilla/net/NeckoCommon.h"
 
 #include "nsIApplicationCacheContainer.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIApplicationCacheService.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDOMWindow.h"
@@ -26,16 +27,18 @@
 #include "nsServiceManagerUtils.h"
 #include "nsStreamUtils.h"
 #include "nsThreadUtils.h"
 #include "nsProxyRelease.h"
 #include "prlog.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 
 using namespace mozilla::ipc;
+using namespace mozilla::net;
+using mozilla::dom::TabChild;
 
 #if defined(PR_LOGGING)
 //
 // To enable logging (see prlog.h for full details):
 //
 //    set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5
 //    set NSPR_LOG_FILE=offlineupdate.log
 //
@@ -401,29 +404,28 @@ OfflineCacheUpdateChild::Schedule()
       NS_WARNING("doc shell tree item is null");
       return NS_ERROR_FAILURE;
     }
 
     nsCOMPtr<nsIDocShellTreeOwner> owner;
     item->GetTreeOwner(getter_AddRefs(owner));
 
     nsCOMPtr<nsITabChild> tabchild = do_GetInterface(owner);
-    if (!tabchild) {
-      NS_WARNING("tab is null");
+    // because owner implements nsITabChild, we can assume that it is
+    // the one and only TabChild.
+    TabChild* child = tabchild ? static_cast<TabChild*>(tabchild.get()) : nullptr;
+
+    if (MissingRequiredTabChild(child, "offlinecacheupdate")) {
       return NS_ERROR_FAILURE;
     }
 
     URIParams manifestURI, documentURI;
     SerializeURI(mManifestURI, manifestURI);
     SerializeURI(mDocumentURI, documentURI);
 
-    // because owner implements nsITabChild, we can assume that it is
-    // the one and only TabChild.
-    mozilla::dom::TabChild* child = static_cast<mozilla::dom::TabChild*>(tabchild.get());
-    
     nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
     if (observerService) {
       LOG(("Calling offline-cache-update-added"));
       observerService->NotifyObservers(static_cast<nsIOfflineCacheUpdate*>(this),
                                        "offline-cache-update-added",
                                        nullptr);
       LOG(("Done offline-cache-update-added"));