From d2903a568cc4f662988cb368f5877deaaa1a11bf Mon Sep 17 00:00:00 2001 From: Slava Egorov Date: Thu, 7 May 2026 04:18:06 -0700 Subject: [PATCH] [vm/io] Range check Filter_Process arguments Add a check both in the native implementation and on the Dart side (to avoid throwing uncatchable ApiError). Simplify native implementation: Dart_ListGetAsBytes has fast path for byte sized typed data lists, so there is no reason to inline the same fast path into the caller. Reported by Kyounghwan Kim (@drg2533) TEST=runtime/tests/vm/dart/regress_b508627933_test.dart Bug: b/508627933 Change-Id: I14c0f5270f143ed2386200241b13313f6a6a6964 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/500461 Commit-Queue: Slava Egorov Reviewed-by: Martin Kustermann --- runtime/bin/filter.cc | 55 +++++++------------ .../vm/dart/regress_b508627933_test.dart | 29 ++++++++++ sdk/lib/_internal/vm/bin/filter_patch.dart | 7 ++- 3 files changed, 54 insertions(+), 37 deletions(-) create mode 100644 runtime/tests/vm/dart/regress_b508627933_test.dart diff --git a/runtime/bin/filter.cc b/runtime/bin/filter.cc index eb9a35d5154..18860db4285 100644 --- a/runtime/bin/filter.cc +++ b/runtime/bin/filter.cc @@ -167,10 +167,6 @@ void FUNCTION_NAME(Filter_Process)(Dart_NativeArguments args) { Dart_Handle data_obj = Dart_GetNativeArgument(args, 1); intptr_t start = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2)); intptr_t end = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3)); - intptr_t chunk_length = end - start; - intptr_t length; - Dart_TypedData_Type type; - uint8_t* buffer = nullptr; Filter* filter = nullptr; Dart_Handle err = GetFilter(filter_obj, &filter); @@ -178,39 +174,26 @@ void FUNCTION_NAME(Filter_Process)(Dart_NativeArguments args) { Dart_PropagateError(err); } - Dart_Handle result = Dart_TypedDataAcquireData( - data_obj, &type, reinterpret_cast(&buffer), &length); - if (!Dart_IsError(result)) { - ASSERT(type == Dart_TypedData_kUint8 || type == Dart_TypedData_kInt8); - if (type != Dart_TypedData_kUint8 && type != Dart_TypedData_kInt8) { - Dart_TypedDataReleaseData(data_obj); - Dart_ThrowException(DartUtils::NewInternalError( - "Invalid argument passed to Filter_Process")); - } - uint8_t* zlib_buffer = new uint8_t[chunk_length]; - if (zlib_buffer == nullptr) { - Dart_TypedDataReleaseData(data_obj); - Dart_PropagateError(Dart_NewApiError("Could not allocate zlib buffer")); - } - - memmove(zlib_buffer, buffer + start, chunk_length); - Dart_TypedDataReleaseData(data_obj); - buffer = zlib_buffer; - } else { - err = Dart_ListLength(data_obj, &length); - if (Dart_IsError(err)) { - Dart_PropagateError(err); - } - buffer = new uint8_t[chunk_length]; - if (buffer == nullptr) { - Dart_PropagateError(Dart_NewApiError("Could not allocate buffer")); - } - err = Dart_ListGetAsBytes(data_obj, start, buffer, chunk_length); - if (Dart_IsError(err)) { - delete[] buffer; - Dart_PropagateError(err); - } + intptr_t length; + err = Dart_ListLength(data_obj, &length); + if (Dart_IsError(err)) { + Dart_PropagateError(err); } + if (!(0 <= start && start <= end && end <= length)) { + Dart_PropagateError(Dart_NewApiError("Invalid range")); + } + + intptr_t chunk_length = end - start; + uint8_t* buffer = new uint8_t[chunk_length]; + if (buffer == nullptr) { + Dart_PropagateError(Dart_NewApiError("Could not allocate buffer")); + } + err = Dart_ListGetAsBytes(data_obj, start, buffer, chunk_length); + if (Dart_IsError(err)) { + delete[] buffer; + Dart_PropagateError(err); + } + // Process will take ownership of buffer, if successful. if (!filter->Process(buffer, chunk_length)) { delete[] buffer; diff --git a/runtime/tests/vm/dart/regress_b508627933_test.dart b/runtime/tests/vm/dart/regress_b508627933_test.dart new file mode 100644 index 00000000000..d7311a7d2c3 --- /dev/null +++ b/runtime/tests/vm/dart/regress_b508627933_test.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Check that RawZLibFilter.process validates its arguments. + +import 'dart:io'; +import 'package:expect/expect.dart'; + +void main() { + Expect.throwsRangeError( + () => RawZLibFilter.deflateFilter().process([1, 2, 3], -1, 0), + ); + Expect.throwsRangeError( + () => RawZLibFilter.deflateFilter().process([1, 2, 3], -2, -1), + ); + Expect.throwsRangeError( + () => RawZLibFilter.deflateFilter().process([1, 2, 3], 0, -1), + ); + Expect.throwsRangeError( + () => RawZLibFilter.deflateFilter().process([1, 2, 3], 4, 2), + ); + Expect.throwsRangeError( + () => RawZLibFilter.deflateFilter().process([1, 2, 3], 2, 4), + ); + Expect.throwsRangeError( + () => RawZLibFilter.deflateFilter().process([1, 2, 3], 5, 6), + ); +} diff --git a/sdk/lib/_internal/vm/bin/filter_patch.dart b/sdk/lib/_internal/vm/bin/filter_patch.dart index c8222735514..34d496ad8e7 100644 --- a/sdk/lib/_internal/vm/bin/filter_patch.dart +++ b/sdk/lib/_internal/vm/bin/filter_patch.dart @@ -7,7 +7,12 @@ part of "common_patch.dart"; base class _FilterImpl extends NativeFieldWrapperClass1 implements RawZLibFilter { @pragma("vm:external-name", "Filter_Process") - external void process(List data, int start, int end); + external void _process(List data, int start, int end); + + void process(List data, int start, int end) { + RangeError.checkValidRange(start, end, data.length); + _process(data, start, end); + } @pragma("vm:external-name", "Filter_Processed") external List? processed({bool flush = true, bool end = false});