YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
PoC: heap OOB read-modify-write in Darknet denormalize_convolutional_layer (CWE-787/125)
Loading a crafted Darknet model (.cfg + .weights) via the darknet partial command corrupts heap memory:
denormalize_convolutional_layer indexes the per-layer weight buffer with the total weight count as the
inner-loop stride/bound instead of the per-filter count.
Root cause
src-lib/convolutional_layer.cpp:1104-1116:
for (int i = 0; i < l.n; ++i) { // i over n filters
const float scale = l.scales[i] / sqrt(l.rolling_variance[i] + 1e-5f);
for (int j = 0; j < l.nweights; ++j) // bound = TOTAL nweights, not per-filter
l.weights[i*l.nweights + j] *= scale; // :1113 index up to l.n*l.nweights-1
...
}
l.nweights = (c/groups)*n*size*size is the TOTAL weight count for all n filters (:764), and
l.weights = xcalloc(l.nweights, sizeof(float)) (:781) โ valid indices [0, nweights-1]. The loop uses
l.nweights as both the per-filter stride and the inner bound, so i*l.nweights + j reaches
l.n*l.nweights - 1 โ l.nร the allocation. For any conv layer with n>=2 filters and batch_normalize=1
(every real model), the i>=1 accesses land entirely past the heap buffer โ out-of-bounds read-modify-write
(the *= both reads and writes l.weights[...]). The correct inner stride is the per-filter count
l.nweights/l.n = (c/groups)*size*size. Reachable via darknet partial net.cfg net.weights out N
(src-cli/darknet_cli.cpp:282), which calls this on every batch-normalized CONVOLUTIONAL layer. Distinct
from the already-filed tree.cpp sscanf stack overflow.
Reproduce (AddressSanitizer)
g++ -fsanitize=address -g -O0 darknet_denormalize_oob_write_harness.cpp -o poc && ./poc
# n=3 filters, nweights(total)=27 ; l.weights allocated = 27 floats (valid index 0..26)
# denormalize inner loop bound = l.nweights(27); index reaches i*nweights+j up to 80 ...
# ==ERROR: AddressSanitizer: heap-buffer-overflow ... 0 bytes after the 108-byte region
Fix
Bound the inner loop by the per-filter weight count: for (j = 0; j < l.nweights/l.n; ++j) l.weights[i*(l.nweights/l.n) + j] *= scale;