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_cpuPython package) - Version verified:
2.21.0(gitv2.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.hReverseSequence(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.tflitefrom the TFLite flatbuffer schema (no toolchain build needed)load.pyβ loads +Invoke()s the model viatf.lite.Interpreter(selectable resolver)crash.tfliteβ 444-byte PoC,seq_lengths={1, 2000000000}- sha256
f6ef6f4be6d405c456b2794a65daeffe122657a16fb59e912b1a6ba2aa074559
- sha256
neg.tfliteβ negative control,seq_lengths={1, 2}(both<=seq_dim size 3), runs cleanpoc_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
- -