Bug 833935 - Warn when child is about to issue illegal IPDL request. r=jdm a=blocking-b2g
authorJason Duell <jduell.mcbugs@gmail.com>
Thu, 24 Jan 2013 19:24:00 +0000
changeset 118337 94a2d6fcdfde
parent 118336 b69e1466e761
child 118338 893e68b73efd
push id360
push userjosh@joshmatthews.net
push dateFri, 25 Jan 2013 10:38:33 +0000
reviewersjdm, blocking-b2g
bugs833935
milestone18.0
Bug 833935 - Warn when child is about to issue illegal IPDL request. r=jdm a=blocking-b2g
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
@@ -88,15 +92,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
@@ -797,16 +797,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;
@@ -1029,16 +1032,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
 //
@@ -400,29 +403,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"));