Skip to content

Commit 9542895

Browse files
jakobkummerowV8 LUCI CQ
authored andcommitted
[wasm][streaming] Properly check max module size
and allow d8-based tests for it. Fixed: 368241697 Change-Id: Iddc9f7e669de7a1d79dccbc99bcc5fb43dad67a1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5886728 Reviewed-by: Clemens Backes <[email protected]> Reviewed-by: Matthias Liedtke <[email protected]> Auto-Submit: Jakob Kummerow <[email protected]> Commit-Queue: Jakob Kummerow <[email protected]> Cr-Commit-Position: refs/heads/main@{#96272}
1 parent 8b96919 commit 9542895

3 files changed

Lines changed: 34 additions & 11 deletions

File tree

src/wasm/streaming-decoder.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ void AsyncStreamingDecoder::Finish(bool can_use_compiled_module) {
294294
if (!full_wire_bytes_.back().empty()) {
295295
size_t total_length = 0;
296296
for (auto& bytes : full_wire_bytes_) total_length += bytes.size();
297+
if (ok()) {
298+
// {DecodeSectionLength} enforces this with graceful error reporting.
299+
CHECK_LE(total_length, max_module_size());
300+
}
297301
auto all_bytes = base::OwnedVector<uint8_t>::NewForOverwrite(total_length);
298302
uint8_t* ptr = all_bytes.begin();
299303
for (auto& bytes : full_wire_bytes_) {
@@ -627,6 +631,18 @@ std::unique_ptr<AsyncStreamingDecoder::DecodingState>
627631
AsyncStreamingDecoder::DecodeSectionLength::NextWithValue(
628632
AsyncStreamingDecoder* streaming) {
629633
TRACE_STREAMING("DecodeSectionLength(%zu)\n", value_);
634+
// Check if this section fits into the overall module length limit.
635+
// Note: {this->module_offset_} is the position of the section ID byte,
636+
// {streaming->module_offset_} is the start of the section's payload (i.e.
637+
// right after the just-decoded section length varint).
638+
// The latter can already exceed the max module size, when the previous
639+
// section barely fit into it, and this new section's ID or length crossed
640+
// the threshold.
641+
uint32_t payload_start = streaming->module_offset();
642+
size_t max_size = max_module_size();
643+
if (payload_start > max_size || max_size - payload_start < value_) {
644+
return streaming->ToErrorState();
645+
}
630646
SectionBuffer* buf =
631647
streaming->CreateNewBuffer(module_offset_, section_id_, value_,
632648
buffer().SubVector(0, bytes_consumed_));

src/wasm/wasm-engine.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,10 +2088,11 @@ uint32_t max_table_init_entries() {
20882088

20892089
// {max_module_size} is declared in wasm-limits.h.
20902090
size_t max_module_size() {
2091-
// Clamp the value of --wasm-max-module-size between 16 and just below 2GB.
2091+
// Clamp the value of --wasm-max-module-size between 16 and the maximum
2092+
// that the implementation supports.
20922093
constexpr size_t kMin = 16;
2093-
constexpr size_t kMax = RoundDown<kSystemPointerSize>(size_t{kMaxInt});
2094-
static_assert(kMin <= kV8MaxWasmModuleSize && kV8MaxWasmModuleSize <= kMax);
2094+
constexpr size_t kMax = kV8MaxWasmModuleSize;
2095+
static_assert(kMin <= kV8MaxWasmModuleSize);
20952096
return std::clamp(v8_flags.wasm_max_module_size.value(), kMin, kMax);
20962097
}
20972098

src/wasm/wasm-js.cc

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ GET_FIRST_ARGUMENT_AS(Tag)
202202
#undef GET_FIRST_ARGUMENT_AS
203203

204204
i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
205-
const v8::FunctionCallbackInfo<v8::Value>& info, ErrorThrower* thrower,
206-
bool* is_shared) {
205+
const v8::FunctionCallbackInfo<v8::Value>& info, size_t max_length,
206+
ErrorThrower* thrower, bool* is_shared) {
207207
DCHECK(i::ValidateCallbackInfo(info));
208208
const uint8_t* start = nullptr;
209209
size_t length = 0;
@@ -234,7 +234,6 @@ i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
234234
if (length == 0) {
235235
thrower->CompileError("BufferSource argument is empty");
236236
}
237-
size_t max_length = i::wasm::max_module_size();
238237
if (length > max_length) {
239238
// The spec requires a CompileError for implementation-defined limits, see
240239
// https://webassembly.github.io/spec/js-api/index.html#limits.
@@ -644,7 +643,8 @@ void WebAssemblyCompileImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
644643
new AsyncCompilationResolver(isolate, context, promise_resolver));
645644

646645
bool is_shared = false;
647-
auto bytes = GetFirstArgumentAsBytes(info, &thrower, &is_shared);
646+
auto bytes = GetFirstArgumentAsBytes(info, i::wasm::max_module_size(),
647+
&thrower, &is_shared);
648648
if (thrower.error()) {
649649
resolver->OnCompilationFailed(thrower.Reify());
650650
return;
@@ -676,8 +676,11 @@ void WasmStreamingCallbackForTesting(
676676
v8::WasmStreaming::Unpack(info.GetIsolate(), info.Data());
677677

678678
bool is_shared = false;
679+
// We don't check the buffer length up front, to allow d8 to test that the
680+
// streaming decoder implementation handles overly large inputs correctly.
681+
size_t unlimited = std::numeric_limits<size_t>::max();
679682
i::wasm::ModuleWireBytes bytes =
680-
GetFirstArgumentAsBytes(info, &thrower, &is_shared);
683+
GetFirstArgumentAsBytes(info, unlimited, &thrower, &is_shared);
681684
if (thrower.error()) {
682685
streaming->Abort(Utils::ToLocal(thrower.Reify()));
683686
return;
@@ -778,7 +781,8 @@ void WebAssemblyValidateImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
778781
ErrorThrower thrower(i_isolate, "WebAssembly.validate()");
779782

780783
bool is_shared = false;
781-
auto bytes = GetFirstArgumentAsBytes(info, &thrower, &is_shared);
784+
auto bytes = GetFirstArgumentAsBytes(info, i::wasm::max_module_size(),
785+
&thrower, &is_shared);
782786

783787
v8::ReturnValue<v8::Value> return_value = info.GetReturnValue();
784788

@@ -857,7 +861,8 @@ void WebAssemblyModuleImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
857861
}
858862

859863
bool is_shared = false;
860-
auto bytes = GetFirstArgumentAsBytes(info, &thrower, &is_shared);
864+
auto bytes = GetFirstArgumentAsBytes(info, i::wasm::max_module_size(),
865+
&thrower, &is_shared);
861866

862867
if (thrower.error()) {
863868
return;
@@ -1175,7 +1180,8 @@ void WebAssemblyInstantiateImpl(
11751180
}
11761181

11771182
bool is_shared = false;
1178-
auto bytes = GetFirstArgumentAsBytes(info, &thrower, &is_shared);
1183+
auto bytes = GetFirstArgumentAsBytes(info, i::wasm::max_module_size(),
1184+
&thrower, &is_shared);
11791185
if (thrower.error()) {
11801186
resolver->OnInstantiationFailed(thrower.Reify());
11811187
return;

0 commit comments

Comments
 (0)