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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions