CVE-2026-8509
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
iftensorflow/lite/kernels/strided_slice.cc |
modified |
Files Changed
tensorflow/lite/kernels/strided_slice.cc
Patch
From b476481b77f6e939e813ac93df22a4a6e7a3dd57 Mon Sep 17 00:00:00 2001 From: Reilly Grant <[email protected]> Date: Tue, 24 Mar 2026 11:42:42 -0700 Subject: [PATCH] [M147] Avoid casting dimensions to float in STRIDED_SLICE ResizeOutputTensor Single-precision floats can only precisely represent values up to 2^24. If the size of the output slice were too large the previous logic would calculate the incorrect output dimension. (Cherry-picked from commit 8cedce08e98d8f11e3ee5ced7a25fb830ccfb935.) PiperOrigin-RevId: 885789312 Bug: 493310462 Change-Id: I7a3a1fadc152b1716e8e45e0cdf1dc125f7d82fd --- diff --git a/tensorflow/lite/kernels/strided_slice.cc b/tensorflow/lite/kernels/strided_slice.cc index 5450c48..8444fb1 100644 --- a/tensorflow/lite/kernels/strided_slice.cc +++ b/tensorflow/lite/kernels/strided_slice.cc @@ -222,8 +222,18 @@ // This is valid for both positive and negative strides dim_shape = end - begin; } - dim_shape = std::ceil((dim_shape) / static_cast<float>(stride)); - dim_shape = dim_shape < 0 ? 0 : dim_shape; + // Ensure we can do an integer division (rounding up) even when dealing with + // negative numbers. + if (dim_shape < 0 != stride < 0) { + dim_shape = 0; + } else { + if (stride < 0) { + TFLITE_CHECK_LT(dim_shape, 0); + dim_shape = -dim_shape; + stride = -stride; + } + dim_shape = (dim_shape + stride - 1) / stride; + } output_shape_vector.push_back(dim_shape); }
Original Bug Report
Heap buffer overflow in TFLite StridedSlice via WebNN slice() due to float32 precision loss in output shape computation
Heap buffer overflow in TFLite StridedSlice via WebNN slice() due to float32 precision loss in output shape computation
Summary
The TFLite STRIDED_SLICE kernel computes output tensor dimensions using float32 arithmetic, which silently loses precision for dimension values exceeding 2^24. The WebNN validation layer computes the same dimensions using exact integer arithmetic, so the graph passes validation while TFLite allocates a smaller output buffer than the data actually written during evaluation. A web page can exploit this discrepancy to trigger a heap buffer overflow in the GPU process through the WebNN slice() API. Affected platforms: Linux, Windows, macOS, ChromeOS (any platform where WebNN uses the TFLite backend).
Bisect
Introducing Commit: 6dfe00ca4114
- Date: 2018-01-23
- Author: A. Unique TensorFlower
- Review: PiperOrigin-RevId: 183020501
This commit added the STRIDED_SLICE kernel to TFLite with the float32 division in ResizeOutputTensor. The bug became web-reachable when Chrome integrated WebNN with the TFLite backend and translated MLGraphBuilder.slice() into the TFLite STRIDED_SLICE op.
Root Cause
When TFLite prepares a STRIDED_SLICE operation, ResizeOutputTensor computes the output dimension along each axis by dividing the slice extent by the stride using float32:
// third_party/tflite/src/tensorflow/lite/kernels/strided_slice.cc
int32_t begin = ::tflite::strided_slice::StridedSliceStartForAxis(
op_params, effective_input_shape, idx);
int32_t end = ::tflite::strided_slice::StridedSliceEndForAxis(
op_params, effective_input_shape, idx, begin);
dim_shape = std::ceil((end - begin) / static_cast<float>(stride));
IEEE 754 single-precision floats have a 24-bit significand, so integers above 2^24 (16,777,216) cannot all be represented exactly. When end - begin equals 16,777,217 and stride equals 1, the cast static_cast<float>(stride) produces 1.0f, but the implicit promotion of dim_shape (16,777,217) to float rounds it down to 16,777,216.0f. The std::ceil call has no effect since the value is already integral after rounding. The output tensor is therefore allocated with 16,777,216 elements along that axis instead of 16,777,217.
The reference implementation of StridedSlice does not consult the output shape at all, as the code itself documents:
// third_party/tflite/src/tensorflow/lite/kernels/internal/reference/strided_slice.h
// Note that the output_shape is not used herein.
Instead, it recomputes begin and end from the original integer parameters and iterates over the true range. When the innermost stride is 1, it issues a single memcpy of stop - start elements per outer iteration through SequentialTensorWriter::WriteN:
// third_party/tflite/src/tensorflow/lite/kernels/internal/portable_tensor.h
void WriteN(int position, int len) {
memcpy(output_ptr_, &input_data_[position], sizeof(T) * len);
output_ptr_ += len;
}
This writes the correct number of elements into a buffer that is too small.
Chromium’s WebNN service translates MLGraphBuilder.slice() into TFLite’s STRIDED_SLICE. The WebNN validation layer in ValidateSliceAndInferOutput computes the output shape using exact integer ceiling division:
// services/webnn/public/cpp/graph_validation_utils.cc
uint32_t output_size = attributes.sizes[i] / attributes.strides[i] +
(attributes.sizes[i] % attributes.strides[i] != 0);
This produces the correct value of 16,777,217, so the operation passes validation. After TFLite builds the model, a post-build check in GraphImplTflite compares each output tensor’s byte count against the WebNN-expected size. However, this check only inspects the graph’s final output tensors, not intermediate tensors. By chaining two slice operations, where the first produces the oversized intermediate tensor and the second extracts a small sub-tensor as the graph output, the mismatch on the intermediate tensor goes undetected and the graph builds successfully. When the graph is dispatched, the first slice writes past the end of its allocated arena buffer, corrupting adjacent memory in the GPU process.
Reproduce
Tested at commit 7c89d33808e55 on Linux x86_64. No source modifications required.
Build configuration (out/asan-release/args.gn):
is_asan = true
is_debug = false
dcheck_always_on = false
target_cpu = "x64"
is_component_build = true
Build:
autoninja -C out/asan-release chrome
Serve the PoC and launch Chrome:
python3 -m http.server 8888 &
ASAN_OPTIONS=detect_odr_violation=0 out/asan-release/chrome \
--no-sandbox \
--enable-features=WebMachineLearningNeuralNetwork \
--user-data-dir=/tmp/poc-$(date +%s) \
http://localhost:8888/poc.html
The GPU process crashes within a few seconds of page load with a heap-buffer-overflow in __asan_memcpy, called from tflite::reference_ops::StridedSlice<unsigned char>.
=================================================================
==1307355==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7b76f54a68c0 at pc 0x55d111bdcbae bp 0x7b7709aabcf0 sp 0x7b7709aab4b0
WRITE of size 65 at 0x7b76f54a68c0 thread T42 (ThreadPoolForeg)
#0 0x55d111bdcbad in __asan_memcpy
#1 0x7f775650a73e in void tflite::reference_ops::StridedSlice<unsigned char>(...) third_party/tflite/src/tensorflow/lite/kernels/internal/portable_tensor.h:130:5
#2 0x7f7756504ed7 in tflite::ops::builtin::strided_slice::EvalImpl<...>(...) third_party/tflite/src/tensorflow/lite/kernels/internal/reference/strided_slice.h:140:3
#3 0x7f77565056f9 in tflite::ops::builtin::strided_slice::Eval<...>(...) third_party/tflite/src/tensorflow/lite/kernels/strided_slice.cc:370:10
#4 0x7f7755f62094 in tflite::Subgraph::InvokeImpl() third_party/tflite/src/tensorflow/lite/core/subgraph.cc
#5 0x7f7755f6112e in tflite::Subgraph::Invoke() third_party/tflite/src/tensorflow/lite/core/subgraph.cc:1653:17
#6 0x7f7755f3f6b4 in tflite::impl::Interpreter::Invoke() third_party/tflite/src/tensorflow/lite/core/interpreter.cc:247:48
#7 0x7f77554ea7bd in webnn::tflite::GraphImplTflite::ComputeResources::DoDispatch(...) services/webnn/tflite/graph_impl_tflite.cc:328:41
0x7b76f54a68c0 is located 0 bytes after 2181038272-byte region [0x7b76734a6800,0x7b76f54a68c0)
allocated by thread T42 (ThreadPoolForeg) here:
#0 0x55d111bdf772 in aligned_alloc
#1 0x7f7755f9e814 in tflite::SimpleMemoryArena::Commit(bool*) third_party/tflite/src/tensorflow/lite/simple_memory_arena.cc:111:31
#2 0x7f7755f14ec8 in tflite::ArenaPlanner::ExecuteAllocations(int, int) third_party/tflite/src/tensorflow/lite/arena_planner.cc:433:32
#3 0x7f7755f5d87c in tflite::Subgraph::PrepareOpsAndTensors() third_party/tflite/src/tensorflow/lite/core/subgraph.cc:1604:42
#4 0x7f7755f5beba in tflite::Subgraph::AllocateTensors(...) third_party/tflite/src/tensorflow/lite/core/subgraph.cc:1035:25
#5 0x7f77554d8722 in webnn::tflite::GraphImplTflite::ComputeResources::Create(...) services/webnn/tflite/graph_impl_tflite.cc:221:34
SUMMARY: AddressSanitizer: heap-buffer-overflow in __asan_memcpy
Full ASAN log is attached as asan.log.
Credit
Please use c6eed09fc8b174b0f3eebedcceb1e792 as the credit for this vulnerability. Thank you.