CVE-2022-35939 (C++, published 2022-09-16T20:15Z)
Description: value: TensorFlow is an open source platform for machine learning. The `ScatterNd` function takes an input argument that determines the indices of of the output tensor. An input index greater than the output tensor or less than zero will either write content at the wrong index or trigger a crash. We have patched the issue in GitHub commit b4d4b4cb019bd7240a52daa4ba61e3cc814f0384. The fix will be included in TensorFlow 2.10.0. We will also cherrypick this commit on TensorFlow 2.9.1, TensorFlow 2.8.1, and TensorFlow 2.7.2, as these are also affected and still in supported range. There are no known workarounds for this issue.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-787 \u2014 Out-of-bounds Write
The product writes data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/tensorflow/tensorflow
Files changed:
tensorflow/lite/kernels/internal/reference/reference_ops.h
tensorflow/lite/kernels/scatter_nd.cc
tensorflow/lite/kernels/scatter_nd_test.cc
Commit message: Check bounds for reads and writes in scatter_nd

PiperOrigin-RevId: 463365479


Vulnerable code:
inline void ScatterNd(const RuntimeShape& indices_shape,
                      const IndicesT* indices_data,
                      const RuntimeShape& updates_shape,
                      const UpdatesT* updates_data,
                      const RuntimeShape& output_shape, UpdatesT* output_data) {
      TFLITE_DCHECK(0 <= idx && idx < output_shape.Dims(j));
  reference_ops::ScatterNd(
  return kTfLiteOk;
      return ScatterNd<IndicesT, float>(indices, updates, output);
      return ScatterNd<IndicesT, uint8_t>(indices, updates, output);
      return ScatterNd<IndicesT, bool>(indices, updates, output);
      return ScatterNd<IndicesT, int8_t>(indices, updates, output);
      return ScatterNd<IndicesT, int32_t>(indices, updates, output);
      return ScatterNd<IndicesT, int64_t>(indices, updates, output);

Fixed code:
inline TfLiteStatus ScatterNd(const RuntimeShape& indices_shape,
                              const IndicesT* indices_data,
                              const RuntimeShape& updates_shape,
                              const UpdatesT* updates_data,
                              const RuntimeShape& output_shape,
                              UpdatesT* output_data) {
  if (n_slices * slice_size > updates_shape.FlatSize()) {
    return kTfLiteError;
  }
    if (to_pos < 0 || to_pos + slice_size > output_flat_size) {
      return kTfLiteError;
    }
  return kTfLiteOk;
  return reference_ops::ScatterNd(
  TfLiteStatus status = kTfLiteError;
      status = ScatterNd<IndicesT, float>(indices, updates, output);
      break;
      status = ScatterNd<IndicesT, uint8_t>(indices, updates, output);
      break;
      status = ScatterNd<IndicesT, bool>(indices, updates, output);
      break;
      status = ScatterNd<IndicesT, int8_t>(indices, updates, output);
      break;
      status = ScatterNd<IndicesT, int32_t>(indices, updates, output);
      break;
      status = ScatterNd<IndicesT, int64_t>(indices, updates, output);
      break;
  if (status != kTfLiteOk) {
    TF_LITE_KERNEL_LOG(context, "scatter_nd index out of bounds");
  }
  return status;
TEST(ScatterNdOpTest, ReadAndWriteArrayLimits) {
  ScatterNdOpModel m({TensorType_INT32, {5, 1}}, {TensorType_INT32, {5}},
                     {TensorType_INT32, {1}});
  m.SetIndices<int32_t>({4, 3, 1, 0, 2});
  m.SetUpdates<int32_t>({1, 2, 3, 7, 9});
  m.SetShape<int32_t>({5});
  ASSERT_EQ(m.Invoke(), kTfLiteOk);
  EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({5}));
  EXPECT_THAT(m.GetOutput<int32_t>(), ElementsAreArray({7, 3, 9, 2, 1}));
}

TEST(ScatterNdOpTest, OOBRead) {
  ScatterNdOpModel m({TensorType_INT32, {1, 1}}, {TensorType_INT32, {1}},
                     {TensorType_INT32, {1}});
  m.SetIndices<int32_t>({4});
  m.SetUpdates<int32_t>({1});
  m.SetShape<int32_t>({1});
  ASSERT_EQ(m.Invoke(), kTfLiteError);
}

TEST(ScatterNdOpTest, OOBWrites) {
  ScatterNdOpModel m({TensorType_INT32, {5, 1}}, {TensorType_INT32, {5}},
                     {TensorType_INT32, {1}});
  m.SetIndices<int32_t>({4, 3, 1, -0x38, 0x38});
  m.SetUpdates<int32_t>({1, 2, 3, 0x44444444, 0x55555555});
  m.SetShape<int32_t>({1});
  ASSERT_EQ(m.Invoke(), kTfLiteError);
}