mirror of
https://github.com/amnezia-vpn/amneziawg-linux-kernel-module.git
synced 2026-10-13 21:34:34 +00:00
[GH-ISSUE #139] Kernel oops (page fault) in jp_spec_applymods → random_byte_modifier during interface teardown #85
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#85
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 @remotetohome on GitHub (Feb 11, 2026).
Original GitHub issue: https://github.com/amnezia-vpn/amneziawg-linux-kernel-module/issues/139
Originally assigned to: @ygurov on GitHub.
Description
Running
awg-quick downon an active AWG 2.0 tunnel with I1–I5 CPS parameters causes a kernel oops (page fault) that results in a hard system freeze requiring a power cycle. The crash occurs because thewg-kexhandshake worker is still running whenjp_spec_free()releases the junk packet spec buffers, leading to a use-after-free inrandom_byte_modifier→get_random_bytes→chacha_block_generic.Steps to reproduce
<r 885><r 374>)sudo awg-quick up ./awg_client.confsudo awg-quick down ./awg_client.confRoot cause analysis
The
wg-kexworkqueue (wg_packet_handshake_send_worker) races with interface teardown. Duringawg-quick down:jp_spec_free()which doeskfree(spec->pkt)andkfree(spec->mods)wg-kexworkqueue worker is still executingwg_packet_send_handshake_initiation→jp_spec_applymodsjp_spec_applymodsiteratesspec->mods[]and callsmod->func(mod->buf, mod->buf_len, peer)mod->funcisrandom_byte_modifier, which callsget_random_bytes(buf, len)wherebufpoints to freed memoryget_random_bytes→_get_random_bytes→chacha_block_generictries to write to the freed buffer → page faultThe
wg-kexworkqueue needs to be flushed/cancelled beforejp_spec_free()releases the buffers, or the junk packet specs need reference counting to prevent use-after-free.This is related to #102 (memory leak in junk.c) — both issues stem from lifecycle management of the
jp_specallocations.Kernel oops
Environment
b2e234ba31)<r 885><r 374>,<r 104>,<r 61>,<r 241>,<r 109>)Workaround
Remove the peer before bringing down the interface to stop handshake attempts:
@janusloo commented on GitHub (Mar 17, 2026):
Hi, I encountered the same issue with the CPS (Custom Protocol Signature) chain. Whenever I add/delete profiles the whole container will crash and along with my Pi. I have to power cycle it down to get it back online.
Also after a while, when 1 or more clients are connecting, the container will crash when using CPS for I1 (e.g. <r 32>).
I got this error:
There seems to be a "race condition" in the kernel module code where it tries to apply the I1 obfuscation modifiers (jp_spec_applymods) to a packet while the underlying memory for those modifiers is being freed or moved during the sync. This results in the kernel trying to read from a restricted memory address, causing the crash.
Please take a look at this. Thanks in advance!
@remotetohome commented on GitHub (Mar 25, 2026):
Update: Second failure mode — workqueue deadlock blocking system suspend
Hit this again on the latest DKMS build (
26f5df0, March 22 2026). Same race condition, different outcome — instead of a page fault crash, the freed memory was reused by the slab allocator, which corrupted workqueue state and causedflush_workqueueto hang indefinitely.The
ip link deleteprocess gets stuck in D state:The process is unkillable (D state) and blocks system suspend - the kernel's freeze_processes loop fails with "1 tasks refusing to freeze" and aborts. The only recovery is a reboot. In some ways this is worse than the crash variant, since the system appears to keep running but can never sleep again and the stuck process never clears.
Same root cause:
jp_spec_free()inwg_destruct()runs before the workqueues are flushed. Depending on slab timing, the handshake worker hits either unmapped memory (crash) or reused memory (corruption/deadlock).Same kernel, same hardware as the original report (6.8.0-106-generic, ThinkPad E16 Gen 1 AMD).
@remotetohome commented on GitHub (Mar 25, 2026):
@ygurov - PS.. definitely using AI to help with the bug diagnosis and prep.. but this is real human reporting. I'm doing AWG2 setups for clients daily and constantly testing tunnels via awg-quick.
I sincerely appreciate all the work on this project.
@janusloo commented on GitHub (Mar 26, 2026):
When can we expect the PR be merged and released? Thanks!
@Jipok commented on GitHub (Mar 28, 2026):
I just hit same problem:
Full dmesg log
Instead of using
awg-quick, I am managing the interface via my jwg with uses forked wgctrl-go library.@Jipok commented on GitHub (Mar 28, 2026):
This crash triggers without bringing the interface down. It happens during a live config sync. M.b. because my tool sets
ReplacePeers: truewhen applying the config.@alandarev commented on GitHub (Mar 31, 2026):
Encountering the same issue, but during the initial handshake, not teardown. Details below.
I1/I2parameters cause kernel buffer overflow injp_spec_applymods→ system crashEnvironment
6.19.6-zen1-1-zen(linux-zen)1.0.20251009(unsigned, DKMS)awg-quickDescription
Adding
S3,S4,I1,I2parameters to an AmneziaWG config (used for STUN/protocolcamouflage in the 2.0 protocol) causes a kernel page fault during a WireGuard handshake,
cascading into multiple oopses and leaving the system unresponsive.
Root cause (analysis)
I1/I2use<r 12>to generate 12 random bytes, which callsget_random_bytes → chacha_block_generic. It appearsjp_spec_applymodsallocates a32-byte output buffer, but
chacha_block_genericrequires 64 bytes — resulting ina write past the end of the buffer (
rbx+0x20→ unmapped page).The initial oops corrupted kernel memory, which cascaded into 5 more oopses across
unrelated processes (
.NET TP Worker,waybar,fd), page table corruption, andeventually a "scheduling while atomic" BUG that made the kernel unresponsive.
Kernel oops — oops #1 (root cause)
The fault address
ffff8b7a048f5000is exactly 32 bytes past the RBX buffer baseffff8b7a048f4fe0(0xfe0 + 0x20 = 0x1000→ next page, unmapped).Cascade — oopses #2–#6
The initial memory corruption propagated to unrelated processes within ~2 seconds:
#2—.NET TP Worker: corrupted page table at7f15f1a55968#3—waybar: general protection fault indup_mmap(non-canonical address0x72d58ae070a97f00)#4—.NET TP Worker(second instance): corrupted page table#5—fd: bad page map inrseq_set_ids_get_csaddr#6— kernel tried "Fixing recursive fault but reboot is needed!" → BUG: scheduling while atomic → unresponsiveReproduction
S3,S4,I1,I2parameters to an AmneziaWG config (e.g. from the STUNcamouflage feature in AmneziaWG 2.0).
awg-quick up <config>.wg_packet_handshake_send_worker.Workaround
Remove
S3,S4,I1,I2from the config. No crashes observed after doing so.@h7lv2 commented on GitHub (May 20, 2026):
Me too. Seeing this across two consecutive boots, with slightly different crash signatures each time.
Environment:
7.0.9-1-cachyosAMNEZIAWG-MODULE=1.0.20260329S1throughS4as well asI1are set, parametersI2throughI5are commented out.Boot −1: exact match —
jp_spec_applymodsrace during active handshakeThis is the crash that matches the issue description verbatim. The
wg-kexworkqueue was mid-handshake insidejp_spec_applymodswhen it faulted writing into freed ChaCha state:This immediately cascaded: the
[D]=DIEtaint from the first oops caused follow-on GPFs inamdgpu(__mutex_lock,drm_sched_rq_update_fifo_locked) as other processes tried to use GPU resources on a now-corrupted kernel, ending with:Hard freeze, required power cycle.
Boot −2: different crash site — forced reboot while module stuck in partial init
This boot the tunnel hung during init at the
bypass.sh/ whitelist step (Error: Whitelist file not found). Attempting to ^C out of it leftsudoitself hung dead. A normal reboot was triggered via the GUI — systemd then attempted to tear downawg-quick@wg0.service(still in a partially-initialized, hung state) during shutdown. Two page faults fired during that teardown:Fault 1 — null/low-address deref during
fishprocess exit (mod_node_page_state):Fault 2 — deferred vfree writing to an invalid PFN:
Then
Fixing recursive fault but reboot is needed!. Again required power cycle.The call traces don't name amneziawg directly, but the module is loaded (kernel tainted
[O]=OOT_MODULE [E]=UNSIGNED_MODULE) and the crashes fire during systemd's forced teardown of the hung service. The corrupted PFN in fault 2 (fffff59d00000034) suggests a bogus page struct pointer (possibly a buffer whose backing pages were already returned mid-init) consistent with the same class of lifecycle bug.Neither incident involved a clean
awg-quick down: one was a forced reboot with the module stuck mid-init, one was an active tunnel that spontaneously oopsed during handshake. I think the bug surface is wider than just teardown of a fully-established tunnel.log-boot-minus1.txt
log-boot-minus2.txt
@JoshuaJakowlew commented on GitHub (Jun 1, 2026):
Faced the same problem on Arch Linux with
7.0.10-arch1-1kernel. System randomly freeze with active wag interface. Looks like freeze may happen at any time - in some minutes, or in 10-20 hours, regardless of traffic amount.Here is relevant part of client config: