Skip to content

fix(striped_locks): guard against connectivity-driven overflow - #763

Merged
ashvardanian merged 2 commits into
unum-cloud:main-devfrom
desertfury:fix/fuzz-striped-locks-overflow
May 24, 2026
Merged

fix(striped_locks): guard against connectivity-driven overflow#763
ashvardanian merged 2 commits into
unum-cloud:main-devfrom
desertfury:fix/fuzz-striped-locks-overflow

Conversation

@desertfury

Copy link
Copy Markdown
Contributor

striped_locks_gt's constructor computed count_ * sizeof(padded_lock_t) with no overflow check, so an attacker-supplied connectivity in the file header could wrap the multiplication and yield a buffer way too small for the stripe array that the constructor then placement-new'd into. ASAN flagged a 128-byte heap-buffer-overflow on the first stripe write during load_from_stream's call into try_reserve.

Adds two layers of defense:

  • index_config_t::validate caps connectivity / connectivity_base at 2^20. That's already higher than any sane HNSW workload would use and well below the overflow threshold.
  • The striped-locks constructor itself clamps desired / count_ to a max that keeps both the * connectivity * 4 and * sizeof(padded_lock_t) multiplications inside size_t, so a direct in-process caller passing wild threads is still safe.

Add checked size arithmetic helpers and wire them into allocation, reservation, serialization, and dense metadata paths that previously relied on unchecked size_t math.

Co-authored-by: Mikhail Chichvarin <6496186+desertfury@users.noreply.github.com>

Co-authored-by: Mikhail Chichvarin <desertfury@nebius.com>

Co-authored-by: Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>
@ashvardanian
ashvardanian changed the base branch from main to main-dev May 24, 2026 12:51
@ashvardanian
ashvardanian force-pushed the fix/fuzz-striped-locks-overflow branch from 7c7e2ea to a7ab827 Compare May 24, 2026 12:55
@ashvardanian
ashvardanian merged commit 89da7c5 into unum-cloud:main-dev May 24, 2026
10 of 11 checks passed
ashvardanian pushed a commit that referenced this pull request May 24, 2026
### Patch

- Fix: Refuse operations without reserved thread contexts (#757) (b8d3403)
- Fix: Checked arithmetic for allocation sizes (#763) (89da7c5)
- Fix: Preserve hash lookup capacity across thread reserves (#765) (3cf843b)
- Fix: Guard quantized casts against zero-magnitude inputs (#758) (0c903f4)
- Fix: Refuse missing metrics in C change-metric API (#760) (490c1b2)
- Fix: Short-circuit self-renames (#761) (830f31a)
- Fix: Keep `vectors_lookup_` capacity after `clear()` #759 (9d77be5)
- Improve: Serialize concurrent same-`Index` Python access with a mutex (47528b5)
- Improve: Test GIL-release contract and progress-callback path (a598493)
- Improve: Release Python GIL during long index operations (d8be67d)
- Fix: Restore `ring_gt::try_push` return value (18c44ee)
- Fix: Stop JavaScript `Remove` loop after exception throw (f3e1052)
- Fix: Stop `usearch_init` on `make` failure (2aa0070)
- Fix: Stop C-ABI metadata readers on failure (34889ee)
- Fix: Report OOM from C-ABI thread-limit changers (ad24056)
- Fix: Bounded probe in `equal_iterator_gt::operator++` (b779c47)
- Fix: Resize cast buffer in `change_metric` for new bytes-per-vector (d544745)
- Fix: Eager-reserve thread contexts in `index_dense_gt::make` (#755) (b296566)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants