Integer overflow in TFLite
Description
Tensorflow is an Open Source Machine Learning Framework. An attacker can craft a TFLite model that would cause an integer overflow in embedding lookup operations. Both embedding_size and lookup_size are products of values provided by the user. Hence, a malicious user could trigger overflows in the multiplication. In certain scenarios, this can then result in heap OOB read/write. Users are advised to upgrade to a patched version.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
tensorflowPyPI | < 2.5.3 | 2.5.3 |
tensorflowPyPI | >= 2.6.0, < 2.6.3 | 2.6.3 |
tensorflowPyPI | >= 2.7.0, < 2.7.1 | 2.7.1 |
tensorflow-cpuPyPI | < 2.5.3 | 2.5.3 |
tensorflow-cpuPyPI | >= 2.6.0, < 2.6.3 | 2.6.3 |
tensorflow-cpuPyPI | >= 2.7.0, < 2.7.1 | 2.7.1 |
tensorflow-gpuPyPI | < 2.5.3 | 2.5.3 |
tensorflow-gpuPyPI | >= 2.6.0, < 2.6.3 | 2.6.3 |
tensorflow-gpuPyPI | >= 2.7.0, < 2.7.1 | 2.7.1 |
Affected products
1- Range: >= 2.7.0, < 2.7.1
Patches
3a4e401da7145Prevent segfault in `embedding_lookup_sparse.cc`
1 file changed · +6 −0
tensorflow/lite/kernels/embedding_lookup_sparse.cc+6 −0 modified@@ -159,6 +159,7 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { TF_LITE_ENSURE_OK(context, GetInputSafe(context, node, 3, &weights)); const TfLiteTensor* value; TF_LITE_ENSURE_OK(context, GetInputSafe(context, node, 4, &value)); + const size_t values_size = NumElements(value); const int lookup_rank = SizeOfDimension(indices, 1); const int embedding_rank = NumDimensions(value); @@ -253,6 +254,11 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { current_squares_weight += w * w; current_total_weight += w; for (int k = 0; k < embedding_size; k++) { + // only index if indices are valid + if (current_output_offset + k < 0) continue; + if (current_output_offset + k >= output_size) continue; + if (example_embedding_offset + k < 0) continue; + if (example_embedding_offset + k >= values_size) continue; output_ptr[current_output_offset + k] += value_ptr[example_embedding_offset + k] * w; }
1de49725a5fc[lite] Check for overflow when creating required bytes.
1 file changed · +16 −7
tensorflow/lite/kernels/embedding_lookup_sparse.cc+16 −7 modified@@ -72,6 +72,7 @@ limitations under the License. #include "tensorflow/lite/kernels/internal/tensor_ctypes.h" #include "tensorflow/lite/kernels/internal/tensor_utils.h" #include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/util.h" namespace tflite { namespace ops { @@ -175,25 +176,33 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { TfLiteIntArray* output_shape = TfLiteIntArrayCreate(output_rank); TF_LITE_ENSURE(context, output_shape != nullptr); int k = 0; - int embedding_size = 1; - int lookup_size = 1; + size_t embedding_size = 1; + size_t lookup_size = 1; for (int i = 0; i < lookup_rank - 1; i++, k++) { - const int dim = dense_shape->data.i32[i]; - lookup_size *= dim; + const size_t dim = dense_shape->data.i32[i]; + TF_LITE_ENSURE_MSG( + context, + MultiplyAndCheckOverflow(lookup_size, dim, &lookup_size) == kTfLiteOk, + "Lookup size overflowed."); output_shape->data[k] = dim; } for (int i = 1; i < embedding_rank; i++, k++) { - const int dim = SizeOfDimension(value, i); - embedding_size *= dim; + const size_t dim = SizeOfDimension(value, i); + TF_LITE_ENSURE_MSG(context, + MultiplyAndCheckOverflow(embedding_size, dim, + &embedding_size) == kTfLiteOk, + "Embedding size overflowed."); output_shape->data[k] = dim; } TF_LITE_ENSURE_STATUS(context->ResizeTensor(context, output, output_shape)); - const int output_size = lookup_size * embedding_size; + const size_t output_size = lookup_size * embedding_size; TfLiteTensorRealloc(output_size * sizeof(float), output); float* output_ptr = GetTensorData<float>(output); const float* weights_ptr = GetTensorData<float>(weights); const float* value_ptr = GetTensorData<float>(value); + // Makes sure reallocation was successful. + TF_LITE_ENSURE(context, output_ptr != nullptr); std::fill_n(output_ptr, output_size, 0.0f);
f19be71717c4[lite] Move MultiplyAndCheckOverflow to util to be able to share it.
5 files changed · +32 −21
tensorflow/lite/BUILD+2 −0 modified@@ -1030,6 +1030,7 @@ cc_library( copts = tflite_copts_warnings() + tflite_copts(), deps = [ ":kernel_api", + ":macros", "//tensorflow/lite/c:common", "//tensorflow/lite/schema:schema_fbs", ], @@ -1083,6 +1084,7 @@ cc_test( features = ["-dynamic_link_test_srcs"], # see go/dynamic_link_test_srcs deps = [ ":util", + "//tensorflow/lite/c:c_api_types", "//tensorflow/lite/c:common", "//tensorflow/lite/schema:schema_fbs", "@com_google_googletest//:gtest_main",
tensorflow/lite/core/subgraph.cc+0 −21 modified@@ -690,27 +690,6 @@ TfLiteStatus Subgraph::CheckInputAndOutputForOverlap(const int* input_indices, return kTfLiteOk; } -namespace { -// Multiply two sizes and return true if overflow occurred; -// This is based off tensorflow/overflow.h but is simpler as we already -// have unsigned numbers. It is also generalized to work where sizeof(size_t) -// is not 8. -TfLiteStatus MultiplyAndCheckOverflow(size_t a, size_t b, size_t* product) { - // Multiplying a * b where a and b are size_t cannot result in overflow in a - // size_t accumulator if both numbers have no non-zero bits in their upper - // half. - constexpr size_t size_t_bits = 8 * sizeof(size_t); - constexpr size_t overflow_upper_half_bit_position = size_t_bits / 2; - *product = a * b; - // If neither integers have non-zero bits past 32 bits can't overflow. - // Otherwise check using slow devision. - if (TFLITE_EXPECT_FALSE((a | b) >> overflow_upper_half_bit_position != 0)) { - if (a != 0 && *product / a != b) return kTfLiteError; - } - return kTfLiteOk; -} -} // namespace - TfLiteStatus Subgraph::BytesRequired(TfLiteType type, const int* dims, size_t dims_size, size_t* bytes) { TF_LITE_ENSURE(&context_, bytes != nullptr);
tensorflow/lite/util.cc+16 −0 modified@@ -27,6 +27,7 @@ limitations under the License. #include "tensorflow/lite/builtin_ops.h" #include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/macros.h" #include "tensorflow/lite/schema/schema_generated.h" namespace tflite { @@ -176,4 +177,19 @@ bool IsValidationSubgraph(const char* name) { // NOLINTNEXTLINE: can't use absl::StartsWith as absl is not allowed. return name && std::string(name).find(kValidationSubgraphNamePrefix) == 0; } + +TfLiteStatus MultiplyAndCheckOverflow(size_t a, size_t b, size_t* product) { + // Multiplying a * b where a and b are size_t cannot result in overflow in a + // size_t accumulator if both numbers have no non-zero bits in their upper + // half. + constexpr size_t size_t_bits = 8 * sizeof(size_t); + constexpr size_t overflow_upper_half_bit_position = size_t_bits / 2; + *product = a * b; + // If neither integers have non-zero bits past 32 bits can't overflow. + // Otherwise check using slow devision. + if (TFLITE_EXPECT_FALSE((a | b) >> overflow_upper_half_bit_position != 0)) { + if (a != 0 && *product / a != b) return kTfLiteError; + } + return kTfLiteOk; +} } // namespace tflite
tensorflow/lite/util.h+6 −0 modified@@ -99,6 +99,12 @@ constexpr char kValidationSubgraphNamePrefix[] = "VALIDATION:"; // Checks whether the prefix of the subgraph name indicates the subgraph is a // validation subgraph. bool IsValidationSubgraph(const char* name); + +// Multiply two sizes and return true if overflow occurred; +// This is based off tensorflow/overflow.h but is simpler as we already +// have unsigned numbers. It is also generalized to work where sizeof(size_t) +// is not 8. +TfLiteStatus MultiplyAndCheckOverflow(size_t a, size_t b, size_t* product); } // namespace tflite #endif // TENSORFLOW_LITE_UTIL_H_
tensorflow/lite/util_test.cc+8 −0 modified@@ -22,6 +22,7 @@ limitations under the License. #include <vector> #include <gtest/gtest.h> +#include "tensorflow/lite/c/c_api_types.h" #include "tensorflow/lite/c/common.h" #include "tensorflow/lite/schema/schema_generated.h" @@ -130,5 +131,12 @@ TEST(ValidationSubgraph, NameIsDetected) { EXPECT_TRUE(IsValidationSubgraph("VALIDATION:main")); } +TEST(MultiplyAndCheckOverflow, Validate) { + size_t res = 0; + EXPECT_TRUE(MultiplyAndCheckOverflow(1, 2, &res) == kTfLiteOk); + EXPECT_FALSE(MultiplyAndCheckOverflow(static_cast<size_t>(123456789023), + 1223423425, &res) == kTfLiteOk); +} + } // namespace } // namespace tflite
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- github.com/advisories/GHSA-98p5-x8x4-c9m5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-23559ghsaADVISORY
- github.com/pypa/advisory-database/tree/main/vulns/tensorflow-cpu/PYSEC-2022-68.yamlghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/tensorflow-gpu/PYSEC-2022-123.yamlghsaWEB
- github.com/tensorflow/tensorflow/blob/ca6f96b62ad84207fbec580404eaa7dd7403a550/tensorflow/lite/kernels/embedding_lookup_sparse.ccghsax_refsource_MISCWEB
- github.com/tensorflow/tensorflow/commit/1de49725a5fc4e48f1a3b902ec3599ee99283043ghsax_refsource_MISCWEB
- github.com/tensorflow/tensorflow/commit/a4e401da71458d253b05e41f28637b65baf64be4ghsax_refsource_MISCWEB
- github.com/tensorflow/tensorflow/commit/f19be71717c497723ba0cea0379e84f061a75e01ghsax_refsource_MISCWEB
- github.com/tensorflow/tensorflow/security/advisories/GHSA-98p5-x8x4-c9m5ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.