Skip to content

Security: TC-deferral timer is rearmed on every new packet, giving an attacker unbounded growth window #1726

@bluetoothbot

Description

@bluetoothbot

Problem

After appending a deferred packet, handle_query_or_defer always calls self._cancel_any_timers_for_addr(addr) and re-arms self._timers[addr] to fire 400–500 ms in the future. This is the assembly window for legitimate, fragmented TC queries (RFC 6762 §18.5), but it has no upper bound — a peer that streams TC packets faster than 400 ms keeps moving the deadline forward indefinitely, so the deferred list is never flushed. Combined with finding #1's lack of a per-list cap, this is what makes the memory-growth attack open-ended rather than self-limiting after ~500 ms.

Why This Matters

A correctly-behaving sender sends its fragmented TC pieces back-to-back; a malicious sender just keeps the stream open. Without a first-packet-arrival deadline, the listener has no way to decide "stop waiting and process what I have," so memory pressure compounds for as long as the attacker chooses.

Suggested Fix

Track the first TC-arrival time for each addr (e.g. alongside the list in _deferred), and on each new packet refuse to reset the timer further than first_arrival + _TC_DELAY_RANDOM_INTERVAL[1] into the future. When the deadline is hit, flush whatever is queued (or drop the queue) regardless of fresh arrivals. This preserves the legitimate fragment-reassembly window while bounding the worst case.

Details

Severity 🟡 Medium
Category dos
Location src/zeroconf/_listener.py:206-218, 220-223
Effort ⚡ Quick fix

🤖 Created by Kōan from audit session

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions