You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

ExecuTorch Method::get_inputs(): out-of-bounds read via unvalidated ExecutionPlan.inputs value-index

Conclusion

CONFIRMED (real ASan SEGV). A structurally-valid .pte whose ExecutionPlan.inputs[i] holds an arbitrary value-table index causes an out-of-bounds read of the runtime values_ array inside executorch::runtime::Method::get_inputs() (runtime/executor/method.cpp:1436). The index comes from Method::get_input_index() (method.cpp:1801), which returns serialization_plan_->inputs()->Get(i) without validating it against the number of values β€” and get_inputs() uses it to index values_ directly, bypassing the ET_CHECK bounds guard that Method::get_value() applies.

The bug persists under the strongest verification mode (Program::Verification::InternalConsistency, i.e. full flatbuffers::Verifier

  • validate_program()), because neither the flatbuffers verifier nor validate_program() range-checks the inputs/outputs index vectors against the values table. This is an application-logic gap, not a verification-configuration issue.
  • Target: pytorch/executorch (ExecuTorch C++ runtime), category executorch
  • Commit verified: a6d812a082df57898b8608f56c867140cc9da32c; line 1436 identical in live main (fetched 2026-07-16 via raw.githubusercontent.com).
  • Component: runtime/executor/method.cpp β€” Method::get_inputs() / Method::get_input_index()
  • Class: CWE-125 (Out-of-bounds Read)
  • Impact: DoS (SEGV) and potential information disclosure (adjacent memory surfaced to caller as EValue payloads) on a public, documented runtime API when handed an untrusted model.

Root cause

runtime/executor/method.cpp:

// get_inputs(): OOB β€” indexes values_ directly, no bounds check
for (size_t i = 0; i < n_input; ++i) {
  input_evalues[i] = values_[get_input_index(i)];   // line 1436
  ...
}

size_t Method::get_input_index(size_t i) const {
  ET_CHECK_MSG(i < inputs_size(), ...);              // only checks loop index i
  return static_cast<size_t>(serialization_plan_->inputs()->Get(i)); // UNVALIDATED value index
}

Contrast the guarded accessors, which route the same index through get_value() / mutable_value():

const EValue& Method::get_value(size_t i) const {
  ET_CHECK_MSG(i < n_value_, ...);   // bounds check present here
  return values_[i];
}

get_input(i) (singular), set_input, MoveCall, FreeCall, etc. all go through get_value/mutable_value and are bounds-checked. get_inputs() (plural) is the one path that indexes values_ directly, so a malicious inputs[i] is dereferenced out of bounds.

validate_program() (runtime/executor/program_validation.cpp) validates each value's tensor and each TensorList item index, but never validates the plan-level inputs()/outputs() index vectors β€” so InternalConsistency does not catch this.

Proof of concept

  • build_pte.cpp β€” emits a minimal program: values=[Int(0)] (so values_ has exactly one element, index 0), inputs=[0x11111111], one chain with a single FreeCall(value_index=0) (lets Method::init() complete without any operator registration), empty delegates. Fully structurally valid.
  • harness.cpp β€” Program::load() (default Minimal) β†’ load_method("forward") β†’ Method::get_inputs(buf, 8).
  • harness_verify.cpp β€” identical but Program::load(..., InternalConsistency).
  • build.sh β€” compiles the ExecuTorch runtime sources + harness with -fsanitize=address.

Crash (verbatim, default Minimal verification)

[harness] load_method OK. inputs_size=1. Calling get_inputs() (expected OOB read here)...
AddressSanitizer:DEADLYSIGNAL
==582470==ERROR: AddressSanitizer: SEGV on unknown address 0x55e6641fd328 ...
==582470==The signal is caused by a READ memory access.
    #0 ... in executorch::runtime::EValue::EValue(EValue const&) runtime/core/evalue.h:162:55
    #1 ... in executorch::runtime::EValue::operator=(EValue const&) runtime/core/evalue.h:180:13
    #2 ... in executorch::runtime::Method::get_inputs(EValue*, unsigned long) runtime/executor/method.cpp:1436:22
    #3 ... in main getinputs_oob/harness.cpp:67:20
SUMMARY: AddressSanitizer: SEGV runtime/core/evalue.h:162:55 in EValue::EValue(EValue const&)

Same crash under full InternalConsistency verification

harness_verify_asan malicious.pte β†’ identical SEGV at method.cpp:1436, proving the malicious file passes VerifyProgramBuffer + validate_program().

Negative control

Same generator with inputs[0]=0x0 (benign.pte, valid index): both harnesses print get_inputs returned 0x0 (NO CRASH) and exit cleanly. Only the out-of-range index triggers the fault.

Distinctness / dedup

Distinct from all prior session/public ExecuTorch findings:

  • Not a NULL deref (compilespec / backend-delegate-data / FlatTensor).
  • Not a backend-delegate bug (XNNPACK / Vulkan / QNN / Ethos-U / WebGPU).
  • Distinct from huntr-poc-executorch-oob (the pybindings Minimal-verification-downgrade / flatbuffer-verifier-bypass OOB): that bug relies on the Verifier being skipped and an inflated vector length prefix. This bug is a semantic index-range gap in Method::get_inputs() that the Verifier is not designed to catch and that survives InternalConsistency.
  • File/line: runtime/executor/method.cpp:1436 / :1801 (core executor).

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support