You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

TFLite REVERSE_SEQUENCE out-of-bounds write via unchecked seq_lengths elements

Summary

The TensorFlow Lite REVERSE_SEQUENCE builtin operator performs an out-of-bounds heap write when fed an attacker-controlled seq_lengths tensor. The kernel's bounds-check loop iterates over NumDimensions(seq_lengths_tensor) β€” which Prepare forces to be 1 β€” instead of the element count, so only seq_lengths[0] is validated. Every remaining element flows unchecked into reference_ops::ReverseSequence, where it drives the destination offset of a memcpy. A crafted 444-byte .tflite triggers a SIGSEGV at the first Invoke().

  • Target: TensorFlow Lite (tensorflow / tensorflow_cpu Python package)
  • Version verified: 2.21.0 (git v2.21.0-rc1-5-ga481b10260d), x86-64 Linux, pip build
  • Component: tensorflow/lite/kernels/reverse_sequence.cc (bounds check) β†’ tensorflow/lite/kernels/internal/reference/reference_ops.h ReverseSequence (OOB write)
  • Op: REVERSE_SEQUENCE (builtin code 112)
  • Impact: Heap out-of-bounds write (memory corruption) from a malicious model β†’ crash / potential RCE
  • Attack surface: Model File Format β€” loading and invoking an untrusted .tflite

Root cause

tensorflow/lite/kernels/reverse_sequence.cc, in ReverseSequenceImpl (Eval path):

TF_LITE_ENSURE_EQ(context, SizeOfDimension(seq_lengths_tensor, 0),
                  SizeOfDimension(input, batch_dim));
for (int i = 0; i < NumDimensions(seq_lengths_tensor); ++i) {   // BUG: NumDimensions()==1
  TF_LITE_ENSURE(context, seq_lengths[i] <= SizeOfDimension(input, seq_dim));
}

Prepare requires NumDimensions(seq_lengths) == 1, so the loop runs exactly once and only seq_lengths[0] is checked. The correct bound is NumElements(seq_lengths_tensor) (a.k.a. SizeOfDimension(seq_lengths_tensor, 0)), which equals the batch dimension size.

The unvalidated values reach reference_ops::ReverseSequence:

int sl = seq_lengths[j] - 1;
...
const int out_pos = ((out_pos_base + p) * dims_at_medium_dim + sl - q) * copy_size;
output_ptr = output_data + out_pos;
memcpy(output_ptr, in_ptr, copy_size * sizeof(Scalar));   // OOB write when sl is huge

With seq_lengths = {1, 2000000000}, sl β‰ˆ 2e9, so output_data + ~2e9 floats (β‰ˆ 8 GB past the 6-element output buffer) is written β†’ SIGSEGV. There is also no lower-bound check, so negative values are equally accepted.

Reproduce

python mk.py 2000000000 crash.tflite   # unchecked seq_lengths[1] = 2e9
python mk.py 2          neg.tflite      # negative control (both lengths <= seq_dim size)
python load.py crash.tflite ref         # -> SIGSEGV (exit 139)
python load.py neg.tflite   ref         # -> clean, output (2,3)

See poc_crash_evidence.log for exit codes across repeated runs, both resolvers, and the gdb backtrace confirming the crash in reference_ops::ReverseSequence ← reverse_sequence::Eval.

Fix

Iterate over the number of seq_lengths elements and reject negative values:

for (int i = 0; i < SizeOfDimension(seq_lengths_tensor, 0); ++i) {
  TF_LITE_ENSURE(context, seq_lengths[i] >= 0);
  TF_LITE_ENSURE(context, seq_lengths[i] <= SizeOfDimension(input, seq_dim));
}

Artifacts

  • mk.py β€” builds the malicious .tflite from the TFLite flatbuffer schema (no toolchain build needed)
  • load.py β€” loads + Invoke()s the model via tf.lite.Interpreter (selectable resolver)
  • crash.tflite β€” 444-byte PoC, seq_lengths={1, 2000000000}
    • sha256 f6ef6f4be6d405c456b2794a65daeffe122657a16fb59e912b1a6ba2aa074559
  • neg.tflite β€” negative control, seq_lengths={1, 2} (both <= seq_dim size 3), runs clean
  • poc_crash_evidence.log β€” verbatim captured evidence (exit codes, both resolvers, gdb backtrace)

Dedup / prior art

No CVE or public advisory found for a REVERSE_SEQUENCE seq_lengths bounds bug. This is a distinct root cause from other TFLite builtin-op OOB issues (e.g. GATHER, SCATTER_ND, TILE, MIRROR_PAD, SPARSE_TO_DENSE index-bounds bugs): here the defect is a wrong loop bound (NumDimensions() instead of the element count) that leaves all but the first seq_lengths element unchecked, combined with a missing negative/lower-bound check. Verified present in the current released tensorflow 2.21.0 kernel source.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support