Bug 1272423 - Refuse to send large messages via the message manager. r=baku
authorAndrew McCreight <continuation@gmail.com>
Thu, 09 Jun 2016 09:35:19 -0700
changeset 301377 0a4f4e0aa89a6fdc6fabeb39e7fcd7a63f43bb93
parent 301376 b0d48deeae7b5855b015353b3d69acf9f2c954dd
child 301378 9e6cbeb45a5c61364128b127f6511cc0052a1041
push id30332
push usercbook@mozilla.com
push dateTue, 21 Jun 2016 10:33:59 +0000
treeherderautoland@0ffa18cfc8b4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1272423
milestone50.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 1272423 - Refuse to send large messages via the message manager. r=baku Large IPC messages will hit a fatal assert, so reject message manager messages earlier. Also, collect telemetry on the rejected messages.
dom/base/nsFrameMessageManager.cpp
toolkit/components/telemetry/Histograms.json
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -45,16 +45,17 @@
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "nsPrintfCString.h"
 #include "nsXULAppAPI.h"
 #include "nsQueryObject.h"
 #include <algorithm>
+#include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
@@ -698,30 +699,43 @@ nsFrameMessageManager::SendRpcMessage(co
                                       JSContext* aCx,
                                       uint8_t aArgc,
                                       JS::MutableHandle<JS::Value> aRetval)
 {
   return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc,
                      aRetval, false);
 }
 
-static void
-RecordMessageSize(size_t aDataLength, const nsAString& aMessageName)
+static bool
+AllowMessage(size_t aDataLength, const nsAString& aMessageName)
 {
   static const size_t kMinTelemetryMessageSize = 8192;
 
   if (aDataLength < kMinTelemetryMessageSize) {
-    return;
+    return true;
   }
 
   NS_ConvertUTF16toUTF8 messageName(aMessageName);
   messageName.StripChars("0123456789");
 
   Telemetry::Accumulate(Telemetry::MESSAGE_MANAGER_MESSAGE_SIZE2, messageName,
                         aDataLength);
+
+  // A message includes more than structured clone data, so subtract
+  // 20KB to make it more likely that a message within this bound won't
+  // result in an overly large IPC message.
+  static const size_t kMaxMessageSize = IPC::Channel::kMaximumMessageSize - 20 * 1024;
+  if (aDataLength < kMaxMessageSize) {
+    return true;
+  }
+
+  Telemetry::Accumulate(Telemetry::REJECTED_MESSAGE_MANAGER_MESSAGE,
+                        messageName);
+
+  return false;
 }
 
 nsresult
 nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
                                    JS::Handle<JS::Value> aJSON,
                                    JS::Handle<JS::Value> aObjects,
                                    nsIPrincipal* aPrincipal,
                                    JSContext* aCx,
@@ -741,17 +755,19 @@ nsFrameMessageManager::SendMessage(const
     return NS_ERROR_UNEXPECTED;
   }
 
   StructuredCloneData data;
   if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, JS::UndefinedHandleValue, data)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
-  RecordMessageSize(data.DataLength(), aMessageName);
+  if (!AllowMessage(data.DataLength(), aMessageName)) {
+    return NS_ERROR_FAILURE;
+  }
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
   nsTArray<StructuredCloneData> retval;
 
@@ -823,17 +839,19 @@ nsFrameMessageManager::DispatchAsyncMess
                                             JSContext* aCx,
                                             uint8_t aArgc)
 {
   StructuredCloneData data;
   if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, aTransfers, data)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
-  RecordMessageSize(data.DataLength(), aMessageName);
+  if (!AllowMessage(data.DataLength(), aMessageName)) {
+    return NS_ERROR_FAILURE;
+  }
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
   return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
                                       aPrincipal);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -10779,16 +10779,24 @@
     "expires_in_version": "55",
     "kind": "exponential",
     "low": 8192,
     "high": 8000000,
     "n_buckets": 50,
     "keyed": true,
     "description": "Each key is the message name, with digits removed, from an async message manager message that was larger than 8192 bytes, recorded in the sending process at the time of sending."
   },
+  "REJECTED_MESSAGE_MANAGER_MESSAGE": {
+    "alert_emails": ["amccreight@mozilla.com"],
+    "bug_numbers": [1272423],
+    "expires_in_version": "55",
+    "kind": "count",
+    "keyed": true,
+    "description": "Each key is the message name, with digits removed, from an async message manager message that was rejected for being over approximately 128MB, recorded in the sending process at the time of sending."
+  },
   "SANDBOX_BROKER_INITIALIZED": {
     "alert_emails": ["bowen@mozilla.com"],
     "bug_numbers": [1256992],
     "expires_in_version": "55",
     "kind": "boolean",
     "description": "Result of call to SandboxBroker::Initialize"
   },
   "SANDBOX_CAPABILITIES_SECCOMP_BPF": {