mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
Validate bloom filter fill ratio on FilterAnnounce ingress
A malformed FilterAnnounce whose fill ratio produces an implausibly high false-positive rate is mostly useless for routing and, once merged into our outgoing filter via bitwise OR, propagates the saturated state to tree peers one hop per announce tick. A saturated filter also made estimated_count() return f64::INFINITY, which compute_mesh_size summed into its cached estimate. handle_filter_announce now rejects inbound FilterAnnounce whose derived FPR exceeds `node.bloom.max_inbound_fpr` (new config field, default 0.05 ≈ fill 0.549 at k=5). Rejection is silent on the wire, logs at WARN, and increments a new `bloom.fill_exceeded` counter. The peer's prior stored filter and filter_sequence are left unchanged so a single rejected announce does not wipe the peer's existing contribution to aggregation. After a successful outgoing FilterAnnounce send, a rate-limited WARN fires if our own filter's FPR exceeds the same cap, surfacing aggregation drift. Limited to once per 60 seconds via a new Node.last_self_warn field. BloomFilter::estimated_count() now takes max_fpr and returns Option<f64>. Returns None for saturated filters (regardless of cap) or when the filter's FPR exceeds max_fpr. Callers updated: debug logs render None as "—", the Debug impl uses f64::INFINITY as "no cap" and prints "saturated" instead of inf, control-socket JSON emits null, and compute_mesh_size propagates None into the already- Option<u64> estimated_mesh_size field.
This commit is contained in:
@@ -13,6 +13,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
and `.deb` packages on `v*` tag push, with SHA-256 checksums
|
||||
- AUR publish workflow for tagged stable releases
|
||||
|
||||
### Security
|
||||
|
||||
- Bloom filter poisoning defense. Reject inbound FilterAnnounce
|
||||
messages whose false-positive rate exceeds a configurable cap
|
||||
(`node.bloom.max_inbound_fpr`, default 0.05). Previously a peer
|
||||
running a modified build could send an all-ones filter, causing
|
||||
(1) lookup attraction / black-hole routing for unknown targets,
|
||||
(2) aggregation contamination as the poisoned bits propagated one
|
||||
hop per announce tick via strict-OR merging, and (3) mesh-size
|
||||
estimate blowup to `f64::INFINITY`. Rejection is silent on the
|
||||
wire; rejected announces log at WARN and increment a new
|
||||
`bloom.fill_exceeded` counter. The peer's prior accepted filter
|
||||
and sequence number are preserved on rejection so a single bad
|
||||
announce cannot wipe a peer's contribution to aggregation.
|
||||
An independent self-plausibility WARN fires (rate-limited to once
|
||||
per 60s) if our own outgoing filter ever exceeds the cap,
|
||||
surfacing aggregation drift or ingress-check bypasses.
|
||||
`BloomFilter::estimated_count` now returns `Option<f64>` and
|
||||
returns `None` for saturated filters, preventing `f64::INFINITY`
|
||||
from propagating into mesh-size estimates. The node-level
|
||||
`estimated_mesh_size` field (already `Option<u64>`) propagates
|
||||
`None` when any contributing filter is above cap.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Control socket path detection in fipsctl and fipstop now checks for
|
||||
|
||||
Reference in New Issue
Block a user