From f760f88b4267d981e13f4b302c437ae800445968 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Fri, 24 Apr 2020 10:49:08 -0700 Subject: [PATCH] Properly handle negative shape dimensions from improper saved models. PiperOrigin-RevId: 308283636 Change-Id: Ib10849425de7d541d8dacfe4d0c709fbac9180b6 --- tensorflow/cc/saved_model/loader.cc | 26 ++++++++++++++++++ .../cc/saved_model/saved_model_bundle_test.cc | 14 ++++++++++ .../testdata/negative_shape/fuzz_generated | Bin 0 -> 10820 bytes 3 files changed, 40 insertions(+) create mode 100644 tensorflow/cc/saved_model/testdata/negative_shape/fuzz_generated diff --git a/tensorflow/cc/saved_model/loader.cc b/tensorflow/cc/saved_model/loader.cc index 3bb4660e449..d193679ec19 100644 --- a/tensorflow/cc/saved_model/loader.cc +++ b/tensorflow/cc/saved_model/loader.cc @@ -19,12 +19,16 @@ limitations under the License. #include "tensorflow/cc/saved_model/constants.h" #include "tensorflow/cc/saved_model/reader.h" +#include "tensorflow/core/framework/attr_value.pb.h" +#include "tensorflow/core/framework/node_def.pb.h" +#include "tensorflow/core/framework/tensor.pb.h" #include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/lib/monitoring/counter.h" #include "tensorflow/core/lib/monitoring/sampler.h" #include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/errors.h" #include "tensorflow/core/platform/protobuf_internal.h" #include "tensorflow/core/protobuf/graph_debug_info.pb.h" #include "tensorflow/core/protobuf/saver.pb.h" @@ -65,12 +69,34 @@ uint64 GetLatencyMicroseconds(const uint64 start_microseconds) { return end_microseconds - start_microseconds; } +// Ensure that constant tensors loaded from the saved model have valid shape. +// TODO(b/154763635): this is temporary and will be replaced with a better audit +static Status ValidateSavedTensors(const GraphDef& graph_def) { + for (const auto& node : graph_def.node()) { + const auto node_iterator = node.attr().find("value"); + if (node_iterator != node.attr().end()) { + AttrValue node_value = node_iterator->second; + if (node_value.has_tensor()) { + const PartialTensorShape node_shape(node_value.tensor().tensor_shape()); + if (node_shape.num_elements() < 0) { + return errors::FailedPrecondition( + "Saved model contains node \"", node.name(), "\" (op \"", + node.op(), "\") which initializes from a tensor with ", + node_shape.num_elements(), " elements"); + } + } + } + } + return Status::OK(); +} + Status LoadMetaGraphIntoSession(const MetaGraphDef& meta_graph_def, const SessionOptions& session_options, std::unique_ptr* session) { Session* session_p = nullptr; TF_RETURN_IF_ERROR(NewSession(session_options, &session_p)); session->reset(session_p); + TF_RETURN_IF_ERROR(ValidateSavedTensors(meta_graph_def.graph_def())); return (*session)->Create(meta_graph_def.graph_def()); } diff --git a/tensorflow/cc/saved_model/saved_model_bundle_test.cc b/tensorflow/cc/saved_model/saved_model_bundle_test.cc index 9fc71552d6f..46f365613f1 100644 --- a/tensorflow/cc/saved_model/saved_model_bundle_test.cc +++ b/tensorflow/cc/saved_model/saved_model_bundle_test.cc @@ -40,6 +40,8 @@ constexpr char kTestDataInitOpV2[] = "cc/saved_model/testdata/half_plus_two_v2/00000123"; constexpr char kTestDataV2DebugInfo[] = "cc/saved_model/testdata/x_plus_y_v2_debuginfo"; +constexpr char kTestNegativeShapeFuzzGenerated[] = + "cc/saved_model/testdata/negative_shape/fuzz_generated"; class LoaderTest : public ::testing::Test { protected: @@ -256,5 +258,17 @@ TEST_F(LoaderTest, SavedModelV2DebugInfo) { EXPECT_NE(bundle.debug_info.get(), nullptr); } +TEST_F(LoaderTest, NegativeShapeDimension) { + SavedModelBundle bundle; + RunOptions run_options; + SessionOptions session_options; + + const string export_dir = io::JoinPath(testing::TensorFlowSrcRoot(), + kTestNegativeShapeFuzzGenerated); + Status st = LoadSavedModel(session_options, run_options, export_dir, + {kSavedModelTagServe}, &bundle); + EXPECT_FALSE(st.ok()); +} + } // namespace } // namespace tensorflow diff --git a/tensorflow/cc/saved_model/testdata/negative_shape/fuzz_generated b/tensorflow/cc/saved_model/testdata/negative_shape/fuzz_generated new file mode 100644 index 0000000000000000000000000000000000000000..5ee5c360ce03537c5cf8ec7d8513eec1ada74ae8 GIT binary patch literal 10820 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 aIQa&#Uui3fuCjDGPgllv%wUP^7yb`2@I3wi literal 0 HcmV?d00001