summaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-02-09 08:53:46 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-02-09 08:53:46 +0100
commit8cecf8d5208f3945b35f879bba3015bb1a11bec6 (patch)
tree0926f5c21f9d10cf929e4c35e7d7e8e8c084dbf5 /js
parent8cd777888a40e987ad536ab68421068f5c06d83b (diff)
parent92104eb6828ba026550e1f4a3c6890c5b8254d36 (diff)
downloadUXP-8cecf8d5208f3945b35f879bba3015bb1a11bec6.tar
UXP-8cecf8d5208f3945b35f879bba3015bb1a11bec6.tar.gz
UXP-8cecf8d5208f3945b35f879bba3015bb1a11bec6.tar.lz
UXP-8cecf8d5208f3945b35f879bba3015bb1a11bec6.tar.xz
UXP-8cecf8d5208f3945b35f879bba3015bb1a11bec6.zip
Merge branch 'ported-upstream'
Diffstat (limited to 'js')
-rw-r--r--js/src/jit/Ion.cpp3
-rw-r--r--js/src/jsapi.h2
-rw-r--r--js/src/jsfun.cpp4
-rw-r--r--js/src/jsscript.cpp50
-rw-r--r--js/src/shell/js.cpp4
-rw-r--r--js/src/vm/SharedArrayObject.cpp34
-rw-r--r--js/src/vm/TypeInference.cpp12
-rw-r--r--js/src/vm/TypeInference.h4
-rw-r--r--js/src/vm/Xdr.h20
-rw-r--r--js/src/wasm/WasmJS.cpp18
-rw-r--r--js/xpconnect/wrappers/AccessCheck.cpp14
11 files changed, 106 insertions, 59 deletions
diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
index 2a158ed7e..c61b414e0 100644
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -568,9 +568,6 @@ jit::LinkIonScript(JSContext* cx, HandleScript calleeScript)
// doesn't has code to handle it after linking happened. So it's
// not OK to throw a catchable exception from there.
cx->clearPendingException();
-
- // Reset the TypeZone's compiler output for this script, if any.
- InvalidateCompilerOutputsForScript(cx, calleeScript);
}
}
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index de1425c9b..2d6ff462c 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5927,7 +5927,7 @@ enum TranscodeResult
TranscodeResult_Failure_BadBuildId = TranscodeResult_Failure | 0x1,
TranscodeResult_Failure_RunOnceNotSupported = TranscodeResult_Failure | 0x2,
TranscodeResult_Failure_AsmJSNotSupported = TranscodeResult_Failure | 0x3,
- TranscodeResult_Failure_UnknownClassKind = TranscodeResult_Failure | 0x4,
+ TranscodeResult_Failure_BadDecode = TranscodeResult_Failure | 0x4,
// A error, the JSContext has a pending exception.
TranscodeResult_Throw = 0x200
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 9fffce448..c952441ad 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -641,6 +641,10 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
objp.set(fun);
}
+ // Verify marker at end of function to detect buffer truncation.
+ if (!xdr->codeMarker(0xA0129CD1))
+ return false;
+
return true;
}
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index 2e02aa63d..10821f26a 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -75,24 +75,19 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
{
JSContext* cx = xdr->cx();
- /*
- * A script constant can be an arbitrary primitive value as they are used
- * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
- * bug 407186.
- */
enum ConstTag {
- SCRIPT_INT = 0,
- SCRIPT_DOUBLE = 1,
- SCRIPT_ATOM = 2,
- SCRIPT_TRUE = 3,
- SCRIPT_FALSE = 4,
- SCRIPT_NULL = 5,
- SCRIPT_OBJECT = 6,
- SCRIPT_VOID = 7,
- SCRIPT_HOLE = 8
+ SCRIPT_INT,
+ SCRIPT_DOUBLE,
+ SCRIPT_ATOM,
+ SCRIPT_TRUE,
+ SCRIPT_FALSE,
+ SCRIPT_NULL,
+ SCRIPT_OBJECT,
+ SCRIPT_VOID,
+ SCRIPT_HOLE
};
- uint32_t tag;
+ ConstTag tag;
if (mode == XDR_ENCODE) {
if (vp.isInt32()) {
tag = SCRIPT_INT;
@@ -116,7 +111,7 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
}
}
- if (!xdr->codeUint32(&tag))
+ if (!xdr->codeEnum32(&tag))
return false;
switch (tag) {
@@ -182,6 +177,10 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
if (mode == XDR_DECODE)
vp.setMagic(JS_ELEMENTS_HOLE);
break;
+ default:
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR value kind");
+ return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
return true;
}
@@ -742,11 +741,20 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
case ScopeKind::Module:
MOZ_CRASH("NYI");
break;
+ default:
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR scope kind");
+ return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
if (mode == XDR_DECODE)
vector[i].init(scope);
}
+
+ // Verify marker to detect data corruption after decoding scope data. A
+ // mismatch here indicates we will almost certainly crash in release.
+ if (!xdr->codeMarker(0xF81F7F5A))
+ return false;
}
/*
@@ -832,12 +840,18 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
}
default: {
- MOZ_ASSERT(false, "Unknown class kind.");
- return xdr->fail(JS::TranscodeResult_Failure_UnknownClassKind);
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR class kind");
+ return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
}
}
+ // Verify marker to detect data corruption after decoding object data. A
+ // mismatch here indicates we will almost certainly crash in release.
+ if (!xdr->codeMarker(0x223DB179))
+ return false;
+
if (ntrynotes != 0) {
JSTryNote* tnfirst = script->trynotes()->vector;
MOZ_ASSERT(script->trynotes()->length == ntrynotes);
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 88d482a23..3f56981cd 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1546,9 +1546,9 @@ ConvertTranscodeResultToJSException(JSContext* cx, JS::TranscodeResult rv)
MOZ_ASSERT(!cx->isExceptionPending());
JS_ReportErrorASCII(cx, "Asm.js is not supported by XDR");
return false;
- case JS::TranscodeResult_Failure_UnknownClassKind:
+ case JS::TranscodeResult_Failure_BadDecode:
MOZ_ASSERT(!cx->isExceptionPending());
- JS_ReportErrorASCII(cx, "Unknown class kind, go fix it.");
+ JS_ReportErrorASCII(cx, "XDR data corruption");
return false;
case JS::TranscodeResult_Throw:
diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp
index 730578cd4..c69306aac 100644
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -116,22 +116,22 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
if (allocSize <= length)
return nullptr;
+ // Test >= to guard against the case where multiple extant runtimes
+ // race to allocate.
+ if (++numLive >= maxLive) {
+ JSRuntime* rt = cx->runtime();
+ if (rt->largeAllocationFailureCallback)
+ rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
+ if (numLive >= maxLive) {
+ numLive--;
+ return nullptr;
+ }
+ }
+
bool preparedForAsmJS = jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length);
void* p = nullptr;
if (preparedForAsmJS) {
- // Test >= to guard against the case where multiple extant runtimes
- // race to allocate.
- if (++numLive >= maxLive) {
- JSRuntime* rt = cx->runtime();
- if (rt->largeAllocationFailureCallback)
- rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
- if (numLive >= maxLive) {
- numLive--;
- return nullptr;
- }
- }
-
uint32_t mappedSize = SharedArrayMappedSize(allocSize);
// Get the entire reserved region (with all pages inaccessible)
@@ -154,8 +154,10 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
# endif
} else {
p = MapMemory(allocSize, true);
- if (!p)
+ if (!p) {
+ numLive--;
return nullptr;
+ }
}
uint8_t* buffer = reinterpret_cast<uint8_t*>(p) + gc::SystemPageSize();
@@ -189,8 +191,6 @@ SharedArrayRawBuffer::dropReference()
uint32_t allocSize = SharedArrayAllocSize(this->length);
if (this->preparedForAsmJS) {
- numLive--;
-
uint32_t mappedSize = SharedArrayMappedSize(allocSize);
UnmapMemory(address, mappedSize);
@@ -202,6 +202,10 @@ SharedArrayRawBuffer::dropReference()
} else {
UnmapMemory(address, allocSize);
}
+
+ // Decrement the buffer counter at the end -- otherwise, a race condition
+ // could enable the creation of unlimited buffers.
+ numLive--;
}
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 5b55ba947..2a7762e4f 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -1511,18 +1511,6 @@ js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList
return true;
}
-void
-js::InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script)
-{
- TypeZone& types = cx->zone()->types;
- if (types.compilerOutputs) {
- for (auto& co : *types.compilerOutputs) {
- if (co.script() == script)
- co.invalidate();
- }
- }
-}
-
static void
CheckDefinitePropertiesTypeSet(JSContext* cx, TemporaryTypeSet* frozen, StackTypeSet* actual)
{
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 45b2711e2..9ba1c3cc8 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -1093,10 +1093,6 @@ bool
FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
RecompileInfo* precompileInfo, bool* isValidOut);
-// Reset any CompilerOutput present for a script.
-void
-InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script);
-
// Update the actual types in any scripts queried by constraints with any
// speculative types added during the definite properties analysis.
void
diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h
index 8e8c5bf17..2a5c62480 100644
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -143,13 +143,17 @@ class XDRState {
template <typename T>
bool codeEnum32(T* val, typename mozilla::EnableIf<mozilla::IsEnum<T>::value, T>::Type * = NULL)
{
+ // Mix the enumeration value with a random magic number, such that a
+ // corruption with a low-ranged value (like 0) is less likely to cause a
+ // miss-interpretation of the XDR content and instead cause a failure.
+ const uint32_t MAGIC = 0xAF647BCE;
uint32_t tmp;
if (mode == XDR_ENCODE)
- tmp = uint32_t(*val);
+ tmp = uint32_t(*val) ^ MAGIC;
if (!codeUint32(&tmp))
return false;
if (mode == XDR_DECODE)
- *val = T(tmp);
+ *val = T(tmp ^ MAGIC);
return true;
}
@@ -167,6 +171,18 @@ class XDRState {
return true;
}
+ bool codeMarker(uint32_t magic) {
+ uint32_t actual = magic;
+ if (!codeUint32(&actual))
+ return false;
+ if (actual != magic) {
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR marker");
+ return fail(JS::TranscodeResult_Failure_BadDecode);
+ }
+ return true;
+ }
+
bool codeBytes(void* bytes, size_t len) {
if (len == 0)
return true;
diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp
index 07d6331b8..0b030c844 100644
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -1484,6 +1484,20 @@ const JSPropertySpec WasmTableObject::properties[] =
JS_PS_END
};
+static bool
+ToTableIndex(JSContext* cx, HandleValue v, const Table& table, const char* noun, uint32_t* index)
+{
+ if (!ToNonWrappingUint32(cx, v, UINT32_MAX, "Table", noun, index))
+ return false;
+
+ if (*index >= table.length()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, "Table", noun);
+ return false;
+ }
+
+ return true;
+}
+
/* static */ bool
WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
{
@@ -1491,7 +1505,7 @@ WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
const Table& table = tableObj->table();
uint32_t index;
- if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "get index", &index))
+ if (!ToTableIndex(cx, args.get(0), table, "get index", &index))
return false;
ExternalTableElem& elem = table.externalArray()[index];
@@ -1530,7 +1544,7 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
return false;
uint32_t index;
- if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "set index", &index))
+ if (!ToTableIndex(cx, args.get(0), table, "set index", &index))
return false;
RootedFunction value(cx);
diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp
index 085e7100e..d17c0629e 100644
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -307,6 +307,20 @@ ExposedPropertiesOnly::check(JSContext* cx, HandleObject wrapper, HandleId id, W
// Unfortunately, |cx| can be in either compartment when we call ::check. :-(
JSAutoCompartment ac(cx, wrappedObject);
+ // Proxies are not allowed in the proto chain.
+ RootedObject o(cx, wrappedObject);
+ while (o) {
+ JSObject* unwrapped = js::IsWrapper(o) ? js::CheckedUnwrap(o, false) : o;
+ if (!unwrapped || js::IsProxy(unwrapped))
+ return false;
+
+ RootedObject p(cx);
+ if (!js::GetObjectProto(cx, o, &p))
+ return false;
+
+ o = p;
+ }
+
bool found = false;
if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found))
return false;