Headline
CVE-2022-29201: Fix undefined behavior in QuantizedConv2D · tensorflow/tensorflow@0f0b080
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.raw_ops.QuantizedConv2D
does not fully validate the input arguments. In this case, references get bound to nullptr
for each argument that is empty. Versions 2.9.0, 2.8.1, 2.7.2, and 2.6.4 contain a patch for this issue.
@@ -91,10 +91,10 @@ TEST_F(QuantizedConv2DTest, Small) { image_quantized.flat<quint8>()); AddInputFromArray<quint8>(filter_quantized.shape(), filter_quantized.flat<quint8>()); AddInputFromArray<float>(TensorShape({1}), {image_min}); AddInputFromArray<float>(TensorShape({1}), {image_max}); AddInputFromArray<float>(TensorShape({1}), {filter_min}); AddInputFromArray<float>(TensorShape({1}), {filter_max}); AddInputFromArray<float>(TensorShape({}), {image_min}); AddInputFromArray<float>(TensorShape({}), {image_max}); AddInputFromArray<float>(TensorShape({}), {filter_min}); AddInputFromArray<float>(TensorShape({}), {filter_max}); TF_ASSERT_OK(RunOpKernel());
// We’re sliding the 3x3 filter across the 3x4 image, with accesses outside @@ -158,10 +158,10 @@ TEST_F(QuantizedConv2DTest, Small32Bit) { AddInputFromArray<quint8>( TensorShape({filter_size, filter_size, depth, filter_count}), {10, 40, 70, 20, 50, 80, 30, 60, 90}); AddInputFromArray<float>(TensorShape({1}), {0}); AddInputFromArray<float>(TensorShape({1}), {255.0f}); AddInputFromArray<float>(TensorShape({1}), {0}); AddInputFromArray<float>(TensorShape({1}), {255.0f}); AddInputFromArray<float>(TensorShape({}), {0}); AddInputFromArray<float>(TensorShape({}), {255.0f}); AddInputFromArray<float>(TensorShape({}), {0}); AddInputFromArray<float>(TensorShape({}), {255.0f});
TF_ASSERT_OK(RunOpKernel()); const int expected_width = image_width; @@ -201,10 +201,10 @@ TEST_F(QuantizedConv2DTest, OddPadding) { AddInputFromArray<quint8>( TensorShape({filter_size, filter_size, depth, filter_count}), {1, 2, 3, 4, 5, 6, 7, 8, 9}); AddInputFromArray<float>(TensorShape({1}), {0}); AddInputFromArray<float>(TensorShape({1}), {255.0f}); AddInputFromArray<float>(TensorShape({1}), {0}); AddInputFromArray<float>(TensorShape({1}), {255.0f}); AddInputFromArray<float>(TensorShape({}), {0}); AddInputFromArray<float>(TensorShape({}), {255.0f}); AddInputFromArray<float>(TensorShape({}), {0}); AddInputFromArray<float>(TensorShape({}), {255.0f});
TF_ASSERT_OK(RunOpKernel()); const int expected_width = image_width / stride; @@ -244,10 +244,10 @@ TEST_F(QuantizedConv2DTest, OddPaddingBatch) { AddInputFromArray<quint8>( TensorShape({filter_size, filter_size, depth, filter_count}), {1, 2, 3, 4, 5, 6, 7, 8, 9}); AddInputFromArray<float>(TensorShape({1}), {0}); AddInputFromArray<float>(TensorShape({1}), {255.0f}); AddInputFromArray<float>(TensorShape({1}), {0}); AddInputFromArray<float>(TensorShape({1}), {255.0f}); AddInputFromArray<float>(TensorShape({}), {0}); AddInputFromArray<float>(TensorShape({}), {255.0f}); AddInputFromArray<float>(TensorShape({}), {0}); AddInputFromArray<float>(TensorShape({}), {255.0f});
TF_ASSERT_OK(RunOpKernel()); const int expected_width = image_width / stride; @@ -302,10 +302,10 @@ TEST_F(QuantizedConv2DTest, SmallWithNoZero) { image_quantized.flat<quint8>()); AddInputFromArray<quint8>(filter_quantized.shape(), filter_quantized.flat<quint8>()); AddInputFromArray<float>(TensorShape({1}), {image_min}); AddInputFromArray<float>(TensorShape({1}), {image_max}); AddInputFromArray<float>(TensorShape({1}), {filter_min}); AddInputFromArray<float>(TensorShape({1}), {filter_max}); AddInputFromArray<float>(TensorShape({}), {image_min}); AddInputFromArray<float>(TensorShape({}), {image_max}); AddInputFromArray<float>(TensorShape({}), {filter_min}); AddInputFromArray<float>(TensorShape({}), {filter_max}); TF_ASSERT_OK(RunOpKernel()); const int expected_width = image_width; const int expected_height = image_height * filter_count;
Related news
### Impact The implementation of [`tf.raw_ops.QuantizedConv2D`](https://github.com/tensorflow/tensorflow/blob/f3b9bf4c3c0597563b289c0512e98d4ce81f886e/tensorflow/core/kernels/quantized_conv_ops.cc) does not fully validate the input arguments: ```python import tensorflow as tf input = tf.constant(1, shape=[1, 2, 3, 3], dtype=tf.quint8) filter = tf.constant(1, shape=[1, 2, 3, 3], dtype=tf.quint8) # bad args min_input = tf.constant([], shape=[0], dtype=tf.float32) max_input = tf.constant(0, shape=[], dtype=tf.float32) min_filter = tf.constant(0, shape=[], dtype=tf.float32) max_filter = tf.constant(0, shape=[], dtype=tf.float32) tf.raw_ops.QuantizedConv2D( input=input, filter=filter, min_input=min_input, max_input=max_input, min_filter=min_filter, max_filter=max_filter, strides=[1, 1, 1, 1], padding="SAME") ``` In this case, references get bound to `nullptr` for each argument that is empty (in the example, all arguments in the `bad args` section). ### Patches We have...
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, multiple TensorFlow operations misbehave in eager mode when the resource handle provided to them is invalid. In graph mode, it would have been impossible to perform these API calls, but migration to TF 2.x eager mode opened up this vulnerability. If the resource handle is empty, then a reference is bound to a null pointer inside TensorFlow codebase (various codepaths). This is undefined behavior. Versions 2.9.0, 2.8.1, 2.7.2, and 2.6.4 contain a patch for this issue.