YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
- Caffe: int64→int32 Truncation in BlobShape Parsing — Shape Corruption / DoS
Caffe: int64→int32 Truncation in BlobShape Parsing — Shape Corruption / DoS
Status: CONFIRMED — READY TO SUBMIT
Severity: Medium (P3) — NOT Critical/P1
⚠️ RCE RESEARCH RESULT: NOT ACHIEVABLE
The copy loop in FromProto() is bounded by count_ (not proto.data_size()),
and a CHECK_EQ(count_, proto.data_size()) guard fires before any write.
SyncedMemory has no virtual functions (no vtable to overwrite).
This is a real bug with real impact, but severity is Medium, not Critical.
Target
- Repo: BVLC/caffe
- Platform: huntr.com
- Format:
.caffemodel(protobuf)
Root Cause
BlobShape.dim is declared as int64 in caffe.proto but cast to int32 at:
src/caffe/blob.cpp:40—shape_vec[i] = shape.dim(i)(no range check)src/caffe/blob.cpp:298—shape[i] = proto.shape().dim(i)(no range check)
A dim value of 0x100000001 (int64) truncates to 1 (int32) → count_ = 1.
Impact: Two Exploitable Effects
Effect 1: Controlled Process Abort (DoS)
Set dim = 0x100000001 (truncates to 1) + data[] with >1 entries.
CHECK_EQ(count_=1, proto.data_size()=N) → LOG(FATAL) → process abort.
Attacker controls WHEN Caffe crashes by controlling data count.
Effect 2: Silent Shape Corruption
Set dim = 0x100000001 (truncates to 1) + exactly 1 data entry.
CHECK_EQ(1, 1) passes. Blob accepted with shape [1] when it should be [4294967297].
Model that expects a 4B-element tensor operates on a 1-element blob.
Impact: adversarial inference manipulation / silent wrong-model behavior.
Why NOT a Heap Overflow
// FromProto() — blob.cpp:315-320
CHECK_EQ(count_, proto.data_size()); // ABORTS if mismatch
for (int i = 0; i < count_; ++i) { // bounded by count_, not proto.data_size()
data_vec[i] = proto.data(i); // only writes count_ elements
}
The CHECK guard fires before any write. Loop uses count_, not proto.data_size().
SyncedMemory has no virtual functions. No vtable overwrite possible.
Vulnerable Files
| File | Line | Issue |
|---|---|---|
src/caffe/blob.cpp |
40 | shape_vec[i] = shape.dim(i) — int64→int32, no range check |
src/caffe/blob.cpp |
298 | shape[i] = proto.shape().dim(i) — same in FromProto |
src/caffe/proto/caffe.proto |
BlobShape | repeated int64 dim consumed as int32 |
PoC Files
poc_caffe_truncation.py— demonstrates both DoS and silent corruption effects
Reproduction
python poc_caffe_truncation.py dos # controlled process abort
python poc_caffe_truncation.py corrupt # silent shape corruption
Fix
// blob.cpp — Reshape(const BlobShape& shape):
for (int i = 0; i < shape.dim_size(); ++i) {
CHECK_LE(shape.dim(i), INT_MAX) << "BlobShape dim exceeds INT_MAX";
CHECK_GE(shape.dim(i), 0) << "BlobShape dim is negative";
shape_vec[i] = static_cast<int>(shape.dim(i));
}
Note
Submit this SEPARATELY from caffe-oom-poc (the INT_MAX boundary case OOM bug). These are distinct vulnerabilities with different root causes and effects.