Bug 1425612 - Better error messages for invalid structured clone data. r=sfink, a=abillings.
☠☠ backed out by 600bee353e15 ☠ ☠
authorJason Orendorff <jorendorff@mozilla.com>
Sat, 16 Dec 2017 07:16:26 -0600
changeset 450450 a8e2b4cf8e26b900983e33cc2fb6b48f1e5747b2
parent 450449 f10263c3babef5f70e1e8fdb9e52c2de15cf22e1
child 450451 600bee353e155608a5832f7eb9d5e42987d66591
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink, abillings
bugs1425612
milestone59.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 1425612 - Better error messages for invalid structured clone data. r=sfink, a=abillings.
js/src/vm/StructuredClone.cpp
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1911,16 +1911,22 @@ JSStructuredCloneReader::readTypedArray(
     } else {
         if (!startRead(&v))
             return false;
         uint64_t n;
         if (!in.read(&n))
             return false;
         byteOffset = n;
     }
+    if (!v.isObject() || !v.toObject().is<ArrayBufferObject>()) {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                  "typed array must be backed by an ArrayBuffer");
+        return false;
+    }
+
     RootedObject buffer(context(), &v.toObject());
     RootedObject obj(context(), nullptr);
 
     switch (arrayType) {
       case Scalar::Int8:
         obj = JS_NewInt8ArrayWithBuffer(context(), buffer, byteOffset, nelems);
         break;
       case Scalar::Uint8:
@@ -1968,16 +1974,21 @@ JSStructuredCloneReader::readDataView(ui
     Value dummy = UndefinedValue();
     if (!allObjs.append(dummy))
         return false;
 
     // Read the ArrayBuffer object and its contents (but no properties).
     RootedValue v(context());
     if (!startRead(&v))
         return false;
+    if (!v.isObject() || !v.toObject().is<ArrayBufferObject>()) {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                  "DataView must be backed by an ArrayBuffer");
+        return false;
+    }
 
     // Read byteOffset.
     uint64_t n;
     if (!in.read(&n))
         return false;
     uint32_t byteOffset = n;
 
     RootedObject buffer(context(), &v.toObject());
@@ -2023,18 +2034,21 @@ JSStructuredCloneReader::readSharedArray
 
     if (!context()->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_DISABLED);
         return false;
     }
 
     // We must not transfer buffer pointers cross-process.  The cloneDataPolicy
     // in the sender should guard against this; check that it does.
-
-    MOZ_RELEASE_ASSERT(storedScope <= JS::StructuredCloneScope::SameProcessDifferentThread);
+    if (storedScope > JS::StructuredCloneScope::SameProcessDifferentThread) {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                  "can't transfer SharedArrayBuffer cross-process");
+        return false;
+    }
 
     // The new object will have a new reference to the rawbuf.
 
     if (!rawbuf->addReference()) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
         return false;
     }
 
@@ -2046,24 +2060,33 @@ JSStructuredCloneReader::readSharedArray
 
     vp.setObject(*obj);
     return true;
 }
 
 bool
 JSStructuredCloneReader::readSharedWasmMemory(uint32_t nbytes, MutableHandleValue vp)
 {
-    MOZ_ASSERT(nbytes == 0);
+    if (nbytes != 0) {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                  "invalid shared wasm memory tag");
+        return false;
+    }
 
     JSContext* cx = context();
 
     // Read the SharedArrayBuffer object.
     RootedValue payload(cx);
     if (!startRead(&payload))
         return false;
+    if (!payload.isObject() || !payload.toObject().is<SharedArrayBufferObject>()) {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                  "shared wasm memory must be backed by a SharedArrayBuffer");
+        return false;
+    }
 
     Rooted<ArrayBufferObjectMaybeShared*> sab(
         cx, &payload.toObject().as<SharedArrayBufferObject>());
 
     // Construct the memory.
     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmMemory).toObject());
     RootedObject memory(cx, WasmMemoryObject::create(cx, sab, proto));
     if (!memory)
@@ -2076,17 +2099,21 @@ JSStructuredCloneReader::readSharedWasmM
 /*
  * Read in the data for a structured clone version 1 ArrayBuffer, performing
  * endianness-conversion while reading.
  */
 bool
 JSStructuredCloneReader::readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems,
                                            MutableHandleValue vp)
 {
-    MOZ_ASSERT(arrayType <= Scalar::Uint8Clamped);
+    if (arrayType > Scalar::Uint8Clamped) {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                  "invalid TypedArray type");
+        return false;
+    }
 
     mozilla::CheckedInt<size_t> nbytes =
         mozilla::CheckedInt<size_t>(nelems) *
         TypedArrayElemSize(static_cast<Scalar::Type>(arrayType));
     if (!nbytes.isValid() || nbytes.value() > UINT32_MAX) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
                                   JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "invalid typed array size");
@@ -2348,16 +2375,24 @@ JSStructuredCloneReader::readHeader()
 
     if (tag != SCTAG_HEADER) {
         // Old structured clone buffer. We must have read it from disk or
         // somewhere, so we can assume it's scope-compatible.
         return true;
     }
 
     MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
+    if (data != uint32_t(JS::StructuredCloneScope::SameProcessSameThread) &&
+        data != uint32_t(JS::StructuredCloneScope::SameProcessDifferentThread) &&
+        data != uint32_t(JS::StructuredCloneScope::DifferentProcess))
+    {
+        JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+                                  "invalid structured clone scope");
+        return false;
+    }
     storedScope = JS::StructuredCloneScope(data);
     if (storedScope < allowedScope) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
                                   "incompatible structured clone scope");
         return false;
     }
 
     return true;