From ef794bb39b7c5d98bd198965c987089ca146c4dd Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 8 Feb 2018 19:22:33 +0100 Subject: Don't allow proxies in the proto chain. --- js/xpconnect/wrappers/AccessCheck.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'js') 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; -- cgit v1.2.3 From 50f6ced9fc76b71b4685d8363d9615204ad6c897 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 23 Nov 2017 06:33:06 +0100 Subject: Remove unnecessary InvalidateCompilerOutputsForScript call. --- js/src/jit/Ion.cpp | 3 --- js/src/vm/TypeInference.cpp | 12 ------------ js/src/vm/TypeInference.h | 4 ---- 3 files changed, 19 deletions(-) (limited to 'js') 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/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 -- cgit v1.2.3 From a8d25a2ed6e6306fb073578158572b04749f7891 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 25 Jan 2018 22:15:26 +0100 Subject: WASM: Separate out ToTableIndex() --- js/src/wasm/WasmJS.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'js') 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); -- cgit v1.2.3 From 91d9f5d658d646e1ad1c0b3a28a9bba0094a44c6 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 26 Jan 2018 21:26:07 +0100 Subject: Make XDR decoding more robust. --- js/src/jsapi.h | 2 +- js/src/jsfun.cpp | 4 ++++ js/src/jsscript.cpp | 50 ++++++++++++++++++++++++++++++++------------------ js/src/shell/js.cpp | 4 ++-- js/src/vm/Xdr.h | 20 ++++++++++++++++++-- 5 files changed, 57 insertions(+), 23 deletions(-) (limited to 'js') diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 9ad3e757f..089e22b09 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* 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* 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* xdr, MutableHandleValue vp) } } - if (!xdr->codeUint32(&tag)) + if (!xdr->codeEnum32(&tag)) return false; switch (tag) { @@ -182,6 +177,10 @@ js::XDRScriptConst(XDRState* 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* 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* 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/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 bool codeEnum32(T* val, typename mozilla::EnableIf::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; -- cgit v1.2.3 From 92104eb6828ba026550e1f4a3c6890c5b8254d36 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 4 Jan 2018 22:24:58 +0100 Subject: Limit the number of SharedArrayBuffers in normal JS code (not just asm.js). --- js/src/vm/SharedArrayObject.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'js') 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(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--; } -- cgit v1.2.3