CVE-2022-29211: Improper Input Validation (CWE-20)
value: TensorFlow is an open source platform for machine learning. Prior to versions 2.9.0, 2.8.1, 2.7.2, and 2.6.4, the implementation of `tf.histogram_fixed_width` is vulnerable to a crash when the values array contain `Not a Number` (`NaN`) elements. The implementation assumes that all floating point operations are defined and then converts a floating point result to an integer index. If `values` contains `NaN` then the result of the division is still `NaN` and the cast to `int32` would result in a crash. This only occurs on the CPU implementation. Versions 2.9.0, 2.8.1, 2.7.2, and 2.6.4 contain a patch for this issue.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 5.5
Published: 2022-05-21T00:15Z
Repository: https://github.com/tensorflow/tensorflow
Language: C++
Files changed: tensorflow/core/kernels/histogram_op.cc
Commit date: 2022-04-20 11:40:43 -0700
Commit message: Prevent crash when histogram is called with NaN values.

Fixes #45770

PiperOrigin-RevId: 443149951

Diff: diff --git a/tensorflow/core/kernels/histogram_op.cc b/tensorflow/core/kernels/histogram_op.cc
index 8e1b53de6ee40..8ba9bccc9fbec 100644
--- a/tensorflow/core/kernels/histogram_op.cc
+++ b/tensorflow/core/kernels/histogram_op.cc
@@ -48,10 +48,19 @@ struct HistogramFixedWidthFunctor<CPUDevice, T, Tout> {
 
     const double step = static_cast<double>(value_range(1) - value_range(0)) /
                         static_cast<double>(nbins);
     const double nbins_minus_1 = static_cast<double>(nbins - 1);
 
+    // We cannot handle NANs in the algorithm below (due to the case to int32)
+    const Eigen::Tensor<int32, 1, 1> nans_tensor =
+        values.isnan().template cast<int32>();
+    const Eigen::Tensor<int32, 0, 1> reduced_tensor = nans_tensor.sum();
+    const int num_nans = reduced_tensor(0);
+    if (num_nans > 0) {
+      return errors::InvalidArgument("Histogram values must not contain NaN");
+    }
+
     // The calculation is done by finding the slot of each value in `values`.
     // With [a, b]:
     //   step = (b - a) / nbins
     //   (x - a) / step
     // , then the entries are mapped to output.
@@ -96,16 +105,16 @@ class HistogramFixedWidthOp : public OpKernel {
     const auto values = values_tensor.flat<T>();
     const auto value_range = value_range_tensor.flat<T>();
     const auto nbins = nbins_tensor.scalar<int32>()();
 
     OP_REQUIRES(
-        ctx, (value_range(0) < value_range(1)),
+        ctx, value_range(0) < value_range(1),
         errors::InvalidArgument("value_range should satisfy value_range[0] < "
                                 "value_range[1], but got '[",
                                 value_range(0), ", ", value_range(1), "]'"));
     OP_REQUIRES(
-        ctx, (nbins > 0),
+        ctx, nbins > 0,
         errors::InvalidArgument("nbins should be a positive number, but got '",
                                 nbins, "'"));
 
     Tensor* out_tensor;
     OP_REQUIRES_OK(ctx,

Vulnerable code:         ctx, (value_range(0) < value_range(1)),
        ctx, (nbins > 0),
Fixed code:     // We cannot handle NANs in the algorithm below (due to the case to int32)
    const Eigen::Tensor<int32, 1, 1> nans_tensor =
        values.isnan().template cast<int32>();
    const Eigen::Tensor<int32, 0, 1> reduced_tensor = nans_tensor.sum();
    const int num_nans = reduced_tensor(0);
    if (num_nans > 0) {
      return errors::InvalidArgument("Histogram values must not contain NaN");
    }

        ctx, value_range(0) < value_range(1),
        ctx, nbins > 0,