CVE-2018-21233 (C++, published 2020-05-04T15:15Z)
Description: value: TensorFlow before 1.7.0 has an integer overflow that causes an out-of-bounds read, possibly causing disclosure of the contents of process memory. This occurs in the DecodeBmp feature of the BMP decoder in core/kernels/decode_bmp_op.cc.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-125 \u2014 Out-of-bounds Read
The product reads data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/tensorflow/tensorflow
Files changed:
tensorflow/core/kernels/decode_bmp_op.cc
tensorflow/core/kernels/fuzzing/BUILD
tensorflow/core/kernels/fuzzing/decode_bmp_fuzz.cc
Commit message: Fix integer overflow in BMP decoder by making the checks in DecodeBmp
more stringent.  Add fuzzer to improve the robustness of the decoder
in the future.

PiperOrigin-RevId: 185780111


Vulnerable code:
    const int last_pixel_offset =
        header_size + (abs(height) - 1) * row_size + (width - 1) * channels_;
    const int expected_file_size = last_pixel_offset + channels_;
                     0, TensorShape({abs(height), width, channels_}), &output));
           abs(height), channels_, top_down);

Fixed code:
    OP_REQUIRES(context, width > 0 && header_size >= 0,
                errors::InvalidArgument("Width must be positive"));
    OP_REQUIRES(context, header_size >= 0,
                errors::InvalidArgument("header size must be nonnegative"));

    // The real requirement is < 2^31 minus some headers and channel data,
    // so rounding down to something that's still ridiculously big.
    OP_REQUIRES(
        context,
        (static_cast<int64>(width) * std::abs(static_cast<int64>(height))) <
            static_cast<int64>(std::numeric_limits<int32_t>::max() / 8),
        errors::InvalidArgument(
            "Total possible pixel bytes must be less than 2^30"));

    const int32 abs_height = abs(height);

    const int64 last_pixel_offset = static_cast<int64>(header_size) +
                                    (abs_height - 1) * row_size +
                                    (width - 1) * channels_;
    const int64 expected_file_size = last_pixel_offset + channels_;
                     0, TensorShape({abs_height, width, channels_}), &output));
           abs_height, channels_, top_down);
tf_ops_fuzz_target_lib("decode_bmp")

/* Copyright 2018 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/kernels/fuzzing/fuzz_session.h"

namespace tensorflow {
namespace fuzzing {

class FuzzDecodeBmp : public FuzzStringInputOp {
  SINGLE_INPUT_OP_BUILDER(DT_STRING, DecodeBmp);
};

STANDARD_TF_FUZZ_FUNCTION(FuzzDecodeBmp);

}  // end namespace fuzzing
}  // end namespace tensorflow