1## TFSA-2020-005: Out of bounds access in TFLite operators 2 3### CVE Number 4CVE-2020-15211 5 6### Impact 7In TensorFlow Lite, saved models in the flatbuffer format use a double indexing 8scheme: a model has a set of subgraphs, each subgraph has a set of operators and 9each operator has a set of input/output tensors. The flatbuffer format uses 10indices for the tensors, indexing into an array of tensors that is owned by the 11subgraph. This results in a pattern of double array indexing when trying to 12[get the data of each 13tensor](https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/kernels/kernel_util.cc#L36): 14```cc 15 return &context->tensors[node->inputs->data[index]]; 16``` 17 18However, some operators can have some tensors be optional. To handle this 19scenario, the flatbuffer model uses a negative `-1` value as [index for these tensors](https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/c/common.h#L82): 20```cc 21#define kTfLiteOptionalTensor (-1) 22``` 23 24This results in [special casing during validation at model loading 25time](https://github.com/tensorflow/tensorflow/blob/0e68f4d3295eb0281a517c3662f6698992b7b2cf/tensorflow/lite/core/subgraph.cc#L566-L580): 26```cc 27 for (int i = 0; i < length; i++) { 28 int index = indices[i]; 29 // Continue if index == kTfLiteOptionalTensor before additional comparisons 30 // below, size_t(-1) is always >= context_tensors_size. 31 if (index == kTfLiteOptionalTensor) { 32 continue; 33 } 34 if (index < 0 || static_cast<size_t>(index) >= context_.tensors_size) { 35 ReportError( 36 "Invalid tensor index %d in %s. The subgraph has %d tensors\n", index, 37 label, context_.tensors_size); 38 consistent_ = false; 39 return kTfLiteError; 40 } 41 } 42``` 43 44Unfortunately, this means that the `-1` index is a valid tensor index for any 45operator, including those that don't expect optional inputs and including for 46output tensors. Thus, this allows writing and reading from outside the bounds of 47heap allocated arrays, although only at a specific offset from the start of 48these arrays. 49 50This results in both read and write gadgets, albeit very limited in scope. 51 52### Vulnerable Versions 53TensorFlow 1.15.0, 1.15.1, 1.15.2, 1.15.3, 2.0.0, 2.0.1, 2.0.2, 2.1.0, 2.1.1, 542.2.0, 2.3.0. 55 56### Patches 57We have patched the issue in several commits 58([46d5b0852](https://github.com/tensorflow/tensorflow/commit/46d5b0852), 59[00302787b7](https://github.com/tensorflow/tensorflow/commit/00302787b7), 60[e11f5558](https://github.com/tensorflow/tensorflow/commit/e11f5558), 61[cd31fd0ce](https://github.com/tensorflow/tensorflow/commit/cd31fd0ce), 62[1970c21](https://github.com/tensorflow/tensorflow/commit/1970c21), and 63[fff2c83](https://github.com/tensorflow/tensorflow/commit/fff2c83)). We will 64release patch releases for all versions between 1.15 and 2.3. 65 66We recommend users to upgrade to TensorFlow 1.15.4, 2.0.3, 2.1.2, 2.2.1, or 672.3.1. 68 69### Workarounds 70A potential workaround would be to add a custom `Verifier` to the model loading 71code to ensure that only operators which accept optional inputs use the `-1` 72special value and only for the tensors that they expect to be optional. Since 73this allow-list type approach is erro-prone, we advise upgrading to the patched 74code. 75 76### For more information 77Please consult [our security 78guide](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md) for 79more information regarding the security model and how to contact us with issues 80and questions. 81 82### Attribution 83This vulnerability has been reported by members of the Aivul Team from Qihoo 84360. 85