diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index e43edab690..da51abec63 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -943,7 +943,9 @@ ArrayBufferObject::wasmGrowToSizeInPlace(uint32_t newSize, // wasm-visible length of the buffer has been increased so it must be the // last fallible operation. - // byteLength can be at most INT32_MAX. + // byteLength can be at most INT32_MAX. Note: if this hard limit changes, + // update the clamping behavior in wasm::DecodeMemoryLimits and remove this + // comment as well as the one in wasmMovingGrowToSize. if (newSize > INT32_MAX) return false; @@ -974,6 +976,7 @@ ArrayBufferObject::wasmMovingGrowToSize(uint32_t newSize, // unmodified and valid. // byteLength can be at most INT32_MAX. + // See comment in wasmGrowToSizeInPlace about wasm::DecodeMemoryLimits. if (newSize > INT32_MAX) return false; diff --git a/js/src/wasm/WasmBinaryConstants.h b/js/src/wasm/WasmBinaryConstants.h index 3c8c49058c..616a9b05e8 100644 --- a/js/src/wasm/WasmBinaryConstants.h +++ b/js/src/wasm/WasmBinaryConstants.h @@ -363,7 +363,8 @@ static const unsigned MaxStringBytes = 100000; static const unsigned MaxLocals = 50000; static const unsigned MaxParams = 1000; static const unsigned MaxBrTableElems = 1000000; -static const unsigned MaxMemoryInitialBytes = 1024 * 1024 * 1024; +static const unsigned MaxMemoryInitialPages = 16384; +static const unsigned MaxMemoryMaximumPages = 65536; static const unsigned MaxModuleBytes = 1024 * 1024 * 1024; static const unsigned MaxFunctionBytes = 128 * 1024; diff --git a/js/src/wasm/WasmValidate.cpp b/js/src/wasm/WasmValidate.cpp index 6617ff9ff8..0904b741c2 100644 --- a/js/src/wasm/WasmValidate.cpp +++ b/js/src/wasm/WasmValidate.cpp @@ -917,20 +917,23 @@ DecodeMemoryLimits(Decoder& d, ModuleEnvironment* env) if (!DecodeLimits(d, &memory)) return false; + if (memory.initial > MaxMemoryInitialPages) + return d.fail("initial memory size too big"); CheckedInt initialBytes = memory.initial; initialBytes *= PageSize; - if (!initialBytes.isValid() || initialBytes.value() > MaxMemoryInitialBytes) - return d.fail("initial memory size too big"); + MOZ_ASSERT(initialBytes.isValid()); memory.initial = initialBytes.value(); if (memory.maximum) { + if (*memory.maximum > MaxMemoryMaximumPages) + return d.fail("maximum memory size too big"); CheckedInt maximumBytes = *memory.maximum; maximumBytes *= PageSize; - if (!maximumBytes.isValid()) - return d.fail("maximum memory size too big"); - memory.maximum = Some(maximumBytes.value()); + // Clamp the maximum memory value to UINT32_MAX; it's not semantically + // visible since growing will fail for values greater than INT32_MAX. + memory.maximum = Some(maximumBytes.isValid() ? maximumBytes.value() : UINT32_MAX); } env->memoryUsage = MemoryUsage::Unshared; @@ -1547,7 +1550,7 @@ DecodeDataSection(Decoder& d, ModuleEnvironment* env) if (!d.readVarU32(&seg.length)) return d.fail("expected segment size"); - if (seg.length > MaxMemoryInitialBytes) + if (seg.length > MaxMemoryInitialPages * PageSize) return d.fail("segment size too big"); seg.bytecodeOffset = d.currentOffset();