Impact The SparseCountSparseOutput and RaggedCountSparseOutput implementations don't validate that the weights tensor has the same shape as the data. The check exists for DenseCountSparseOutput, where both tensors are fully specified: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/core/kernels/countops.cc#L110-L117
In the sparse and ragged count weights are still accessed in parallel with the data: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/core/kernels/countops.cc#L199-L201
But, since there is no validation, a user passing fewer weights than the values for the tensors can generate a read from outside the bounds of the heap buffer allocated for the weights.
Patches We have patched the issue in 3cbb917b4714766030b28eba9fb41bb97ce9ee02 and will release a patch release.
We recommend users to upgrade to TensorFlow 2.3.1.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability is a variant of GHSA-p5f8-gfw5-33w4
Impact The datasplits argument of tf.rawops.StringNGrams lacks validation. This allows a user to pass values that can cause heap overflow errors and even leak contents of memory python >> tf.rawops.StringNGrams(data=["aa", "bb", "cc", "dd", "ee", "ff"], datasplits=[0,8], separator=" ", ngramwidths=[3], leftpad="", rightpad="", padwidth=0, preserveshortsequences=False) StringNGrams(ngrams=<tf.Tensor: shape=(6,), dtype=string, numpy= array([b'aa bb cc', b'bb cc dd', b'cc dd ee', b'dd ee ff', b'ee ff \xf4j\xa7q\x7f\x00\x00q\x00\x00\x00\x00\x00\x00\x00\xd8\x9b~\xa8q\x7f\x00', b'ff \xf4j\xa7q\x7f\x00\x00q\x00\x00\x00\x00\x00\x00\x00\xd8\x9b~\xa8q\x7f\x00 \x9b~\xa8q\x7f\x00\x00p\xf5j\xa7q\x7f\x00\x00H\xf8j\xa7q\x7f\x00\x00\xf0\xf3\xf7\x85q\x7f\x00\x00}\xa6\x00\x00\x00\x00\x00~\xa6\x00\x00\x00\x00\x00\xb0~\xeb\x9bq\x7f\x00'],...
All the binary strings after ee ff are contents from the memory stack. Since these can contain return addresses, this data leak can be used to defeat ASLR.
Patches We have patched the issue in 0462de5b544ed4731aa2fb23946ac22c01856b80 and will release patch releases for all versions between 1.15 and 2.3.
We recommend users to upgrade to TensorFlow 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 2.3.1.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact When determining the common dimension size of two tensors, TFLite uses a DCHECK which is no-op outside of debug compilation modes: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/kernels/internal/types.h#L437-L442
Since the function always returns the dimension of the first tensor, malicious attackers can craft cases where this is larger than that of the second tensor. In turn, this would result in reads/writes outside of bounds since the interpreter will wrongly assume that there is enough data in both tensors.
Patches We have patched the issue in 8ee24e7949a20 and will release patch releases for all versions between 1.15 and 2.3.
We recommend users to upgrade to TensorFlow 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 2.3.1.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact Changing the TensorFlow's SavedModel protocol buffer and altering the name of required keys results in segfaults and data corruption while loading the model. This can cause a denial of service in products using tensorflow-serving or other inference-as-a-service installments.
We have added fixes to this in f760f88b4267d981e13f4b302c437ae800445968 and fcfef195637c6e365577829c4d67681695956e7d (both going into TensorFlow 2.2.0 and 2.3.0 but not yet backported to earlier versions). However, this was not enough, as #41097 reports a different failure mode.
Patches We have patched the issue in adf095206f25471e864a8e63a0f1caef53a0e3a6 and will release patch releases for all versions between 1.15 and 2.3. Patch releases for versions between 1.15 and 2.1 will also contain cherry-picks of f760f88b4267d981e13f4b302c437ae800445968 and fcfef195637c6e365577829c4d67681695956e7d.
We recommend users to upgrade to TensorFlow 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 2.3.1.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Shuaike Dong, from Alipay Tian Qian Security Lab && Lab for Applied Security Research, CUHK.
Impact The Shard API in TensorFlow expects the last argument to be a function taking two int64 (i.e., long long) arguments: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/core/util/worksharder.h#L59-L60
However, there are several places in TensorFlow where a lambda taking int or int32 arguments is being used: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/core/kernels/randomop.cc#L204-L205 https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/core/kernels/randomop.cc#L317-L318
In these cases, if the amount of work to be parallelized is large enough, integer truncation occurs. Depending on how the two arguments of the lambda are used, this can result in segfaults, read/write outside of heap allocated arrays, stack overflows, or data corruption.
Patches We have patched the issue in 27b417360cbd671ef55915e4bb6bb06af8b8a832 and ca8c013b5e97b1373b3bb1c97ea655e69f31a575. We will release patch releases for all versions between 1.15 and 2.3.
We recommend users to upgrade to TensorFlow 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 2.3.1.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact To mimic Python's indexing with negative values, TFLite uses ResolveAxis to convert negative values to positive indices. However, the only check that the converted index is now valid is only present in debug builds: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/kernels/internal/reference/reduce.h#L68-L72
If the DCHECK does not trigger, then code execution moves ahead with a negative index. This, in turn, results in accessing data out of bounds which results in segfaults and/or data corruption. Patches We have patched the issue in 2d88f470dea2671b430884260f3626b1fe99830a and will release patch releases for all versions between 1.15 and 2.3.
We recommend users to upgrade to TensorFlow 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 2.3.1.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact The implementation of SparseFillEmptyRowsGrad uses a double indexing pattern: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/core/kernels/sparsefillemptyrowsop.cc#L263-L269
It is possible for reverseindexmap(i) to be an index outside of bounds of gradvalues, thus resulting in a heap buffer overflow.
Patches We have patched the issue in 390611e0d45c5793c7066110af37c8514e6a6c54 and will release a patch release for all affected versions.
We recommend users to upgrade to TensorFlow 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 2.3.1.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact In TensorFlow Lite models using segment sum can trigger writes outside of bounds of heap allocated buffers by inserting negative elements in the segment ids tensor: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/kernels/internal/reference/referenceops.h#L2625-L2631
Users having access to segmentidsdata can alter outputindex and then write to outside of outputdata buffer.
This might result in a segmentation fault but it can also be used to further corrupt the memory and can be chained with other vulnerabilities to create more advanced exploits.
Patches We have patched the issue in 204945b and will release patch releases for all affected versions.
We recommend users to upgrade to TensorFlow 2.2.1, or 2.3.1.
Workarounds A potential workaround would be to add a custom Verifier to the model loading code to ensure that the segment ids are all positive, although this only handles the case when the segment ids are stored statically in the model.
A similar validation could be done if the segment ids are generated at runtime between inference steps.
If the segment ids are generated as outputs of a tensor during inference steps, then there are no possible workaround and users are advised to upgrade to patched code.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been discovered from a variant analysis of GHSA-p2cq-cprg-frvm.
Impact In TensorFlow Lite models using segment sum can trigger a write out bounds / segmentation fault if the segment ids are not sorted. Code assumes that the segment ids are in increasing order, using the last element of the tensor holding them to determine the dimensionality of output tensor: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/kernels/segmentsum.cc#L39-L44
This results in allocating insufficient memory for the output tensor and in a write outside the bounds of the output array: https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/kernels/internal/reference/referenceops.h#L2625-L2631
This usually results in a segmentation fault, but depending on runtime conditions it can provide for a write gadget to be used in future memory corruption-based exploits.
Patches We have patched the issue in 204945b and will release patch releases for all affected versions.
We recommend users to upgrade to TensorFlow 2.2.1, or 2.3.1.
Workarounds A potential workaround would be to add a custom Verifier to the model loading code to ensure that the segment ids are sorted, although this only handles the case when the segment ids are stored statically in the model.
A similar validation could be done if the segment ids are generated at runtime between inference steps.
If the segment ids are generated as outputs of a tensor during inference steps, then there are no possible workaround and users are advised to upgrade to patched code.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact The tf.rawops.DataFormatVecPermute API does not validate the srcformat and dstformat attributes. The code assumes that these two arguments define a permutation of NHWC.
However, these assumptions are not checked and this can result in uninitialized memory accesses, read outside of bounds and even crashes.
python >> import tensorflow as tf >> tf.rawops.DataFormatVecPermute(x=[1,4], srcformat='1234', dstformat='1234') <tf.Tensor: shape=(2,), dtype=int32, numpy=array([4, 757100143], dtype=int32)> ... >> tf.rawops.DataFormatVecPermute(x=[1,4], srcformat='HHHH', dstformat='WWWW') <tf.Tensor: shape=(2,), dtype=int32, numpy=array([4, 32701], dtype=int32)> ... >> tf.rawops.DataFormatVecPermute(x=[1,4], srcformat='H', dstformat='W') <tf.Tensor: shape=(2,), dtype=int32, numpy=array([4, 32701], dtype=int32)> >> tf.rawops.DataFormatVecPermute(x=[1,2,3,4], srcformat='1234', dstformat='1253') <tf.Tensor: shape=(4,), dtype=int32, numpy=array([4, 2, 939037184, 3], dtype=int32)> ... >> tf.rawops.DataFormatVecPermute(x=[1,2,3,4], srcformat='1234', dstformat='1223') <tf.Tensor: shape=(4,), dtype=int32, numpy=array([4, 32701, 2, 3], dtype=int32)> ... >> tf.rawops.DataFormatVecPermute(x=[1,2,3,4], srcformat='1224', dstformat='1423') <tf.Tensor: shape=(4,), dtype=int32, numpy=array([1, 4, 3, 32701], dtype=int32)> ... >> tf.rawops.DataFormatVecPermute(x=[1,2,3,4], srcformat='1234', dstformat='432') <tf.Tensor: shape=(4,), dtype=int32, numpy=array([4, 3, 2, 32701], dtype=int32)> ... >> tf.rawops.DataFormatVecPermute(x=[1,2,3,4], srcformat='12345678', dstformat='87654321') munmapchunk(): invalid pointer Aborted ... >> tf.rawops.DataFormatVecPermute(x=[[1,5],[2,6],[3,7],[4,8]], srcformat='12345678', dstformat='87654321') <tf.Tensor: shape=(4, 2), dtype=int32, numpy= array([[71364624, 0], [71365824, 0], [ 560, 0], [ 48, 0]], dtype=int32)> ... >> tf.rawops.DataFormatVecPermute(x=[[1,5],[2,6],[3,7],[4,8]], srcformat='12345678', dstformat='87654321') free(): invalid next size (fast) Aborted
A similar issue occurs in tf.rawops.DataFormatDimMap, for the same reasons:
python >> tf.rawops.DataFormatDimMap(x=[[1,5],[2,6],[3,7],[4,8]], srcformat='1234', >> dstformat='8765') <tf.Tensor: shape=(4, 2), dtype=int32, numpy= array([[1954047348, 1954047348], [1852793646, 1852793646], [1954047348, 1954047348], [1852793632, 1852793632]], dtype=int32)>
Patches We have patched the issue in GitHub commit ebc70b7a592420d3d2f359e4b1694c236b82c7ae and will release TensorFlow 2.4.0 containing the patch. TensorFlow nightly packages after this commit will also have the issue resolved.
Since this issue also impacts TF versions before 2.4, we will patch all releases between 1.15 and 2.3 inclusive.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact The implementation of MatrixDiag operations does not validate that the tensor arguments are non-empty:
cc numrows = context->input(2).flat<int32>()(0); numcols = context->input(3).flat<int32>()(0); paddingvalue = context->input(4).flat<T>()(0);
Thus, users can trigger null pointer dereferences if any of the above tensors are null:
python import tensorflow as tf
d = tf.converttotensor([],dtype=tf.float32) p = tf.converttotensor([],dtype=tf.float32) tf.rawops.MatrixDiagV2(diagonal=d, k=0, numrows=0, numcols=0, paddingvalue=p)
Changing from tf.rawops.MatrixDiagV2 to tf.rawops.MatrixDiagV3 still reproduces the issue.
Patches We have patched the issue in GitHub commit a7116dd3913c4a4afd2a3a938573aa7c785fdfc6.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Ye Zhang and Yakun Zhang of Baidu X-Team.
Impact The reference implementation of the GatherNd TFLite operator is vulnerable to a division by zero error:
cc ret.dimstocount[i] = remainflatsize / paramsshape.Dims(i);
An attacker can craft a model such that params input would be an empty tensor. In turn, paramsshape.Dims(.) would be zero, in at least one dimension.
Patches We have patched the issue in GitHub commit 8e45822aa0b9f5df4b4c64f221e64dc930a70a9d.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact The implementation of the BatchToSpaceNd TFLite operator is vulnerable to a division by zero error:
cc TFLITEENSUREEQ(context, outputbatchsize % blockshape[dim], 0); outputbatchsize = outputbatchsize / blockshape[dim];
An attacker can craft a model such that one dimension of the block input is 0. Hence, the corresponding value in blockshape is 0.
Patches We have patched the issue in GitHub commit 2c74674348a4708ced58ad6eb1b23354df8ee044.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact The TFLite computation for size of output after padding, ComputeOutSize, does not check that the stride argument is not 0 before doing the division.
cc inline int ComputeOutSize(TfLitePadding padding, int imagesize, int filtersize, int stride, int dilationrate = 1) { int effectivefiltersize = (filtersize - 1) dilationrate + 1; switch (padding) { case kTfLitePaddingSame: return (imagesize + stride - 1) / stride; case kTfLitePaddingValid: return (imagesize + stride - effectivefiltersize) / stride; default: return 0; } } Users can craft special models such that ComputeOutSize is called with stride set to 0.
Patches We have patched the issue in GitHub commit 49847ae69a4e1a97ae7f2db5e217c77721e37948.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact Calling TF operations with tensors of non-numeric types when the operations expect numeric tensors result in null pointer dereferences.
There are multiple ways to reproduce this, listing a few examples here:
python import tensorflow as tf import numpy as np data = tf.random.truncatednormal(shape=1,mean=np.float32(20.8739),stddev=779.973,dtype=20,seed=64)
python import tensorflow as tf import numpy as np data = tf.random.statelesstruncatednormal(shape=1,seed=[63,70],mean=np.float32(20.8739),stddev=779.973,dtype=20)
python import tensorflow as tf import numpy as np data = tf.onehot(indices=[62,50],depth=136,onvalue=np.int32(237),offvalue=158,axis=856,dtype=20)
python import tensorflow as tf import numpy as np data = tf.range(start=np.int32(214),limit=660,delta=129,dtype=20)
python import tensorflow as tf import numpy as np data = tf.rawops.ResourceCountUpTo(resource=np.int32(30), limit=872, T=3)
python import tensorflow as tf import numpy as np
writerarray = np.array([1,2],dtype=np.int32) writertensor = tf.converttotensor(writerarray,dtype=tf.resource)
All these examples and similar ones have the same behavior: the conversion from Python array to C++ array is vulnerable to a type confusion:
cc int pyarraytype = PyArrayTYPE(array); PyArrayDescr descr = PyArrayDESCR(array); switch (pyarraytype) { ... case NPYVOID: // Quantized types are currently represented as custom struct types. // PyArrayTYPE returns NPYVOID for structs, and we should look into // descr to derive the actual type. // Direct feeds of certain types of ResourceHandles are represented as a // custom struct type. return PyArrayDescrtoTFDataType(descr, outtfdatatype); ... }
For the tensor types involved in the above example, the pyarraytype is NPYVOID but the descr field is such that descr->field = NULL. Then PyArrayDescrtoTFDataType will trigger a null dereference:
cc Status PyArrayDescrtoTFDataType(PyArrayDescr descr, TFDataType outtfdatatype) { PyObject key; PyObject value; Pyssizet pos = 0; if (PyDictNext(descr->fields, &pos, &key, &value)) { ... } }
This is because the Python's PyDictNext implementation would dereference the first argument.
Patches We have patched the issue in GitHub commit 030af767d357d1b4088c4a25c72cb3906abac489.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360 as well as Ye Zhang and Yakun Zhang of Baidu X-Team.
Impact The implementation of tf.rawops.FusedBatchNorm is vulnerable to a heap buffer overflow: python import tensorflow as tf
x = tf.zeros([10, 10, 10, 6], dtype=tf.float32) scale = tf.constant([0.0], shape=[1], dtype=tf.float32) offset = tf.constant([0.0], shape=[1], dtype=tf.float32) mean = tf.constant([0.0], shape=[1], dtype=tf.float32) variance = tf.constant([0.0], shape=[1], dtype=tf.float32) epsilon = 0.0 exponentialavgfactor = 0.0 dataformat = "NHWC" istraining = False tf.rawops.FusedBatchNorm( x=x, scale=scale, offset=offset, mean=mean, variance=variance, epsilon=epsilon, exponentialavgfactor=exponentialavgfactor, dataformat=dataformat, istraining=istraining) If the tensors are empty, the same implementation can trigger undefined behavior by dereferencing null pointers:
python import tensorflow as tf import numpy as np
x = tf.zeros([10, 10, 10, 1], dtype=tf.float32) scale = tf.constant([], shape=[0], dtype=tf.float32) offset = tf.constant([], shape=[0], dtype=tf.float32) mean = tf.constant([], shape=[0], dtype=tf.float32) variance = tf.constant([], shape=[0], dtype=tf.float32) epsilon = 0.0 exponentialavgfactor = 0.0 dataformat = "NHWC" istraining = False
tf.rawops.FusedBatchNorm( x=x, scale=scale, offset=offset, mean=mean, variance=variance, epsilon=epsilon, exponentialavgfactor=exponentialavgfactor, dataformat=dataformat, istraining=istraining)
The implementation fails to validate that scale, offset, mean and variance (the last two only when required) all have the same number of elements as the number of channels of x. This results in heap out of bounds reads when the buffers backing these tensors are indexed past their boundary.
If the tensors are empty, the validation mentioned in the above paragraph would also trigger and prevent the undefined behavior.
Patches We have patched the issue in GitHub commit 6972f9dfe325636b3db4e0bc517ee22a159365c0.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Ying Wang and Yakun Zhang of Baidu X-Team.
Impact An attacker can cause a heap buffer overflow in QuantizedMul by passing in invalid thresholds for the quantization:
python import tensorflow as tf
x = tf.constant([256, 328], shape=[1, 2], dtype=tf.quint8) y = tf.constant([256, 328], shape=[1, 2], dtype=tf.quint8) minx = tf.constant([], dtype=tf.float32) maxx = tf.constant([], dtype=tf.float32) miny = tf.constant([], dtype=tf.float32) maxy = tf.constant([], dtype=tf.float32)
tf.rawops.QuantizedMul(x=x, y=y, minx=minx, maxx=maxx, miny=miny, maxy=maxy)
This is because the implementation assumes that the 4 arguments are always valid scalars and tries to access the numeric value directly:
cc const float minx = context->input(2).flat<float>()(0); const float maxx = context->input(3).flat<float>()(0); const float miny = context->input(4).flat<float>()(0); const float maxy = context->input(5).flat<float>()(0);
However, if any of these tensors is empty, then .flat<T>() is an empty buffer and accessing the element at position 0 results in overflow.
Patches We have patched the issue in GitHub commit efea03b38fb8d3b81762237dc85e579cc5fc6e87.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Ying Wang and Yakun Zhang of Baidu X-Team.
Impact The fix for CVE-2020-15209 missed the case when the target shape of Reshape operator is given by the elements of a 1-D tensor. As such, the fix for the vulnerability allowed passing a null-buffer-backed tensor with a 1D shape:
cc if (tensor->data.raw == nullptr && tensor->bytes > 0) { if (registration.builtincode == kTfLiteBuiltinReshape && i == 1) { // In general, having a tensor here with no buffer will be an error. // However, for the reshape operator, the second input tensor is only // used for the shape, not for the data. Thus, null buffer is ok. continue; } else { // In all other cases, we need to return an error as otherwise we will // trigger a null pointer dereference (likely). ReportError("Input tensor %d lacks data", tensorindex); return kTfLiteError; } }
Patches We have patched the issue in GitHub commit f8378920345f4f4604202d4ab15ef64b2aceaa16.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact An attacker can trigger an integer division by zero undefined behavior in tf.rawops.QuantizedBiasAdd:
python import tensorflow as tf
inputtensor = tf.constant([], shape=[0, 0, 0, 0], dtype=tf.quint8) bias = tf.constant([], shape=[0], dtype=tf.quint8) mininput = tf.constant(-10.0, dtype=tf.float32) maxinput = tf.constant(-10.0, dtype=tf.float32) minbias = tf.constant(-10.0, dtype=tf.float32) maxbias = tf.constant(-10.0, dtype=tf.float32)
tf.rawops.QuantizedBiasAdd(input=inputtensor, bias=bias, mininput=mininput, maxinput=maxinput, minbias=minbias, maxbias=maxbias, outtype=tf.qint32)
This is because the implementation of the Eigen kernel does a division by the number of elements of the smaller input (based on shape) without checking that this is not zero:
cc template <typename T1, typename T2, typename T3> void QuantizedAddUsingEigen(const Eigen::ThreadPoolDevice& device, const Tensor& input, float inputmin, float inputmax, const Tensor& smallerinput, float smallerinputmin, float smallerinputmax, Tensor output, float outputmin, float outputmax) { ... const int64 inputelementcount = input.NumElements(); const int64 smallerinputelementcount = smallerinput.NumElements(); ... bcast[0] = inputelementcount / smallerinputelementcount; ... }
This integral division by 0 is undefined behavior.
Patches We have patched the issue in GitHub commit 67784700869470d65d5f2ef20aeb5e97c31673cb.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Yakun Zhang and Ying Wang of Baidu X-Team.
Impact If the splits argument of RaggedBincount does not specify a valid SparseTensor, then an attacker can trigger a heap buffer overflow:
python import tensorflow as tf tf.rawops.RaggedBincount(splits=[7,8], values= [5, 16, 51, 76, 29, 27, 54, 95],\ size= 59, weights= [0, 0, 0, 0, 0, 0, 0, 0],\ binaryoutput=False)
This will cause a read from outside the bounds of the splits tensor buffer in the implementation of the RaggedBincount op: cc for (int idx = 0; idx < numvalues; ++idx) { while (idx >= splits(batchidx)) { batchidx++; } ... if (bin < size) { if (binaryoutput) { out(batchidx - 1, bin) = T(1); } else { T value = (weightssize > 0) ? weights(idx) : T(1); out(batchidx - 1, bin) += value; } } }
Before the for loop, batchidx is set to 0. The attacker sets splits(0) to be 7, hence the while loop does not execute and batchidx remains 0. This then results in writing to out(-1, bin), which is before the heap allocated buffer for the output tensor.
Patches We have patched the issue in GitHub commit eebb96c2830d48597d055d247c0e9aebaea94cd5.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2 and TensorFlow 2.3.3, as these are also affected.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact An attacker can cause a heap buffer overflow in QuantizedResizeBilinear by passing in invalid thresholds for the quantization:
python import tensorflow as tf
images = tf.constant([], shape=[0], dtype=tf.qint32) size = tf.constant([], shape=[0], dtype=tf.int32) min = tf.constant([], dtype=tf.float32) max = tf.constant([], dtype=tf.float32)
tf.rawops.QuantizedResizeBilinear(images=images, size=size, min=min, max=max, aligncorners=False, halfpixelcenters=False)
This is because the implementation assumes that the 2 arguments are always valid scalars and tries to access the numeric value directly:
cc const float inmin = context->input(2).flat<float>()(0); const float inmax = context->input(3).flat<float>()(0);
However, if any of these tensors is empty, then .flat<T>() is an empty buffer and accessing the element at position 0 results in overflow.
Patches We have patched the issue in GitHub commit f6c40f0c6cbf00d46c7717a26419f2062f2f8694.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Ying Wang and Yakun Zhang of Baidu X-Team.
Impact The optimized implementation of the TransposeConv TFLite operator is vulnerable to a division by zero error:
cc int heightcol = (height + padt + padb - filterh) / strideh + 1; int widthcol = (width + padl + padr - filterw) / stridew + 1;
An attacker can craft a model such that stride{h,w} values are 0. Code calling this function must validate these arguments.
Patches We have patched the issue in GitHub commit 801c1c6be5324219689c98e1bd3e0ca365ee834d.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact TFlite graphs must not have loops between nodes. However, this condition was not checked and an attacker could craft models that would result in infinite loop during evaluation. In certain cases, the infinite loop would be replaced by stack overflow due to too many recursive calls.
For example, the While implementation could be tricked into a scneario where both the body and the loop subgraphs are the same. Evaluating one of the subgraphs means calling the Eval function for the other and this quickly exhaust all stack space. Patches We have patched the issue in GitHub commit 9c1dc920d8ffb4893d6c9d27d1f039607b326743 (for the While operator) and in GitHub commit c6173f5fe66cdbab74f4f869311fe6aae2ba35f4 (in general). The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact An attacker can trigger a division by 0 in tf.rawops.Conv2DBackpropInput:
python import tensorflow as tf
inputtensor = tf.constant([52, 1, 1, 5], shape=[4], dtype=tf.int32) filtertensor = tf.constant([], shape=[0, 1, 5, 0], dtype=tf.float32) outbackprop = tf.constant([], shape=[52, 1, 1, 0], dtype=tf.float32)
tf.rawops.Conv2DBackpropInput(inputsizes=inputtensor, filter=filtertensor, outbackprop=outbackprop, strides=[1, 1, 1, 1], usecudnnongpu=True, padding='SAME', explicitpaddings=[], dataformat='NHWC', dilations=[1, 1, 1, 1]) This is because the implementation does a division by a quantity that is controlled by the caller:
cc const sizet sizeA = outputimagesize dims.outdepth; const sizet sizeB = filtertotalsize dims.outdepth; const sizet sizeC = outputimagesize filtertotalsize; const sizet workunitsize = sizeA + sizeB + sizeC; ... const sizet shardsize = useparallelcontraction ? 1 : (targetworkingsetsize + workunitsize - 1) / workunitsize;
Patches We have patched the issue in GitHub commit 2be2cdf3a123e231b16f766aa0e27d56b4606535.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Yakun Zhang and Ying Wang of Baidu X-Team.
Impact The Prepare step of the SpaceToDepth TFLite operator does not check for 0 before division.
cc const int blocksize = params->blocksize; const int inputheight = input->dims->data[1]; const int inputwidth = input->dims->data[2]; int outputheight = inputheight / blocksize; int outputwidth = inputwidth / blocksize;
An attacker can craft a model such that params->blocksize would be zero.
Patches We have patched the issue in GitHub commit 0d45ea1ca641b21b73bcf9c00e0179cda284e7e7.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact An attacker can cause a heap buffer overflow to occur in Conv2DBackpropFilter:
python import tensorflow as tf
inputtensor = tf.constant([386.078431372549, 386.07843139643234], shape=[1, 1, 1, 2], dtype=tf.float32) filtersizes = tf.constant([1, 1, 1, 1], shape=[4], dtype=tf.int32) outbackprop = tf.constant([386.078431372549], shape=[1, 1, 1, 1], dtype=tf.float32) tf.rawops.Conv2DBackpropFilter( input=inputtensor, filtersizes=filtersizes, outbackprop=outbackprop, strides=[1, 66, 49, 1], usecudnnongpu=True, padding='VALID', explicitpaddings=[], dataformat='NHWC', dilations=[1, 1, 1, 1] )
Alternatively, passing empty tensors also results in similar behavior:
python import tensorflow as tf
inputtensor = tf.constant([], shape=[0, 1, 1, 5], dtype=tf.float32) filtersizes = tf.constant([3, 8, 1, 1], shape=[4], dtype=tf.int32) outbackprop = tf.constant([], shape=[0, 1, 1, 1], dtype=tf.float32)
tf.rawops.Conv2DBackpropFilter( input=inputtensor, filtersizes=filtersizes, outbackprop=outbackprop, strides=[1, 66, 49, 1], usecudnnongpu=True, padding='VALID', explicitpaddings=[], dataformat='NHWC', dilations=[1, 1, 1, 1] )
This is because the implementation computes the size of the filter tensor but does not validate that it matches the number of elements in filtersizes. Later, when reading/writing to this buffer, code uses the value computed here, instead of the number of elements in the tensor.
Patches We have patched the issue in GitHub commit c570e2ecfc822941335ad48f6e10df4e21f11c96.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Yakun Zhang and Ying Wang of Baidu X-Team.
Impact An attacker can cause a heap buffer overflow in QuantizedReshape by passing in invalid thresholds for the quantization:
python import tensorflow as tf
tensor = tf.constant([], dtype=tf.qint32) shape = tf.constant([], dtype=tf.int32) inputmin = tf.constant([], dtype=tf.float32) inputmax = tf.constant([], dtype=tf.float32)
tf.rawops.QuantizedReshape(tensor=tensor, shape=shape, inputmin=inputmin, inputmax=inputmax)
This is because the implementation assumes that the 2 arguments are always valid scalars and tries to access the numeric value directly:
cc const auto& inputminfloattensor = ctx->input(2); ... const float inputminfloat = inputminfloattensor.flat<float>()(0); const auto& inputmaxfloattensor = ctx->input(3); ... const float inputmaxfloat = inputmaxfloattensor.flat<float>()(0);
However, if any of these tensors is empty, then .flat<T>() is an empty buffer and accessing the element at position 0 results in overflow.
Patches We have patched the issue in GitHub commit a324ac84e573fba362a5e53d4e74d5de6729933e.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Ying Wang and Yakun Zhang of Baidu X-Team.
Impact An attacker can trigger a heap buffer overflow in tf.rawops.QuantizedResizeBilinear by manipulating input values so that float rounding results in off-by-one error in accessing image elements:
python import tensorflow as tf
l = [256, 328, 361, 17, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 384] images = tf.constant(l, shape=[1, 1, 15, 1], dtype=tf.qint32) size = tf.constant([12, 6], shape=[2], dtype=tf.int32) min = tf.constant(80.22522735595703) max = tf.constant(80.39215850830078)
tf.rawops.QuantizedResizeBilinear(images=images, size=size, min=min, max=max, aligncorners=True, halfpixelcenters=True)
This is because the implementation computes two integers (representing the upper and lower bounds for interpolation) by ceiling and flooring a floating point value:
cc const float inf = std::floor(in); interpolation->lower[i] = std::max(staticcast<int64>(inf), staticcast<int64>(0)); interpolation->upper[i] = std::min(staticcast<int64>(std::ceil(in)), insize - 1); For some values of in, interpolation->upper[i] might be smaller than interpolation->lower[i]. This is an issue if interpolation->upper[i] is capped at insize-1 as it means that interpolation->lower[i] points outside of the image. Then, in the interpolation code, this would result in heap buffer overflow:
cc template <int RESOLUTION, typename T, typename TSCALE, typename TCALC> inline void OutputLerpForChannels(const InterpolationCache<TSCALE>& xs, const int64 x, const TSCALE ysilerp, const int channels, const float min, const float max, const T ysinputlowerptr, const T ysinputupperptr, T outputyptr) { const int64 xslower = xs.lower[x]; ... for (int c = 0; c < channels; ++c) { const T topleft = ysinputlowerptr[xslower + c]; ... } }
For the other cases where interpolation->upper[i] is smaller than interpolation->lower[i], we can set them to be equal without affecting the output.
Patches We have patched the issue in GitHub commit f851613f8f0fb0c838d160ced13c134f778e3ce7.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Ying Wang and Yakun Zhang of Baidu X-Team.
Impact If the splits argument of RaggedBincount does not specify a valid SparseTensor, then an attacker can trigger a heap buffer overflow:
python import tensorflow as tf tf.rawops.RaggedBincount(splits=[0], values=[1,1,1,1,1], size=5, weights=[1,2,3,4], binaryoutput=False)
This will cause a read from outside the bounds of the splits tensor buffer in the implementation of the RaggedBincount op:
cc for (int idx = 0; idx < numvalues; ++idx) { while (idx >= splits(batchidx)) { batchidx++; } ... }
Before the for loop, batchidx is set to 0. The user controls the splits array, making it contain only one element, 0. Thus, the code in the while loop would increment batchidx and then try to read splits(1), which is outside of bounds.
Patches We have patched the issue in GitHub commit eebb96c2830d48597d055d247c0e9aebaea94cd5.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2 and TensorFlow 2.3.3, as these are also affected.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by members of the Aivul Team from Qihoo 360.
Impact An attacker can trigger a null pointer dereference by providing an invalid permutation to tf.rawops.SparseMatrixSparseCholesky:
python import tensorflow as tf import numpy as np from tensorflow.python.ops.linalg.sparse import sparsecsrmatrixops
indicesarray = np.array([[0, 0]]) valuearray = np.array([-10.0], dtype=np.float32) denseshape = [1, 1] st = tf.SparseTensor(indicesarray, valuearray, denseshape)
input = sparsecsrmatrixops.sparsetensortocsrsparsematrix( st.indices, st.values, st.denseshape)
permutation = tf.constant([], shape=[1, 0], dtype=tf.int32) tf.rawops.SparseMatrixSparseCholesky(input=input, permutation=permutation, type=tf.float32)
This is because the implementation fails to properly validate the input arguments: cc void Compute(OpKernelContext ctx) final { ... const Tensor& inputpermutationindices = ctx->input(1); ... ValidateInputs(ctx, inputmatrix, inputpermutationindices, &batchsize, &numrows); ... }
void ValidateInputs(OpKernelContext ctx, const CSRSparseMatrix& sparsematrix, const Tensor& permutationindices, int batchsize, int64 numrows) { OPREQUIRES(ctx, sparsematrix.dtype() == DataTypeToEnum<T>::value, ...) ... } Although ValidateInputs is called and there are checks in the body of this function, the code proceeds to the next line in ValidateInputs since OPREQUIRES is a macro that only exits the current function.
cc #define OPREQUIRES(CTX, EXP, STATUS) \ do { \ if (!TFPREDICTTRUE(EXP)) { \ CheckNotInComputeAsync((CTX), "OPREQUIRESASYNC"); \ (CTX)->CtxFailure(FILE, LINE, (STATUS)); \ return; \ } \ } while (0)
Thus, the first validation condition that fails in ValidateInputs will cause an early return from that function. However, the caller will continue execution from the next line. The fix is to either explicitly check context->status() or to convert ValidateInputs to return a Status.
Patches We have patched the issue in GitHub commit e6a7c7cc18c3aaad1ae0872cb0a959f5c923d2bd.
The fix will be included in TensorFlow 2.5.0. We will also cherrypick this commit on TensorFlow 2.4.2, TensorFlow 2.3.3, TensorFlow 2.2.3 and TensorFlow 2.1.4, as these are also affected and still in supported range.
For more information Please consult our security guide for more information regarding the security model and how to contact us with issues and questions.
Attribution This vulnerability has been reported by Ying Wang and Yakun Zhang of Baidu X-Team.