Skip to content

Fix out-of-bounds memory access in CIRCULAR_BUFFER with zero slot count - #3694

Open
NEX-S wants to merge 1 commit into
tensorflow:mainfrom
NEX-S:fix-circular-buffer-zero-num-slots-oob
Open

NEX-S wants to merge 1 commit into
tensorflow:mainfrom
NEX-S:fix-circular-buffer-zero-num-slots-oob

Conversation

@NEX-S

@NEX-S NEX-S commented Sep 4, 2026

Copy link
Copy Markdown

BUG=#3695

What

CircularBufferEval computes the buffer shift size as (num_slots - 1) * depth, where num_slots = output->dims->data[1]. CircularBufferPrepare validated the other dimensions but never checked that the output slot count is at least 1.

Why

With num_slots == 0, (num_slots - 1) * depth evaluates to -depth as an int and wraps to a huge size_t when passed to memmove in EvalInt8:

memmove(output, &output[depth], (num_slots - 1) * depth);
memcpy(&output[(num_slots - 1) * depth], input, depth);

This performs a large out-of-bounds read from output + depth and a large out-of-bounds write starting at output. All tensor dimensions come from the model file, so a crafted .tflite model can trigger this (reproduced under ASan as negative-size-param, see #3695). On microcontroller targets, which typically run without mitigations, this is an out-of-bounds write primitive.

Fix

Reject slot counts < 1 in CircularBufferPrepare:

TF_LITE_ENSURE(context, output->dims->data[1] >= 1);

Testing

Added CircularBufferTest.ZeroNumSlotsRejectedInPrepare:

  • Fails without the fix (InitAndPrepare returns kTfLiteOk for a [1,0,1,1] output, where it must fail).
  • Passes with the fix (Prepare rejects the shape).

Existing tests (4) continue to pass.

@NEX-S
NEX-S requested a review from a team as a code owner September 4, 2026 09:56
@google-cla

google-cla Bot commented Sep 4, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@NEX-S
NEX-S force-pushed the fix-circular-buffer-zero-num-slots-oob branch from 8664810 to 726ce45 Compare September 4, 2026 09:59
CircularBufferEval computes the buffer shift size as
(num_slots - 1) * depth, where num_slots is output->dims->data[1].
CircularBufferPrepare did not validate this dimension; with num_slots == 0
the size becomes negative and wraps to a huge size_t when passed to memmove,
causing an out-of-bounds read/write on the output tensor. All dimensions come
from the model file, so a crafted model can trigger this.

Reject output slot counts < 1 in Prepare and add a regression test that fails
without the fix and passes with it.

BUG=tensorflow#3695
@NEX-S
NEX-S force-pushed the fix-circular-buffer-zero-num-slots-oob branch from d58760a to d06d60d Compare September 5, 2026 05:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant