mirror of
https://github.com/amnezia-vpn/amneziawg-linux-kernel-module.git
synced 2026-10-13 21:34:34 +00:00
[GH-ISSUE #228] wg_get_device_dump re-sends the same message forever when the first peer does not fit #132
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
amnezia-vpn/amneziawg-linux-kernel-module#132
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @rudenko-ks on GitHub (Aug 31, 2026).
Original GitHub issue: https://github.com/amnezia-vpn/amneziawg-linux-kernel-module/issues/228
When a device's own attributes fill most of the dump buffer, the first peer
cannot be appended, and the dump never advances. The kernel re-emits the same
message indefinitely instead of failing or making progress.
Plain WireGuard cannot reach this: its device block is a few hundred bytes, so
the first peer always fits. The AmneziaWG I1–I5 attributes make the device block
large enough to leave no room, which turns a latent condition into a reachable
one.
Mechanism
wg_get_device_dump, netlink.c (v3.1.20260812):On the first call
ctx->next_peeris NULL, sonext_peer_cursorstarts NULL.If
get_peerfails on the very first peer, the loop breaks at line 520 withnext_peer_cursorstill NULL anddone == false.Line 542 then assigns NULL back into
ctx->next_peer— no progress — and line543 returns
skb->len, which is non-zero. Netlink treats that as "more tocome" and calls the dump callback again with identical state. The same device
block is produced again, forever.
The peer path already has the pattern this case is missing:
get_peersavesctx->next_allowedip(netlink.c:389) so a peer whose allowed-ips overflowresumes correctly in the next message. Only the "not even the first peer fits"
case has no cursor to save.
Reproduction
Any interface whose device attributes leave less room than one peer needs.
With a 4096-byte reader buffer (what
amneziawg-toolsuses), the threshold is:Derived from the source and confirmed by 37 measurements with zero residual.
Concretely:
awgo-1, no header-protection key, one peer with an IPv4 endpoint→ 3628 bytes of I1–I5. A 15-character name with a key and an IPv6 endpoint
→ 3572.
Three bands, by total I1–I5 size in bytes:
Measured on one wedged interface: 20 000 identical 3932-byte messages in
0.554 s, and it does not stop.
The trigger is a handshake, not a configuration change
The kernel writes a peer's endpoint when the handshake completes, and the
endpoint costs 20 bytes (IPv4) or 32 (IPv6) in the dump. So an interface that
reads fine can become unreadable with no change to its configuration.
Observed on an unchanged interface with 3648 bytes of I1–I5:
awg showreturnsin 2 ms before any client connects, and hangs after the first handshake —
1.47 s of CPU and 599 MB RSS in the reader before it was killed.
This is what makes the bug hard to attribute in the field: the operator changes
nothing, a client connects, and the interface becomes unreadable.
Note on allowed-ips
They are not part of this. The resumable branch at netlink.c:389 paginates them
correctly; the continuation message carries the peer without key, PSK,
handshake or endpoint (52 bytes instead of 168). Verified up to 100 subnets on
a single peer with no change to the threshold.
Suggested direction
Two independent things, both cheap:
Either return
-EMSGSIZE, or record a cursor that lets the next call skipahead, so the dump terminates either way.
nlmsg_total_sizeof the device attributes is known before any peer isattempted — refusing early would give a clear error instead of a spin.
Related
hang and reboot with multi-kilobyte I1–I3. The symptom matches this bug.
the userspace half of this hang.
Environment
Kernel 6.8.0-138, module and tools
amneziawg 3.1.20260812, x86-64.