TFLite: Fix string input buffer sizing in SetStringData - #4141
Conversation
|
Hi maintainers, gentle ping on this pr when u have time! |
|
Confirming the mechanism in this PR, with a reproduction that needs no TF 1. Independent confirmation, quantified. Reading A standalone harness replicating that arithmetic (no TF/TFLite dependencies) and completes clean for the rank-1 consistent control ( ), so the overflow is specific to // Replicates the buffer arithmetic of TfLiteInterpreterWrapper::SetStringData
// (tensorflow_serving/servables/tensorflow/tflite_interpreter_pool.cc:61-119).
// batch_size comes from dim_size(0) per tflite_session.cc:635-636; the
// flattened string count comes from the request tensor's total elements.
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
int main(int argc, char** argv) {
const int batch_size = argc > 1 ? atoi(argv[1]) : 1;
const int total_strings = argc > 2 ? atoi(argv[2]) : 1000;
const size_t per_string = argc > 3 ? (size_t)atoi(argv[3]) : 1;
int32_t num_strings = batch_size;
std::vector<int32_t> offset_;
offset_.push_back(static_cast<int32_t>(0));
size_t total_size = 0;
for (int i = 0; i < total_strings; ++i) {
total_size += per_string;
offset_.push_back(static_cast<int32_t>(total_size));
}
size_t required_bytes = total_size + sizeof(int32_t) * (num_strings + 2);
char* buf = static_cast<char*>(malloc(required_bytes));
printf("batch_size=%d strings=%d each=%zu total_size=%zu required_bytes=%zu "
"table_write_end=%zu\n",
batch_size, total_strings, per_string, total_size, required_bytes,
sizeof(int32_t) * (offset_.size() + 1));
memcpy(buf, &num_strings, sizeof(int32_t));
int32_t start = sizeof(int32_t) * (num_strings + 2);
for (size_t i = 0; i < offset_.size(); i++) {
size_t size_offset_i = start + offset_[i];
if (size_offset_i > std::numeric_limits<int32_t>::max()) {
printf("guard fired at i=%zu\n", i);
break;
}
int32_t offset_i = static_cast<int32_t>(size_offset_i);
memcpy(buf + sizeof(int32_t) * (i + 1), &offset_i, sizeof(int32_t));
}
printf("offset-table loop completed\n");
free(buf);
return 0;
}(compile with 2. Reachability details.
(One smaller note while in this function: the offsets are accumulated as Happy to help extend the regression test with the |
Fix TFLite string input buffer sizing in TensorFlow Serving
Summary
TfLiteInterpreterWrapper::SetStringData()sizes the TFLite string tensor buffer header frombatch_size, but writes one offset entry for every flattened string element in the TensorFlow input tensor. For non-rank-1 string inputs, a request can make the flattened string count larger thanbatch_size, causing the offset table writes to exceed the allocated buffer.This change sizes the string buffer from the actual flattened string count, keeps offsets as
size_tuntil the final checked conversion to TFLite'sint32_toffset format, and adds overflow/allocation checks. A regression test covers a shape[1, 2]string tensor, where the first dimension is1but the flattened string count is2.Reachability
This is reachable through the supported TensorFlow Serving Predict path when TFLite serving is enabled:
tensorflow_model_server --prefer_tflite_model=truesetsSessionBundleConfig.prefer_tflite_model.SavedModelBundleFactoryloadsmodel.tfliteintoTfLiteSession.PredictionServiceImpl::Predict()and RESTHttpRestApiHandler::ProcessPredictRequest()route request tensors throughTensorflowPredictor::Predict().TfLiteSession::SetInputAndInvokeMiniBatch()handles string inputs by resizing the TFLite input to{batch_size}and then callingSetStringData()with the full TensorFlow string tensor.For a string tensor with shape
[1, 2],batch_sizeis1whiletensor.flat<tstring>().size()is2. No guard rejects that shape beforeSetStringData()writes the string offset table.Impact
The confirmed primitive is a heap buffer overflow in the TFLite string input marshalling path. A minimal ASan reproduction of the original arithmetic with
batch_size = 1and two flattened string elements reports:The direct overwrite is controlled by the number of flattened strings and their offsets. Practical impact depends on deployment using TFLite model serving and on allocator/layout conditions, so the conservative impact statement is remote process memory corruption in TFLite-enabled TensorFlow Serving.
Fix
std::vector<size_t>.total_size,num_strings, and the final byte sizes againststd::numeric_limits.int32_toffset type.[1, 2]) to ensure the buffer sizes itself against the flattened string count correctly.Verification
Performed:
SetStringData().Not performed: