Segmentation faultin TensorFlow when converting a Python string to tf.float16
Description
In TensorFlow before 1.15.2 and 2.0.1, converting a string (from Python) to a tf.float16 value results in a segmentation fault in eager mode as the format checks for this use case are only in the graph mode. This issue can lead to denial of service in inference/training where a malicious attacker can send a data point which contains a string instead of a tf.float16 value. Similar effects can be obtained by manipulating saved models and checkpoints whereby replacing a scalar tf.float16 value with a scalar string will trigger this issue due to automatic conversions. This can be easily reproduced by tf.constant("hello", tf.float16), if eager execution is enabled. This issue is patched in TensorFlow 1.15.1 and 2.0.1 with this vulnerability patched. TensorFlow 2.1.0 was released after we fixed the issue, thus it is not affected. Users are encouraged to switch to TensorFlow 1.15.1, 2.0.1 or 2.1.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
tensorflowPyPI | < 1.15.2 | 1.15.2 |
tensorflowPyPI | >= 2.0.0, < 2.0.1 | 2.0.1 |
tensorflow-cpuPyPI | < 1.15.2 | 1.15.2 |
tensorflow-cpuPyPI | >= 2.0.0, < 2.0.1 | 2.0.1 |
tensorflow-gpuPyPI | < 1.15.2 | 1.15.2 |
tensorflow-gpuPyPI | >= 2.0.0, < 2.0.1 | 2.0.1 |
Affected products
1- Range: < 1.15.2
Patches
35d80e1e8e6eeMerge pull request #36215 from tensorflow-jenkins/version-numbers-1.15.2-8214
3 files changed · +3 −3
tensorflow/core/public/version.h+1 −1 modified@@ -22,7 +22,7 @@ limitations under the License. // tensorflow/tools/pip_package/setup.py #define TF_MAJOR_VERSION 1 #define TF_MINOR_VERSION 15 -#define TF_PATCH_VERSION 1 +#define TF_PATCH_VERSION 2 // TF_VERSION_SUFFIX is non-empty for pre-releases (e.g. "-alpha", "-alpha.1", // "-beta", "-rc", "-rc.1")
tensorflow/tensorflow.bzl+1 −1 modified@@ -58,7 +58,7 @@ def register_extension_info(**kwargs): # not contain rc or alpha, only numbers. # Also update tensorflow/core/public/version.h # and tensorflow/tools/pip_package/setup.py -VERSION = "1.15.1" +VERSION = "1.15.2" VERSION_MAJOR = VERSION.split(".")[0] def if_v2(a):
tensorflow/tools/pip_package/setup.py+1 −1 modified@@ -47,7 +47,7 @@ # result for pip. # Also update tensorflow/tensorflow.bzl and # tensorflow/core/public/version.h -_VERSION = '1.15.1' +_VERSION = '1.15.2' REQUIRED_PACKAGES = [ 'absl-py >= 0.7.0',
765ac8d16effMerge pull request #35913 from tensorflow-jenkins/relnotes-2.0.1-6767
1 file changed · +8 −0
RELEASE.md+8 −0 modified@@ -1,3 +1,11 @@ +# Release 2.0.1 + +## Bug Fixes and Other Changes +* Fixes a security vulnerability where converting a Python string to a `tf.float16` value produces a segmentation fault ([CVE-2020-5215](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-5215)) +* Updates `curl` to `7.66.0` to handle [CVE-2019-5482](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5482) and [CVE-2019-5481](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5481) +* Updates `sqlite3` to `3.30.01` to handle [CVE-2019-19646](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-19646), [CVE-2019-19645](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-19645) and [CVE-2019-16168](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16168) + + # Release 2.0.0 ## Major Features and Improvements
5ac1b9e24ff6Fix segfault when attempting to convert string to float16.
3 files changed · +95 −12
tensorflow/python/BUILD+11 −0 modified@@ -1839,6 +1839,17 @@ py_library( ], ) +tf_py_test( + name = "framework_constant_op_test", + size = "small", + srcs = ["framework/constant_op_test.py"], + main = "framework/constant_op_test.py", + python_version = "PY3", + deps = [ + ":constant_op", + ], +) + tf_py_test( name = "framework_registry_test", size = "small",
tensorflow/python/framework/constant_op_test.py+61 −0 added@@ -0,0 +1,61 @@ +# Copyright 2020 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for tensorflow.python.framework.constant_op.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl.testing import parameterized + +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.platform import test + + +class ConstantOpTest(test.TestCase, parameterized.TestCase): + + @parameterized.parameters( + dtypes.bfloat16, + dtypes.complex128, + dtypes.complex64, + dtypes.double, + dtypes.float16, + dtypes.float32, + dtypes.float64, + dtypes.half, + dtypes.int16, + dtypes.int32, + dtypes.int64, + dtypes.int8, + dtypes.qint16, + dtypes.qint32, + dtypes.qint8, + dtypes.quint16, + dtypes.quint8, + dtypes.uint16, + dtypes.uint32, + dtypes.uint64, + dtypes.uint8, + ) + def test_convert_string_to_number(self, dtype): + with self.assertRaises(TypeError): + constant_op.constant("hello", dtype) + + +if __name__ == "__main__": + ops.enable_eager_execution() + test.main()
tensorflow/python/lib/core/py_seq_tensor.cc+23 −12 modified@@ -21,6 +21,7 @@ limitations under the License. #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/core/stringpiece.h" #include "tensorflow/core/lib/strings/str_util.h" +#include "tensorflow/core/platform/macros.h" #include "tensorflow/core/platform/types.h" #include "tensorflow/python/lib/core/numpy.h" #include "tensorflow/python/lib/core/py_util.h" @@ -396,6 +397,21 @@ typedef Converter<int32> Int32Converter; // Floating-point support +// Returns `true` if `out` overflows when converted from `as_double`. +template <class T> +static inline bool CheckForOverflow(double as_double, T* out) { + return (sizeof(T) < sizeof(double) && std::isinf(*out) && + std::isfinite(as_double)); +} + +// There is no `std::isinf` that takes `Eigen::half` as argument but Eigen +// provides `Eigen::half_impl::isinf` instead. +template <> +inline bool CheckForOverflow<Eigen::half>(double as_double, Eigen::half* out) { + return (sizeof(Eigen::half) < sizeof(double) && + Eigen::half_impl::isinf(*out) && std::isfinite(as_double)); +} + template <class T> static const char* ConvertOneFloat(PyObject* v, T* out) { if (PyErr_Occurred()) { @@ -405,20 +421,19 @@ static const char* ConvertOneFloat(PyObject* v, T* out) { const double as_double = PyFloat_AS_DOUBLE(v); *out = static_cast<T>(as_double); // Check for overflow - if (TF_PREDICT_FALSE(sizeof(T) < sizeof(double) && std::isinf(*out) && - std::isfinite(as_double))) { + if (TF_PREDICT_FALSE(CheckForOverflow<T>(as_double, out))) { return ErrorOutOfRangeDouble; } return nullptr; } #if PY_MAJOR_VERSION < 3 if (PyInt_Check(v)) { - *out = PyInt_AS_LONG(v); + *out = static_cast<T>(PyInt_AS_LONG(v)); return nullptr; } #endif if (PyLong_Check(v)) { - *out = PyLong_AsDouble(v); + *out = static_cast<T>(PyLong_AsDouble(v)); if (PyErr_Occurred()) return ErrorOutOfRangeDouble; return nullptr; } @@ -467,13 +482,7 @@ struct ConverterTraits<Eigen::half> { static const tensorflow::DataType kTypeEnum = DT_HALF; static const char* ConvertScalar(PyObject* v, Eigen::half* out) { - // NOTE(nareshmodi): Is there a way to convert to C double without the - // intermediate Python double? This will help with ConvertOneFloat as well. - Safe_PyObjectPtr as_float = make_safe(PyNumber_Float(v)); - double v_double = PyFloat_AS_DOUBLE(as_float.get()); - *out = Eigen::half(v_double); - - return nullptr; + return ConvertOneFloat<Eigen::half>(v, out); } }; @@ -613,7 +622,9 @@ Status PySeqToTensor(PyObject* obj, DataType dtype, Tensor* ret) { break; case DT_HALF: - RETURN_STRING_AS_STATUS(NumpyHalfConverter::Convert(obj, &state, ret)); + if (NumpyHalfConverter::Convert(obj, &state, ret) == nullptr) + return Status::OK(); + break; case DT_INT64: if (Int64Converter::Convert(obj, &state, ret) == nullptr)
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
9- github.com/advisories/GHSA-977j-xj7q-2jr9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-5215ghsaADVISORY
- github.com/pypa/advisory-database/tree/main/vulns/tensorflow-cpu/PYSEC-2020-303.yamlghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/tensorflow-gpu/PYSEC-2020-338.yamlghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/tensorflow/PYSEC-2020-258.yamlghsaWEB
- github.com/tensorflow/tensorflow/commit/5ac1b9e24ff6afc465756edf845d2e9660bd34bfghsax_refsource_MISCWEB
- github.com/tensorflow/tensorflow/releases/tag/v1.15.2ghsax_refsource_MISCWEB
- github.com/tensorflow/tensorflow/releases/tag/v2.0.1ghsax_refsource_MISCWEB
- github.com/tensorflow/tensorflow/security/advisories/GHSA-977j-xj7q-2jr9ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.