tsk-arasu's picture
Upload folder using huggingface_hub
0ef171e verified
|
Raw
History Blame Contribute Delete
8.95 kB

Null Pointer Dereference in ExecuTorch create_tensor_layout() via Missing TensorLayout.sizes (.ptd)

Target: ExecuTorch 1.3.1 (.ptd, huntr Model File Vulnerability program) Severity: Low-Medium (Denial of Service) CWE: CWE-476 (NULL Pointer Dereference) Component: extension/flat_tensor/flat_tensor_data_map.cpp Authentication Required: No β€” only requires a victim application to load an attacker-supplied .ptd file and call a public API.

Summary

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.

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.

Vulnerability Details

extension/flat_tensor/serialize/flat_tensor.fbs:

table TensorLayout {
  scalar_type: executorch_flatbuffer.ScalarType;
  sizes: [int32];        // not required
  dim_order: [uint8];    // not required
}

extension/flat_tensor/flat_tensor_data_map.cpp (pristine 1.3.1 source, lines 97–108):

Result<const TensorLayout> create_tensor_layout(
    const flat_tensor_flatbuffer::TensorLayout* tensor_layout) {
  ScalarType scalar_type =
      static_cast<ScalarType>(tensor_layout->scalar_type());
  const int dim = tensor_layout->sizes()->size();          // <-- crash site: sizes() may be null
  const auto serialized_sizes = tensor_layout->sizes()->data();
  const auto serialized_dim_order = tensor_layout->dim_order()->data();
  return TensorLayout::create(
      Span<const int32_t>(serialized_sizes, dim),
      Span<const uint8_t>(serialized_dim_order, dim),
      scalar_type);
}

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).

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.

Steps to Reproduce

Environment

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).

1. PoC file

poc/poc_tensorlayout_sizes_null.ptd (272 bytes, included in this report β€” sha256 f9c20d5697f9d147938eb31b188a14f82767252af47f5075358b7bc98c802476) is a well-formed .ptd file with:

  • One NamedData entry: key = "weight1", segment_index = 0
  • tensor_layout present (non-null), with scalar_type set to a valid value
  • tensor_layout.sizes omitted

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.

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.

2. Build the harness and trigger the crash

export ET_PARENT=/path/to/parent-of-executorch
C10_INC="$ET_SRC/runtime/core/portable_type/c10"
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"

clang++-16 -std=c++17 -fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all \
  $INCLUDES -DFLATBUFFERS_MAX_ALIGNMENT=1024 -DC10_USING_CUSTOM_GENERATED_MACROS \
  -c poc/harness_flat_tensor_fuzzer.cpp -o harness.o

clang++-16 -fsanitize=fuzzer,address,undefined -o poc_harness harness.o \
  "$ET_BUILD/extension/flat_tensor/libextension_flat_tensor.a" \
  "$ET_BUILD/extension/data_loader/libextension_data_loader.a" \
  "$ET_BUILD/libexecutorch_core.a"

export ASAN_OPTIONS="abort_on_error=1:symbolize=0"
export UBSAN_OPTIONS="halt_on_error=1:print_stacktrace=0"
./poc_harness -timeout=5 -runs=0 poc/poc_tensorlayout_sizes_null.ptd

Expected result (secure behavior)

get_tensor_layout("weight1") should return a clean Error::InvalidExternalData, since a TensorLayout with no sizes cannot describe a valid tensor shape.

Actual result β€” verified against the pristine (unmodified) ExecuTorch 1.3.1 source

Running: poc/poc_tensorlayout_sizes_null.ptd
extension/flat_tensor/flat_tensor_data_map.cpp:101:43: runtime error: member call on null pointer of type 'flatbuffers::Vector<int>'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior extension/flat_tensor/flat_tensor_data_map.cpp:101:43 in
==<pid>== ERROR: libFuzzer: deadly signal

Reproduced 3/3 identical runs against the pristine, unmodified source tree (re-verified live for this report, not against any locally-modified copy):

run 1: extension/flat_tensor/flat_tensor_data_map.cpp:101:43: runtime error: member call on null pointer of type 'flatbuffers::Vector<int>'
run 2: (identical)
run 3: (identical)

Impact

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.

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.

What's at risk: Availability only. No memory corruption or code execution.

Why not Critical: Same reasoning as the other null-pointer-dereference findings in this codebase β€” a controlled crash, not a memory-safety violation.

Suggested Remediation

In create_tensor_layout(), after checking tensor_layout itself for null, additionally check its sizes and dim_order fields:

Result<const TensorLayout> create_tensor_layout(
    const flat_tensor_flatbuffer::TensorLayout* tensor_layout) {
  if (tensor_layout == nullptr) {
    return Error::InvalidExternalData;
  }
  ScalarType scalar_type = static_cast<ScalarType>(tensor_layout->scalar_type());
  if (tensor_layout->sizes() == nullptr || tensor_layout->dim_order() == nullptr) {
    return Error::InvalidExternalData;
  }
  const int dim = tensor_layout->sizes()->size();
  const auto serialized_sizes = tensor_layout->sizes()->data();
  const auto serialized_dim_order = tensor_layout->dim_order()->data();
  return TensorLayout::create(
      Span<const int32_t>(serialized_sizes, dim),
      Span<const uint8_t>(serialized_dim_order, dim),
      scalar_type);
}

A regression test should build a .ptd NamedData.tensor_layout with sizes/dim_order omitted and assert a clean Error return.

Files Included in This Report

  • poc/poc_tensorlayout_sizes_null.ptd β€” the exact 272-byte PoC file used for all verification in this report (sha256 f9c20d5697f9d147938eb31b188a14f82767252af47f5075358b7bc98c802476)
  • poc/gen_poc.py β€” illustrative regeneration script (produces an equivalent-but-not-byte-identical file that triggers the same crash line β€” see note above)
  • poc/harness_flat_tensor_fuzzer.cpp β€” the harness used to trigger and reproduce the crash

huntr Submission Note

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.