Skip to content

harden(ingest): validate inbound CMS/CountSketch wire dimensions (defensive) - #344

Merged
zzylol merged 1 commit into
mainfrom
harden/sketch-dim-validation
May 26, 2026
Merged

zzylol merged 1 commit into
mainfrom
harden/sketch-dim-validation

Conversation

@zzylol

@zzylol zzylol commented May 26, 2026

Copy link
Copy Markdown
Contributor

Optional, non-breaking defense-in-depth: validate the rows/cols declared on inbound modified-OTLP CMS/CountSketch data points before reconstructing the matrix, so a malformed/adversarial payload is skipped (logged) rather than panicking or producing a degenerate sketch. Companion to ProjectASAP/ASAPCollector#451 — per that compatibility analysis the backend needs no required change; this is hardening only.

What

New validate_sketch_dims() (shared by both accumulators), wired into from_sketchlib_proto_bytes:

  • reject rows < 1 or cols < 1;
  • reject the narrow-hash-budget violation rows * ceil(log2(cols)) > 64;
  • reject oversized dims rows * cols > 8Mi cells (all products saturating_mul, so no overflow/panic).

On rejection it returns Err (never panics); the existing ingest caller already skips the data point (decoded_failed += 1; continue), now logged at warn! for dim rejections (ordinary decode fallbacks stay debug!).

Files:

  • data_plane/src/precompute_engine/operators/count_min_sketch_accumulator.rs (validator + wiring + 3 tests)
  • data_plane/src/precompute_engine/operators/count_sketch_accumulator.rs (calls shared validator + 2 tests)
  • data_plane/src/drivers/ingest/otel.rs (warn-log dim rejections at the skip site)

On the budget formula

The naive floor(log2(cols))+2 > 64 would wrongly reject the canonical 5×2048 and 5×4096 configs. The correct producer-side condition — verified against asap_sketchlib's MatrixFastHash::assert_compatible (matrix_storage.rs: the Packed64 wire hasher reads ceil(log2(cols)) column-index bits per row from one 64-bit word) — is rows * ceil(log2(cols)) > 64, which admits 5×2048/5×4096/5×2000/4×1000 and rejects degenerate dims. This matches the edge-side guard added in ASAPCollector#451, so producer and consumer agree.

Verification / caveat (honest)

Validation logic verified standalone (rustc) for all required-valid + reject cases (no panic; correct messages); unit tests mirror it. Full cargo test -p data_plane could not run locally due to a pre-existing, unrelated dependency skew: the path-dep'd asap-precompute-rs in the local ASAPCollector checkout is stale against the current asap_sketchlib (d7ca0ce, which renamed CountMinSketchCountMin etc. and added proto fields) — confirmed it fails identically without any of my files, while asap_sketchlib (my actual dependency) builds and exposes every API used. Should build cleanly in CI with pinned deps.

🤖 Generated with Claude Code

…rix reconstruct

Defensive, non-breaking hardening on the modified-OTLP frequency-sketch
ingest path. Before reconstructing a CMS / CountSketch matrix from the
wire-declared `(rows, cols)`, validate the dims so a malformed / hostile
payload fails gracefully instead of risking a degenerate matrix or a huge
allocation.

New shared `validate_sketch_dims` helper (in count_min_sketch_accumulator,
reused by count_sketch_accumulator) rejects:
- `rows < 1` or `cols < 1` (degenerate, no cells);
- narrow-hash-budget violation `rows * ceil(log2(cols)) > 64` — the point at
  which the cross-language Packed64 wire hasher's per-row column slices
  overflow / alias the 64-bit word and the matrix-cell layout degrades
  (mirrors sketchlib's `MatrixFastHash::assert_compatible`); checking the
  column-index bits alone keeps the realistic configs 5x2048 / 5x4096 /
  5x2000 valid;
- obviously-oversized dims `rows * cols > 8M cells` to cap allocation.

On rejection the decoder returns `Err` (never panics); the existing OTLP
ingest caller already skips that data point and increments `decoded_failed`.
That call site now logs dim-validation rejections at WARN (ordinary decode
fallbacks stay at DEBUG to avoid spam). Valid configs decode unchanged.

Unit tests added to both accumulators: a malformed-dim data point is
skipped (Err, no panic), a valid one still decodes, plus zero/budget/cap/
extreme-value (saturating) cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant