Skip to content

Commit c48c039

Browse files
David G. AndersenFrank Chen
David G. Andersen
authored and
Frank Chen
committed
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
1 parent d321e55 commit c48c039

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

tensorflow/core/kernels/decode_bmp_op.cc

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,32 @@ class DecodeBmpOp : public OpKernel {
9191
errors::InvalidArgument(
9292
"Number of channels must be 1, 3 or 4, was ", channels_));
9393

94+
OP_REQUIRES(context, width > 0 && header_size >= 0,
95+
errors::InvalidArgument("Width must be positive"));
96+
OP_REQUIRES(context, header_size >= 0,
97+
errors::InvalidArgument("header size must be nonnegative"));
98+
99+
// The real requirement is < 2^31 minus some headers and channel data,
100+
// so rounding down to something that's still ridiculously big.
101+
OP_REQUIRES(
102+
context,
103+
(static_cast<int64>(width) * std::abs(static_cast<int64>(height))) <
104+
static_cast<int64>(std::numeric_limits<int32_t>::max() / 8),
105+
errors::InvalidArgument(
106+
"Total possible pixel bytes must be less than 2^30"));
107+
108+
const int32 abs_height = abs(height);
109+
94110
// there may be padding bytes when the width is not a multiple of 4 bytes
95111
// 8 * channels == bits per pixel
96112
const int row_size = (8 * channels_ * width + 31) / 32 * 4;
97113

98-
const int last_pixel_offset =
99-
header_size + (abs(height) - 1) * row_size + (width - 1) * channels_;
114+
const int64 last_pixel_offset = static_cast<int64>(header_size) +
115+
(abs_height - 1) * row_size +
116+
(width - 1) * channels_;
100117

101118
// [expected file size] = [last pixel offset] + [last pixel size=channels]
102-
const int expected_file_size = last_pixel_offset + channels_;
119+
const int64 expected_file_size = last_pixel_offset + channels_;
103120

104121
OP_REQUIRES(
105122
context, (expected_file_size <= input.size()),
@@ -115,12 +132,12 @@ class DecodeBmpOp : public OpKernel {
115132
Tensor* output = nullptr;
116133
OP_REQUIRES_OK(
117134
context, context->allocate_output(
118-
0, TensorShape({abs(height), width, channels_}), &output));
135+
0, TensorShape({abs_height, width, channels_}), &output));
119136

120137
const uint8* bmp_pixels = &img_bytes[header_size];
121138

122139
Decode(bmp_pixels, row_size, output->flat<uint8>().data(), width,
123-
abs(height), channels_, top_down);
140+
abs_height, channels_, top_down);
124141
}
125142

126143
uint8* Decode(const uint8* input, const int row_size, uint8* const output,

tensorflow/core/kernels/fuzzing/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ tf_ops_fuzz_target_lib("decode_base64")
4343

4444
tf_ops_fuzz_target_lib("encode_jpeg")
4545

46+
tf_ops_fuzz_target_lib("decode_bmp")
47+
4648
tf_ops_fuzz_target_lib("decode_png")
4749

4850
tf_ops_fuzz_target_lib("decode_jpeg")
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright 2018 Google Inc. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
16+
#include "tensorflow/cc/ops/standard_ops.h"
17+
#include "tensorflow/core/kernels/fuzzing/fuzz_session.h"
18+
19+
namespace tensorflow {
20+
namespace fuzzing {
21+
22+
class FuzzDecodeBmp : public FuzzStringInputOp {
23+
SINGLE_INPUT_OP_BUILDER(DT_STRING, DecodeBmp);
24+
};
25+
26+
STANDARD_TF_FUZZ_FUNCTION(FuzzDecodeBmp);
27+
28+
} // end namespace fuzzing
29+
} // end namespace tensorflow

0 commit comments

Comments
 (0)