You need to agree to share your Hugging Face 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.

Paddle-Lite naive_buffer/.nb loader -- unchecked prog_size OOB read

Target pin: 28fe23f222de1865e01f0ab41d2494a1222be4f0 (tag v2.14-rc, PaddlePaddle/Paddle-Lite)

Sink (source-confirmed at pin)

lite/model_parser/model_parser.cc:990-996 (LoadModelFbsFromMemory):

uint64_t prog_size;
reader->Read(&prog_size, sizeof(uint64_t));      // attacker-controlled, unvalidated
model_parser::Buffer prog_data(prog_size);       // CWE-789: eager alloc of attacker-chosen size
reader->Read(prog_data.data(), prog_size);        // CWE-125: no check vs remaining buffer length

lite/core/model/base/io.cc:72-76 (CharBufferReader::Read, the reader used for the in-memory .nb load path):

void CharBufferReader::Read(void* dst, size_t size) const {
  CHECK(dst);
  lite::TargetCopy(TargetType::kHost, dst, buf_ + cur_, size);  // memcpy-equivalent
  cur_ += size;                                                  // NO check that cur_+size <= length_
}

There is no bounds check anywhere between the untrusted prog_size read at model_parser.cc:991 and the raw copy at model_parser.cc:996 / io.cc:74. prog_size is a raw uint64_t taken directly from attacker-supplied model bytes.

Reachable surface

MobileConfig::set_model_from_buffer(const std::string&) (lite/api/paddle_api.cc:815) stores the entire input as lite_model_file_ with model_from_memory_=true. LightPredictorImpl::Init (lite/api/light_api_impl.cc:35) sees !lite_model_file().empty() && is_model_from_memory()==true and constructs LightPredictor(lite_model_file().c_str(), lite_model_file().length(), ...) (lite/api/light_api_impl.cc:47-49) -> LightPredictor::Build(const char*, size_t) (lite/api/light_api.cc:59-73) -> LoadModelNaiveFromMemory -> for meta_version==1 -> LoadModelFbsFromMemory -> sink above.

Note: this is the sibling in-memory entry point of set_model_from_file (the file-based set_model_from_file path uses BinaryFileReader, whose Read() calls fread + CHECK_EQ, which aborts cleanly on truncated reads instead of reading OOB -- see io.cc:52-57). The pure memory-safety OOB read requires the buffer entry point, set_model_from_buffer, which is the documented, commonly used sibling API (e.g. for models bundled as in-app resources/assets rather than loose files) and exists on every MobileConfig consumer, mobile or Python.

PoC

Payload (47 bytes total): meta_version=1 (2B) + opt_version (16B, ignored)

  • prog_size=0x40000000 (1 GiB, 8B LE) + 21 bytes of real trailing content. prog_size is 1073741803 bytes larger than the real remaining buffer.

Verified against the pip paddlelite==2.13rc0 wheel (pip3 install --user paddlelite), after confirming via 'git diff v2.13-rc 28fe23f2 -- lite/model_parser/model_parser.cc lite/core/model/base/io.cc' that both sink files are byte-identical between the wheel's version tag (v2.13-rc) and the requested pin (v2.14-rc / 28fe23f2).

Negative control (poc_negctrl.py)

A truthful prog_size (matches the real remaining bytes) with garbage flatbuffer content fails cleanly via a deliberate CHECK/LOG(FATAL) in flatbuffer verification (param_desc.h:102, 'CombinedParamsDesc verification failed') -> SIGABRT, exit 134. This is the intended, safe failure mode for malformed-but- honest input.

Exploit (poc_oob_read.py)

Same structure, but prog_size lies about the buffer length. Result: SIGSEGV, exit 139, si_code=SEGV_MAPERR.

strace -f -e trace=memory shows the causal chain directly:

brk(0x5825b5433000)                     = 0x5825b5433000     # top of heap just before the sink runs
...
mmap(NULL, 1073745920, PROT_READ|PROT_WRITE, ...) = 0x71e7045ff000   # eager alloc of prog_data (CWE-789), succeeds
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x5825b54333aa} ---

The fault address (0x5825b54333aa) is 938 bytes past the immediately preceding brk() boundary (0x5825b5433000) -- i.e. the unbounded TargetCopy read started inside the small (47-byte) heap-resident source buffer and walked forward past the top of the mapped heap into unmapped address space, exactly matching the missing cur_ + size <= length_ check in CharBufferReader::Read. Reproduced twice (strace_oob_read.log), same offset-from-brk each time.

Files

  • poc_oob_read.py -- the exploit; run with 'python3 poc_oob_read.py'
  • poc_negctrl.py -- negative control (truthful prog_size -> clean CHECK-abort, not memory-unsafe)
  • strace_oob_read.log -- strace of the exploit run showing the mmap(prog_data) + SEGV_MAPERR sequence
  • negctrl.log -- output of the negative control run (SIGABRT via deliberate CHECK)
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support