tsk-arasu's picture
Upload folder using huggingface_hub
c6c65e3 verified
|
Raw
History Blame Contribute Delete
7.66 kB

Null Pointer Dereference in ExecuTorch FlatTensorDataMap::get_key() via Missing NamedData.key (.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 enumeration API.

Summary

FlatTensorDataMap::get_key() is a public API for enumerating the names of tensors/blobs stored in a .ptd file by index β€” the standard pattern for an application to discover what data a file contains before requesting it by name. It dereferences NamedData.key without checking it for null, even though key is an ordinary (non-required) field in the schema. A .ptd file with a NamedData entry present in the named_data vector (so it is counted by get_num_keys()) but whose own key field is omitted crashes any process that enumerates keys by index β€” a completely standard, expected usage pattern, not an edge case.

Confirmed against the pristine, unmodified ExecuTorch 1.3.1 source.

Vulnerability Details

extension/flat_tensor/serialize/flat_tensor.fbs:

table NamedData {
  key: string;              // not required
  segment_index: uint32;
  tensor_layout: TensorLayout;
}

extension/flat_tensor/flat_tensor_data_map.cpp (pristine 1.3.1 source, lines 197–211):

ET_NODISCARD Result<uint32_t> FlatTensorDataMap::get_num_keys() const {
  return flat_tensor_->named_data()->size();
}

ET_NODISCARD Result<const char*> FlatTensorDataMap::get_key(
    uint32_t index) const {
  uint32_t num_keys = get_num_keys().get();
  ET_CHECK_OR_RETURN_ERROR(
      index >= 0 && index < num_keys,
      InvalidArgument,
      "Index %u out of range of size %u",
      index,
      num_keys);
  return flat_tensor_->named_data()->Get(index)->key()->c_str();   // <-- crash site, line 201 (offset within function)
}

FlatTensorDataMap::load()'s validation only checks that the named_data vector itself is non-null at the top level β€” it never inspects the fields of individual NamedData elements. get_named_data() (the linear-search helper backing get_tensor_layout()/get_data()/load_data_into()) happens to implicitly avoid crashing on a null key in some cases due to how its comparison is structured, but get_key() is a completely separate, simpler code path that enumerates by index directly β€” it does not go through get_named_data() at all, so it inherits none of that incidental behavior.

Steps to Reproduce

Environment

Linux x86-64, ExecuTorch 1.3.1 pristine source, clang-16, CMake, Ninja. No authentication, no host access.

1. Build ExecuTorch with sanitizers

Same build as REPORT-01 Step 1 (EXECUTORCH_BUILD_EXTENSION_FLAT_TENSOR=ON).

2. Build the harness (poc/harness_flat_tensor_fuzzer.cpp, included β€” identical to REPORT-01's harness, which already calls get_key() for every index up to get_num_keys())

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"

3. PoC file

poc/poc_get_key_null.ptd (272 bytes, included in this report β€” sha256 427bc13020be820b41aafec2c6e00de360fe97185d3879d5ec770594c21ac39) contains a named_data vector with at least one NamedData entry whose key field is omitted.

4. Trigger the crash

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_get_key_null.ptd

Expected result (secure behavior)

get_key() should return a clean Error (e.g. InvalidExternalData) for an entry with no key, rather than crashing.

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

Running: poc/poc_get_key_null.ptd
extension/flat_tensor/flat_tensor_data_map.cpp:201:57: runtime error: member call on null pointer of type 'flatbuffers::String'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior extension/flat_tensor/flat_tensor_data_map.cpp:201:57 in
==<pid>== ERROR: libFuzzer: deadly signal

Reproduced 3/3 identical runs against the pristine source (re-verified live for this report):

run 1: extension/flat_tensor/flat_tensor_data_map.cpp:201:57: runtime error: member call on null pointer of type 'flatbuffers::String'
run 2: (identical)
run 3: (identical)

Impact

Who is affected: Any application enumerating tensor/blob names in a .ptd file via get_num_keys() + get_key() β€” the standard discovery pattern for this format.

What the attacker can do: Cause a deterministic crash simply by having one entry in the named_data vector with no key β€” the file still loads successfully (the vector itself is present), so the crash only surfaces during ordinary enumeration.

What's at risk: Availability only.

Why not Critical: Controlled null-pointer dereference, no memory corruption or code execution.

Suggested Remediation

ET_NODISCARD Result<const char*> FlatTensorDataMap::get_key(
    uint32_t index) const {
  uint32_t num_keys = get_num_keys().get();
  ET_CHECK_OR_RETURN_ERROR(
      index >= 0 && index < num_keys,
      InvalidArgument,
      "Index %u out of range of size %u",
      index,
      num_keys);
  auto* named_data = flat_tensor_->named_data()->Get(index);
  ET_CHECK_OR_RETURN_ERROR(
      named_data != nullptr && named_data->key() != nullptr,
      InvalidExternalData,
      "NamedData entry %u or its key is null",
      index);
  return named_data->key()->c_str();
}

Design recommendation: this is one of several findings in this file (see companion reports on get_tensor_layout()/create_tensor_layout()) where the file validates the top-level presence of named_data/segments vectors at load() time but never validates the fields within each element. A single validation pass over named_data() at load time β€” or a shared per-entry validator called from every accessor β€” would close this entire class of findings at once rather than requiring a separate patch per accessor as each is independently discovered.

A regression test should build a .ptd with a NamedData entry that has key omitted, asserting get_key() returns a clean Error rather than crashing.

Files Included in This Report

  • poc/poc_get_key_null.ptd β€” the 272-byte PoC file (sha256 427bc13020be820b41aafec2c6e00de360fe97185d3879d5ec770594c21ac39)
  • poc/harness_flat_tensor_fuzzer.cpp β€” the harness used to trigger and reproduce the crash (same binary as REPORT-01/02/04, which all target extension/flat_tensor/flat_tensor_data_map.cpp)

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_get_key_null.ptd is ready for that upload.