From cleech at redhat.com Mon Apr 6 18:27:07 2026 From: cleech at redhat.com (Chris Leech) Date: Mon, 6 Apr 2026 11:27:07 -0700 Subject: Kernel ML-KEM implementation plans In-Reply-To: <20260331001358.GA5190@sol> References: <5F9ACD7A-F3B8-463A-A00E-28F68819A66C@gmail.com> <20260331001358.GA5190@sol> Message-ID: <20260406-e1d94afb79556186f06749f4@redhat.com> On Mon, Mar 30, 2026 at 05:13:58PM -0700, Eric Biggers wrote: > On Mon, Mar 30, 2026 at 06:41:46PM -0500, Ryan Appel wrote: > > Hello all, > > > > Looking through the mail archives I see no information on an > > implementation of ML-KEM that has been planned, except for leancrypto > > attempting to make a Key-Agreement Scheme a Key-Encapsulation > > Mechanism. > > > > Is there a plan to implement a KEM interface at this point? Is this > > something that needs support? How could someone contribute to this? > > We don't add new algorithms preemptively, but rather only when an > in-kernel user comes along. Otherwise there's a risk that the code will > never be used. > > Do you have a specific in-kernel user in mind? I haven't actually heard > anyone specifically say they need ML-KEM in the kernel yet. > > I guess the obvious use case would be WireGuard. But that would require > a new WireGuard protocol version that replaces X25519 with something > like X25519MLKEM768. It's going to be up to the WireGuard author > (Jason) to decide whether that's in the roadmap for WireGuard. > > Also maybe Bluetooth, though it seems the spec for that is yet to be > defined? > > Anyway, point is, before it makes sense to consider possible > implementation strategies, there needs to be a plan to actually use it. The NVMe fabrics authentication protocol will need a PQC replacement for it's FFDHE use. There is not a specification update for that yet. - Chris From mail at aparcar.org Thu Apr 9 14:31:55 2026 From: mail at aparcar.org (Paul Spooren) Date: Thu, 9 Apr 2026 23:31:55 +0900 Subject: Adding message type 5/6 for PQC (was Re: Export noise primitives for additional "chain key ratcheting") In-Reply-To: <9E8ACE91-126B-41BD-BCE2-8B54DCE78B97@aparcar.org> References: <9E8ACE91-126B-41BD-BCE2-8B54DCE78B97@aparcar.org> Message-ID: Hello again, To follow up my previous email, I gave it a bit more thoughts. Two new messages types now strike me as an easier migration path. I wrote the design and mangled it through an AI for readability. I?d be interested if other people have similar ideas or pursue entirely different approaches for PQC. Heads up, dealing with such big keys (~500kb) breaks this nice and clean WireGuard feel. However, to stay compatible with existing scripts, the design outlined below still allows addressing peers with their ?classical? public key, while peer setup requires the full path. Anyway, for those who care: ## Motivation A sufficiently powerful quantum computer running Shor's algorithm can break Curve25519 ECDH, allowing an attacker to: - Decrypt recorded WireGuard handshakes ("harvest now, decrypt later") - Recover static keys from captured initiations and impersonate peers WireGuard's Noise IK handshake could be augmented with post-quantum key exchange to protect against this threat while retaining full backward compatibility with existing deployments. ## Approach We add two new message types (5 and 6) that extend the existing Noise IKpsk2 handshake with a hybrid post-quantum layer. The classical Noise IK steps run first, unchanged, followed by two additional KEM operations that mix post-quantum shared secrets into the session key. The design is hybrid: even if the PQC algorithms are broken, the classical X25519 security remains. The PQC layer can only add entropy, never weaken. ### Algorithm Choice - **Classic McEliece 460896** for static peer authentication. Code-based cryptography with 40+ years of cryptanalysis. Conservative choice for long-term identity keys. Decapsulation is fast (~40?s); the tradeoff is a large public key (~524 KB). - **ML-KEM-512** (FIPS 203) for ephemeral forward secrecy. Lattice-based, NIST-standardized. Fresh keypair per handshake ensures that compromising static keys cannot decrypt past sessions. Compact: 800-byte public key, 768-byte ciphertext. ### Wire Format ``` Type 5 ? PQC Initiation (1104 bytes): [type:4][sender:4][ephemeral:32][enc_static:48][enc_timestamp:28] [mce_ciphertext:156][mlkem_encaps_key:800] [mac1:16][mac2:16] Type 6 ? PQC Response (1032 bytes): [type:4][sender:4][receiver:4][ephemeral:32][enc_nothing:16] [mce_ciphertext:156][mlkem_ciphertext:768][enc_empty:16] [mac1:16][mac2:16] ``` Backward compatible: existing WireGuard implementations silently drop unknown message types. Classical peers continue using types 1-4 without modification. ### Protocol Flow **Type 5 creation (initiator):** Phase 1 ? classical Noise IK, identical to Type 1: 1. Generate ephemeral X25519 key, mix into chain 2. DH(ephemeral, responder_static) ? encrypt initiator's static key 3. DH(initiator_static, responder_static) ? encrypt timestamp Phase 2 ? post-quantum augmentation: 4. Domain separation: mix PQC construction string into chain key 5. McEliece encapsulate to responder's static McEliece key ? 156-byte ciphertext + 32-byte shared secret, mixed into chain key via KDF 6. ML-KEM keygen ? 800-byte encapsulation key sent in message, 1632-byte decapsulation key held in handshake state **Type 6 creation (responder):** Phase 1 ? classical response (e, ee, se, psk, {}), identical to Type 2. Phase 2 ? post-quantum augmentation: 4. McEliece encapsulate to initiator's static McEliece key ? shared secret mixed into chain key 5. ML-KEM encapsulate using initiator's ephemeral encapsulation key ? shared secret mixed into chain key 6. Encrypt empty payload for transcript authentication Both sides derive identical session keys from the combined classical + PQC chain key, then proceed with the normal WireGuard transport. ### PQC-Aware MAC1 For Type 5/6, the mac1 key derivation includes the responder's McEliece public key hash: ``` pqc_mac1_key = BLAKE2s(classical_mac1_key || BLAKE2s(mce_pubkey)) ``` This tightens the DoS boundary: only peers who possess the responder's full PQC public key (~524 KB) can send valid Type 5 messages. Classical Type 1/2 mac1 is unchanged. ## Key Management ### No Separate PQC Private Key The McEliece keypair is derived deterministically from the existing WireGuard private key: ``` seed = BLAKE2s(wg_private_key || "wg-pqc-mceliece-seed") mce_sk, mce_pk = McEliece460896_KeyGen(seed) ``` One secret to protect. No additional key storage. Changing the WireGuard private key automatically rotates the PQC identity. ### Unified PublicKey Field There is no separate PQC configuration key. The standard `PublicKey` field handles both classical and PQC peers: - **44 base64 characters** (32 bytes decoded): classical Curve25519 key - **~700 KB base64** (524,192 bytes decoded): classical key + McEliece public key, concatenated Since McEliece public keys are too large for config file lines or netlink messages, if a PublicKey value starts with `/`, it is read from that file path: ```ini [Interface] PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk= [Peer] PublicKey = /etc/wireguard/peer1.pub AllowedIPs = 10.0.0.2/32 Endpoint = 203.0.113.1:51820 ``` A new `wg pqcpubkey` command generates the key file: ```sh wg genkey | tee /etc/wireguard/private | wg pqcpubkey > /etc/wireguard/peer1.pub ``` This reads a private key from stdin (same UX as `wg pubkey`) and outputs the combined base64 blob. ### PQC Enforcement When a peer is configured with a PQC public key, classical Type 1 initiations from that peer are silently rejected. There is no way to downgrade a PQC-configured peer to classical-only. No explicit toggle is needed ? the presence of the McEliece key implies PQC-only. ## What We Explicitly Do Not Do - No separate PQC configuration keys or toggles - No modification to the classical Noise IK protocol - No changes to the transport data path (Type 4) > On 1. Apr 2026, at 05:14, Paul Spooren wrote: > > Hi, > > I?m looking into hardening WireGuard against quantum computers, specifically how to extend the Noise-based handshake. > > A bit of background, while PSK injection with external daemons for forward secrecy, exists, that?s extra software running, exposing extra ports etc. Modifying a Rust/Go implementation is easier than the Kernel, but my background is running things on WiFi routers, so Kernel is preferred. That said, I?d like to extend the current WireGuard message format and attach PQC without exceeding the IPv6 MTU of 1280 bytes. In literature I don?t find definitive a PQC handshake standard, however combining ML-KEM512 for forward secrecy and McEliece460896 for static long-term keys does exist in practice[1] and fits into WireGuard init and response messages. Alternatively, sntrup653 could be used for forward secrecy without PQ authentication, similar to Signal's PQXDH[2]. Possibly new primitives/schemes are developed, with smaller public keys and ciphertexts. > > Just today I read an email about ML-KEM and the Kernel; none of these cryptographic primitives are (to my knowledge) part of the Linux Kernel, making a ?new? protocol version of WireGuard more difficult to implement and further out in the future. > > I wondered if WireGuard could export some of the noise primitives like mix_hash and mix_key to allow ?one way? (ratchet) modifications of the chaining key and ?append only" bytes to the outgoing packet (PQ pubkey, ciphertext). After appending bytes, WireGuard takes over again and calculates the MAC, proceeding as usual. The "ratcheting? Kernel module would work similar to the existing PSK approach, it adds additional data to the chaining key, however it can?t downgrade it (except crashing the Kernel). Another approach could be to add netlink handling for an active daemon, this would at least reduce the open ports and network complexity. > > Yet another way to have PQ WireGuard could be to produce one's own modules like WolfGuard did the recently[3] with AES/FIPS, however I thought to ask anyway. > > Thanks, > Paul > > [1]: https://rosenpass.eu/docs/rosenpass-project/whitepaper/ > [2]: https://signal.org/docs/specifications/pqxdh/ > [3]: https://github.com/wolfSSL/wolfGuard From Jason at zx2c4.com Fri Apr 10 14:20:51 2026 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Fri, 10 Apr 2026 16:20:51 +0200 Subject: [ANNOUNCE] WireGuardNT v0.11 and WireGuard for Windows v0.6 Released Message-ID: Hey folks, I generally don't send announcement emails for the Windows software, because the built-in updater takes care of notifying the relevant users. But because this hasn't been updated in so long, and because of recent news articles, I thought it'd be a good idea to notify the list. After a lot of hardwork, we've released an updated Windows client, both the low level kernel driver and api harness, called WireGuardNT, and the higher level management software, command line utilities, and UI, called WireGuard for Windows. There are some new features -- such as support for removing individual allowed IPs without dropping packets (as was added already to Linux and FreeBSD) and setting very low MTUs on IPv4 connections -- but the main improvement is lots of accumulated bug fixes, performance improvements, and above all, immense code streamlining due to ratcheting forward our minimum supported Windows version [1]. These projects are now built in a much more solid foundation, without having to maintain decades of compatibility hacks and alternative codepaths, and bizarre logic, and dynamic dispatching, and all manner of crust. There have also been large toolchain updates -- the EWDK version used for the driver, the Clang/LLVM/MingW version used for the userspace tooling, the Go version used for the main UI, the EV certificate and signing infrastructure -- which all together should amount to better performance and more modern code. But, as it's our first Windows release in a long while, please test and let me know how it goes. Hopefully there are no regressions, and we've tested this quite a bit -- including on Windows 10 1507 Build 10240, the most ancient Windows that we support which Microsoft does not anymore -- but you never know. So feel free to write me as needed. As always, the built-in updater should be prompting users to click the update button, which will check signatures and securely update the software. Alternatively, if you're installing for the first time or want to update immediately, our mini 80k fetcher will download and verify the latest version: - https://download.wireguard.com/windows-client/wireguard-installer.exe - https://www.wireguard.com/install/ And to learn more about each of these two Windows projects: - https://git.zx2c4.com/wireguard-windows/about/ - https://git.zx2c4.com/wireguard-nt/about/ Finally, I should comment on the aforementioned news articles. When we tried to submit the new NT kernel driver to Microsoft for signing, they had suspended our account, as I wrote about first in a random comment [2] on Hacker News in a thread about this happening to another project, and then later that day on Twitter [3]. The comments that followed were a bit off the rails. There's no conspiracy here from Microsoft. But the Internet discussion wound up catching the attention of Microsoft, and a day later, the account was unblocked, and all was well. I think this is just a case of bureaucratic processes getting a bit out of hand, which Microsoft was able to easily remedy. I don't think there's been any malice or conspiracy or anything weird. I think most news articles currently circulating haven't been updated to show that this was actually fixed pretty quickly. So, in case you were wondering, "but how can there be a new WireGuard for Windows update when the account is blocked?!", now you know that the answer is, "because the account was unblocked." Anyway, enjoy the new software, and let me know how it works for you. Thanks, Jason [1] https://lists.zx2c4.com/pipermail/wireguard/2026-March/009541.html [2] https://news.ycombinator.com/item?id=47687884 [3] https://x.com/EdgeSecurity/status/2041872931576299888 From Jason at zx2c4.com Fri Apr 10 21:42:02 2026 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Fri, 10 Apr 2026 23:42:02 +0200 Subject: [ANNOUNCE] WireGuardNT v0.11 and WireGuard for Windows v0.6 Released In-Reply-To: References: Message-ID: If you're a tiny percentage of users running older builds of Windows 10 and are seeing in your logs, "[MGR] Update checker: The parameter is incorrect." in WireGuard for Windows v0.6, you'll need to run the fetcher to get back on track. Download and run https://download.wireguard.com/windows-client/wireguard-installer.exe and you should be all set (and will get v0.6.1 installed). If you're not seeing that in your logs, you don't need to do anything. Sorry about this! Growing pains. Jason From leon at darkk.net.ru Fri Apr 10 16:28:00 2026 From: leon at darkk.net.ru (Leonid Evdokimov) Date: Fri, 10 Apr 2026 19:28:00 +0300 Subject: WireGuard obfuscation & active probing: staying virtuous under pressure Message-ID: Hi list, I want to share an experiment on active probing of WireGuard. Observation: a relatively small burst of replayed handshake packets can reliably force WireGuard into "Under Load" mode for ~1 second. During this period, WireGuard responds to all handshake attempts (including replays) with Cookie messages. Summary ======= This does not break WireGuard itself, but it appears to affect most WireGuard-specific obfuscation layers I've looked at (xt_wgobfs, evrim-patch, swgp-go, ClusterM/wg-obfuscator, AmneziaWG, Mullvad's LWO, gutd). This distinguisher does not give censors absolute confidence. However, Frolov, Wampler and Wustrow have demonstrated a conceptually similar timeout-based distinguisher for TCP-based Probe-resistant Proxies at NDSS'20. This jar of Cookies seems to be in good company. Active probing is a well-known and realistic threat for an obfuscated protocol. E.g. Russia used it against Telegram proxies back in 2018 and still uses it in 2026. Same story with China and Shadowsocks. Iran? You name it. I'm describing the attack, exploring possible mitigations for in-tree and out-of-tree obfuscators, propose an alternative DoS mitigation based on TOTP-like identity, and speculate about some ideas to make WireGuard implementations more obfuscation-friendly. The rest of the letter may take ?20 minutes to read. I'm sorry for it being that wordy yet I hope I've managed to structure it in a readable way. I don't consider the mitigation complete and would appreciate feedback on its feasibility and alternatives. Set and setting =============== A common design for WireGuard obfuscation is to run a fully encrypted protocol on top of WireGuard, optionally with additional disguise. This aligns with the "turn the stream into noise" approach Jason mentioned in the "Let's talk about obfuscation again" thread at https://lists.zx2c4.com/pipermail/wireguard/2018-September/003295.html Such obfuscators typically rely on a long-term obfuscation key (OBFSK), exchanged out of band and used for symmetric encryption (weaker constructions are used as well). In practice, OBFSK is often shared across a clique of peers, partly because Cookie messages are sent before peer identity is known. The obfuscated WireGuard fights two distinct attackers with different goals & capabilities: "Censor": observes traffic and can replay it, but does not know OBFSK. Censor wants to reveal an obfuscated WireGuard endpoint. "DoSer": may know OBFSK and responder.static_public, and may be a legitimate peer capable of generating arbitrary handshake initiations. DoSer is a malicious competitor and/or user wanting to disrupt service. Encryption of cleartext, authentication of padding and shaping noise into a stream of plausible packets is out of scope of this letter. This Cookie jar already gets too big on its own. Cookies as distinguisher ======================== An active prober can replay captured handshake packets to force WireGuard to talk, triggering ?Under Load? mode. Once triggered, WireGuard replies with Cookie messages to any handshake with valid mac1, including replays(!). Two properties make this useful as a distinguisher: - the transition is easy to trigger with a short burst - the "Under Load" state persists for ~1 second (Go and Linux) I have not rigorously compared this behavior against other UDP services under similar load, but I assume it is sufficiently distinctive. WireGuard-Go starts sending Cookies after ~128 queued handshakes (1/8 of default queue size 1024), Linux kernel implementation uses a queue of 4096, so the threshold is ~512. One way to trigger "Under Load" is to send a paced "train" of handshakes with a low interpacket gap. It works surprisingly well both in LAN and over the Internet. The numbers I got are summarized in the table below. WireGuard under test | Train | Train rate | Steady rate | RTT -----------------------+-------+------------------+ ------------+------- Core i7-6600U x2, Go | 200 | 35k pps, 59 Mbit | 12,000 pps | LAN MikroTik RB951G-2HnD | 750 | 35k pps, 59 Mbit | 640 pps | LAN Celeron J1900, FreeBSD | 550 | 50k pps, 84 Mbit | ? | 3 ms UpCloud VM, EPYC 7543 | 700 | 50k pps, 84 Mbit | ? | 14 ms Amnezia-1.5, kmod-awg | 2000 | 50k pps, 84 Mbit | ? | 47 ms Experiment details ================== Celeron machine was located in the same city as the load generator (Russia, St.Petersburg), but within a different ISP. UpCloud VM was in a nearby country (Sweden). AmneziaWG box was "far away" in Western Europe. The train speed is expressed with packet rate instead of interpacket gap as that's what MikroTik Traffic Generator sets. RB3011UiAS-RM was used as a load generator for the experiments. Some installations might need other tools as RouterOS limits /tool/traffic-generator header length to 256 bytes. E.g., AmneziaWG adding more than 66 bytes of padding can't be tested with it. Unfortunately, pktgen in mainline Linux had some issues with custom payloads, that's why RouterOS was used. While 2000 packets might sound like a lot, it's just 350 KiB of traffic. It's an unnoticeable volume of traffic for a VPN hub and/or "exit node". It is an inexpensive amount of traffic for a modern active prober. It's in the same ballpark as The Guardian index page (gziped) being 150 KiB, as measured without additional css/js/img assets. More boring way to fill the queue is to saturate the worker thread doing handshake processing. Running Device.ConsumeMessageInitiation takes 0.13 ms on Intel Core i7-6600U. Thus, this CPU is expected to handle at most ~7700 pps of handshakes per core. That correlates well with the numbers above. Mitigation challenges ===================== Mitigating active probing at the obfuscation layer is possible, but significantly harder out-of-tree than in-tree: - The obfuscator needs to preserve SrcIP for WireGuard's rate limiting. - Forwarding Cookies preserves DoS protection but exposes a probing signal. - Dropping Cookies removes the distinguisher but breaks legitimate handshakes under load (clients cannot compute mac2). - Peer identity is not available before WireGuard processes the packet. Handling Cookies in the obfuscator requires: - tracking mac1 - decrypting per-IP Cookies - maintaining per-endpoint state to update mac2 Details below. Lacking SrcIP preservation collapses all traffic to an external IP of the obfuscator, typically 127.0.0.1. Number of handshakes with valid mac2 is rate-limited to 20pps Under Load. Thus, DoSer scheduling a handshake "train" every 1s gets DoS for all users. It's possible to limit the number of in-flight handshake_initiation packets between obfuscation and WireGuard layers to avoid Cookie response being triggered. It's a poor-man mitigation: it protects against burst-based probing, but the undersized queue does not protect from DoS. More on that below. Naive drop of Cookies at the obfuscation layer opens WireGuard layer to the following DoS attack: as soon as Under Load condition is triggered, WireGuard layer would demand mac2 and all(!) the clients will be unable to progress with handshake till Under Load is gone as they can't compute mac2. Go and Linux versions stay in Under Load state for one second. Fighting "censor" alone is relatively easy. E.g. add coarse UTC timestamps, limit handshake validity to ?30 seconds, keep some fixed-size replay filter (e.g. a Bloom filter of a size depending on a number of configured peers), and that should be enough. DoSer is a different beast. I suggest using temporary Peer Identity to fight DoSer in absence of Cookies. TOTP-based DoS mitigation ========================= Adding clocked Peer ID (ClkID) to an obfuscation-layer envelope effectively introduces a temporary, TOTP-like, pre-DH identifier. It trades some of WireGuard's identity-hiding properties for earlier filtering. Responder being Under Load may use ClkID for quick drop of invalid ClkIDs and as a rate-limit key instead of (isMac2Valid, SrcIP) condition. ClkID might be HASH(LABEL_CLKID || Epoch || initiator.static_public || responder.static_public || p2p.PSK) Epoch might be int(UTC.Seconds / 120); 120 comes from RekeyAfterTime and Cookie lifetime. It's worth investigating if 128 saves a measurable amount of CPU cycles: cloudflare/boringtun Cookie emitter assumes it's worth it. Am I right that ClkID does not worsen Identity-hiding properties if we factor UDP metadata in? ClkID is essentially a one-time ID under normal conditions and it's only reused for retries within a 2min interval. The latter implies that ClkID has to be encrypted by an obfuscator, but that's out of scope of this writeup. ClkID opens the possibility for a powerful attacker mounting targeted DoS against a specific user via rate-limiting at the obfuscation layer. That needs knowledge of semi-public receiver.OBFSK paired with capability to observe obfuscated traffic. DoSer knows OBFSK but can't listen traffic, and censor does not know OBFSK otherwise the obfuscation game is already lost. ClkID demands PSK to be unique for each pair of connected WireGuard interfaces to avoid DoS through impersonation within the clique of peers. That's one common setup, but default WireGuard also has PSK=0^256. I've observed one large deployment reusing non-zero PSKs across a clique of users. Initiator's and Responder.static_public are mixed into ClkID to make deployment of these kind "working", but "insecure" against malicious clique members. "Working" as in "not suffering from an extra rate-limit imposed by shooting themselves in the foot". Lack of that mixin will lead to violation of principle of least astonishment as adding few more peers to such a deployment may lead to unexpected handshake drops within the mesh. The price responder pays to support ClkID-based dispatch is computation of Blake2s-256 for each configured peer every two minutes. That's ?300ms spent every 2min for (1 << 20) peers on a Skylake Intel Core i7-6600U. It's close to 0.25% of a single CPU core time, it does not sound prohibitive for an obfuscated protocol. That still has few open problems: thundering herd; CPU usage penalty for an completely idle interface; CPU usage penalty for an interface with low number of active peers & high number of peers configured. I would appreciate feedback whether the proposed ClkID approach is a reasonable direction, or if there are simpler alternatives I am missing. WireGuard & identity ==================== Identity-hiding property of the WireGuard handshake makes it non-trivial to rate-limit based on the initiator's identity as the identity is unsealed only after DH and that's exactly the CPU-consuming operation. However, identity-hiding is not absolute in WireGuard: E.g. observer knowing responder.static_public may passively confirm the expected identity of a responder using mac1. They still have to see the flow in both directions to use response as a confirmation (not "proof"). But that's exactly how TSPU is to be deployed (TSPU is Russian tsar-in-the-middle filtering equipment) and that's how jabber.ru XMPP traffic was intercepted. Assuming that censor is a bi-directional observer sounds plausible to me for the purpose of threat modeling. E.g. observer with responder.static_private key seized may decrypt initiator.static_public. E.g. observer may use receiver_index to keep track of user's network location when the user is roaming from one IP to another. So, if I understand WireGuard's identity-hiding correctly, the main goal is to make two user's sessions non-linkable if the user is silent(!) for an extended period of time AND connection metadata does not allow for session linkage: e.g. user roams to another IP AND rotates listen-port. IIUC, this extended period is ?3min of silence, as RejectAfterTime states. One may say that obfuscation slightly improves privacy of WireGuard as it encrypts the WireGuard header. Now, as a client moves between networks, a passive observer of both network paths will need OBFSK to determine the fact that old and new IP addresses belong to the same system using the unencrypted receiver_index of the packets. However, listen-port on both sides often stays the same while one of the peers is roaming, so anonymity set is still "all the users of the Endpoint roaming at the same time". NTP Client Data Minimization draft mentions similar problem at https://datatracker.ietf.org/doc/html/draft-ietf-ntp-data-minimization-04#section-4.1 ClkID alternatives ================== SrcIP is a bad key for rate-limiting as IP ownership verification becomes unreliable without Cookies. Established sessions might have their SrcIP verified, but new ones are not. Roaming with session being active transfers the ownership to the new IP, but roaming to the new IP after two minutes of silence keeps SrcPort at most. Active Queue Management combined with Proof-of-Work schemes like hashcash is another way to make an attack more costly to DoSer, but they come with their own drawbacks. First, PoW penalises the legitimate user as well, especially under bad network weather as we lose ability to distinguish handshake timeout due to natural packet loss from the need to mint more zeroes & work harder. Second, designing PoW schemes in the era of ASIC miners might be tricky. E.g. Antminer KA3-166T mining Blake2s-256 produces 52,000 MH/W, GPU AMD RX 6650 XT does 70 MH/W while Intel Core i7-6600U CPU does just 1 MH/W. ClkID performance ================= When the responder is completely idle, it may put ClkID check after DH and avoid spending time on regular re-computation of ClkIDs for all configured peers. When the responder is active and transits to Under Load it gets tricky. On one hand, it will already take 17ms to do DH for these 128 handshakes. On another hand, these 17ms may be rather spent computing ?44,000 ClkIDs given the fact that Blake2s-256 takes ~340 less time than DH. What's worse, the censor might try to use RTT as a signal to distinguish VPN doing NAT from full-mesh Tailscale-like end-to-end VPN and RTT bias "Under Load". It's unclear to me if it's possible to have a unified ClkID behavior suitable both for a smallish interface with 256 peers and for WireGuardMaxxer with (1<<20) peers. I don't know the quasi-optimal way to go. One might be to have several "escalation" steps. Here are some back of the napkin calculations: First one is being idle & doing nothing. Being idle is good both for battery consumption and overall mental health. Second one is an active interface with a TINY number of peers, e.g. ?100 peers. 100 comes from Blake2s-256 being 340 times more computationally expensive than one DH exchange and need to compute ?one Epoch. This interface can compute ClkID in the Handshake thread and be just fine. Third one is an active interface with OKAY number of peers, e.g. under ?2'500. These interfaces have latency penalty less than 1ms for computing the full ClkID table as the interface transitions to "Under Load" state. OKAY value is not necessary a compile-time constant, it might also be a runtime estimate to keep latency under 1ms depending on something like LoadAverage value. Fourth one is an active interface with a HUGE number of peers, something between OKAY and MAX_PEERS_PER_DEVICE. These interfaces can't afford to spend a few hundred milliseconds to process the next handshake while transitioning to Under Load state, so they should refresh ClkID tables in the background. OBFSK scoping ============= Handling Cookie messages at the obfuscator layer and dropping Cookie messages from the on-the-wire part of the obfuscated protocol opens a possibility to bind OBFSK to a listening port on ingress and to an endpoint on egress instead of having the same key shared among the whole clique. Scoped OBFSK brings little value to typical setups. Peers in full-mesh already know all OBFSK keys. All peers in hub-and-spoke share OBFSK for the hub. However, scoped OBFSK aligns well with WireGuard agility allowing other topologies. Obfuscator handling Cookies on its own might set OBFSK to some F(peer), e.g. defaulting to HASH(LABEL_OBFS || peer.static_public). However, an out-of-tree obfuscator has to recover peer identity from mac1 (or receiver_index), which is not directly available after packet emission. This leads to cache-based or computationally expensive lookup methods doing trial hashing over all known peers. Both methods are also prone to ToC/ToU races. DoS with undersized queue ========================= First, it's tricky to make a robust estimator of in-flight handshakes count. The obfuscator gets a handshake_response if the handshake_initiation was handled, but it's challenging to distinguish "handshake not yet handled" from "handshake dropped" cases. The handshakes are not guaranteed to be handled in FIFO order, e.g. WireGuard-Go starts a per-CPU RoutineHandshake worker. Overestimating the number of in-flight handshakes lowers handshake throughput available for "good" users. The DoSer knowing responder.static_public might craft 512 different handshakes with out-of-date encrypted_timestamp, send them and force the obfuscator on the responder side into a hard choice. When should it be ready to relay the next handshake of the legitimate user to the WireGuard layer given the complete silence? Underestimating the number of in-flight handshakes and putting WireGuard backend Under Load leaves the obfuscator with a choice between plain DoS and computational DoS. Plain DoS may come from cookies being dropped by obfuscator and legitimate users being unable to do handshakes for 1s. Computational DoS comes from cookies being decrypted & used without any IP validation. If I do math correctly, sustaining a computational DoS against a somewhat modern CPU still needs ~10 Mbit/s of handshakes per attacked core. That's not a lot, but disabling the Cookie-based protection in such a convoluted way does not sound too bad for certain setups. Although, it's still suboptimal for a deployment of a scale of a sizable VPN service provider. WireGuard over Shadowsocks-2022 =============================== TL;DR: Too much crypto + deployment challenges. Shadowsocks is a good solution against censor, but it strips 40 more bytes from MTU and AEADs data twice: XChaCha20-Poly1305 of Shadowsocks + ChaCha20-Poly1305 of WireGuard burning twice as much carbon credits. Performance matters: e.g. Mullvad introduces LWO claiming performance improvement over Shadowsocks. WireGuard over Shadowsocks might drop SrcIP. This allows DoSer talking to WireGuard through Shadowsocks to trigger rate-limiting of 127.0.0.1 (or other "external" IP address of the Shadowsocks daemon). Common recipes on the web do nothing special about this threat. I expect WireGuard-Go and Linux kernel implementations to drop handshakes exceeding the 20pps limit and DoS legitimate users if Under Load is triggered. Other implementations behave differently, more below. IIUC, Shadowsocks deployments typically assume trusted PSK holders and that's a weaker assumption than WireGuard's threat model. WireGuard assumes peer being potentially malicious (e.g. limited to 50 INITIATIONS_PER_SECOND) and responder.static_public being known to an attacker (attacker gets Cookies & juices at most 20 PACKETS_PER_SECOND out of a single SrcIP they control). The only major installation of Shadowsocks+WireGuard I know is Mullvad. I assume, Mullvad uses Rust gotatun implementation, so I've chosen not to explore DoS-ability of it in-the-wild as gotatun takes a non-mainline approach to anti-DoS Cookies. Iron-rich Cookies recipes ========================= Two Rust implementations behave differently regarding the Cookies compared to WireGuard-Go and Linux kernel. mullvad/gotatun checks Under Load condition on per-SrcIP basis, not with per-device queue waterline like Linux & Go do. It makes sense given that the development is led by Mullvad: the goal might be to avoid "leaking" "Under Load" state to the network. It makes gotatun vulnerable to SrcIP spoofing, however the vulnerability is unlikely exploitable for DoS purposes: it's just a per-IP slot allocation in a HashMap that is .clear()'ed every second without doing memory reallocation. The only vector I see here is OOM through spoofing. Saturating 10 Gbit/s interface with handshakes will probably lead just to ~1?2GiB of HashMap being allocated. So, it's an unrealistic OOM trigger. cloudflare/boringtun does completely different things. It flips global "Under Load" flag after 10 handshakes within a second, and I don't see post-mac2 per-IP rate limiter at all. I feel like both gotatun and boringtun may warrant further analysis regarding their CPU DoS resistance in certain setups given the different way to handle Under Load conditions. Sidenotes ========= Sidenote #1: WireGuard Go ratelimiter.Allow() should probably follow Linux kernel WireGuard implementation and use IPv6 as /64 subnet. Sidenote #2: WireGuard web page on DoS mitigation seems to be out of date, https://www.wireguard.com/protocol/#dos-mitigation says: > In order for the server to remain silent unless it receives a valid > packet, while under load, all messages are required to have a MAC that > combines the receiver's public key and optionally the PSK as the MAC > key. IIUC, PSK is not currently used for DoS-related mac1/mac2, it's mixed into KDF for handshake_response.encrypted_nothing and SymmetricSession. Am I getting it wrong? What's for WireGuard? ===================== I have not built a full PoC yet, so these ideas are exploratory. Still, I'd like to discuss a few changes that could make WireGuard easier to integrate with obfuscation layers, without changing its core. 1) Optional per-device Send-Cookie toggle Allowing WireGuard to disable the built-in Cookie sender on a per-device basis would let an obfuscation layer take full responsibility for DoS protection. This avoids forcing out-of-tree obfuscators to choose between: - interpreting Cookie messages, or - leaking a distinguisher, or - breaking handshakes under load. This would be conceptually similar to net.ipv4.tcp_syncookies allowing delegating DoS tradeoffs to the operator. 2) Optional exposure of a receiver identifier Obfuscators currently lack access to peer identity, which makes per-peer configuration and rate limiting difficult without trial hashing over all peers. An optional mechanism to expose a receiver-side identifier in outgoing packets (e.g., HASH(static_public) or ClkID conveyed via the mac2 field) could allow obfuscators to integrate with WireGuard's identity model without modifying handshake semantics. Question: Would changes of this scope be acceptable for the reference implementation, or is this better kept entirely out-of-tree? Would it make sense to develop a more detailed proposal? Acknowledgements ================ I'd like to thank Danil Bezborodov (@ShaTie), Egor Koleda (@radioegor146) and Dmitry Nourell (hey at flo.boo) for valuable suggestions and corrections. I'm also thankful to Schei?e und Pisse Stiftung for donations supporting the work on this idea, to Amnezia VPN led by Mazay Banzaev for real-word data on WireGuard usage, to B4CKSP4CE hackerspace for equipment used for benchmarks. And for the "WireGuard itself is derived from an exfiltration mechanism of mine" as Jason Donenfeld told at https://lists.zx2c4.com/pipermail/wireguard/2018-September/003295.html for providing an excellent and well-thought protocol to build upon. -- WBRBW, Leonid Evdokimov, https://darkk.net.ru tel:+79816800702 PGP: 6691 DE6B 4CCD C1C1 76A0 0D4A E1F2 A980 7F50 FAB2 From syzbot at syzkaller.appspotmail.com Mon Apr 13 15:01:12 2026 From: syzbot at syzkaller.appspotmail.com (syzbot) Date: Mon, 13 Apr 2026 08:01:12 -0700 Subject: [PATCH] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit In-Reply-To: <20260413150024.1003490-1-shardul.b@mpiricsoftware.com> Message-ID: <69dd0538.a00a0220.468cb.0049.GAE@google.com> > wg_netns_pre_exit() manually acquires rtnl_lock() inside the > pernet .pre_exit callback. This causes a hung task when another > thread holds rtnl_mutex - the cleanup_net workqueue (or the > setup_net failure rollback path) blocks indefinitely in > wg_netns_pre_exit() waiting to acquire the lock. > > Convert to .exit_rtnl, introduced in commit 7a60d91c690b ("net: > Add ->exit_rtnl() hook to struct pernet_operations."), where the > framework already holds RTNL and batches all callbacks under a > single rtnl_lock()/rtnl_unlock() pair, eliminating the contention > window. > > The rcu_assign_pointer(wg->creating_net, NULL) is safe to move > from .pre_exit to .exit_rtnl (which runs after synchronize_rcu()) > because all RCU readers of creating_net either use maybe_get_net() > - which returns NULL for a dying namespace with zero refcount - or > access net->user_ns which remains valid throughout the entire > ops_undo_list sequence. > > Reported-by: syzbot+pFBD3bslSSshiJCd3rxy at syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?id=cb64c22a492202ca929e18262fdb8cb89e635c70 > Signed-off-by: Shardul Bankar > --- > drivers/net/wireguard/device.c | 6 ++---- > 1 file changed, 2 insertions(+), 4 deletions(-) > > diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c > index 46a71ec36af8..eb854c5294a3 100644 > --- a/drivers/net/wireguard/device.c > +++ b/drivers/net/wireguard/device.c > @@ -411,12 +411,11 @@ static struct rtnl_link_ops link_ops __read_mostly = { > .newlink = wg_newlink, > }; > > -static void wg_netns_pre_exit(struct net *net) > +static void wg_netns_exit_rtnl(struct net *net, struct list_head *dev_kill_list) > { > struct wg_device *wg; > struct wg_peer *peer; > > - rtnl_lock(); > list_for_each_entry(wg, &device_list, device_list) { > if (rcu_access_pointer(wg->creating_net) == net) { > pr_debug("%s: Creating namespace exiting\n", wg->dev->name); > @@ -429,11 +428,10 @@ static void wg_netns_pre_exit(struct net *net) > mutex_unlock(&wg->device_update_lock); > } > } > - rtnl_unlock(); > } > > static struct pernet_operations pernet_ops = { > - .pre_exit = wg_netns_pre_exit > + .exit_rtnl = wg_netns_exit_rtnl > }; > > int __init wg_device_init(void) > -- > 2.34.1 > I see the command but can't find the corresponding bug. The email is sent to syzbot+HASH at syzkaller.appspotmail.com address but the HASH does not correspond to any known bug. Please double check the address. From ryan.appel.333 at gmail.com Thu Apr 2 17:08:17 2026 From: ryan.appel.333 at gmail.com (Ryan Appel) Date: Thu, 2 Apr 2026 12:08:17 -0500 Subject: Kernel ML-KEM implementation plans In-Reply-To: <20260331011133.GB5190@sol> References: <20260331001358.GA5190@sol> <7507DE2E-1507-4D03-B6EF-9C139BBF34F8@gmail.com> <20260331011133.GB5190@sol> Message-ID: <8721F1CE-0E84-4A2B-816F-0A4485BA808E@gmail.com> Another potential and likely use case is Wi-Fi. WPA3 supports both SAE-PK (which currently uses ECDSA-P256 and will likely migrate to ML-DSA or other, And WPA3 enterprise supports EAP, which uses the IKE Diffie-Hellman groups, which already have added support for (pending finalization) ML-KEM groups. Of course the spec will have to be updated, but it?s highly likely that at least ML-KEM-512 will be supported. The actual use of the algorithm is as simple as calling it instead of ECDH, but in theory, we typically care very much about the difference between key agreement and key exchange. The major difference on a code front is that with ECDH, you input a public and private key, and get out a shared key. But with ML-KEM, you input a public key, and get out a shared key, and a cipher text. Or you input a private key and a cipher text and get out the same shared key. (Encapsulation -> one input, two outputs) (Decapsulation -> two inputs, one output) I understand that there is a chicken and egg scenario where there?s need to wait for the need before developing, but something at least to consider for the roadmap. > On Mar 30, 2026, at 8:11?PM, Eric Biggers wrote: > > On Mon, Mar 30, 2026 at 07:44:55PM -0500, Ryan Appel wrote: >> WireGuard was my big implementation user. > > Any more details on this? Googling for research papers shows that there > have indeed been several proposals for quantum-resistant WireGuard. But > some use algorithms other than ML-KEM. Others don't modify the kernel > code but rather do the key establishment in userspace. I haven't looked > into the details, but it also sounds like it's not as simple as swapping > out the algorithm, either. > > I think step 1 is work out some plan with the WireGuard folks. Which > may or may not turn out to involve in-kernel ML-KEM. > >> I also know that VMware uses the kernel crypto space for many of its >> crypto operations. I do not know when they will want ML-KEM and if >> they will want it only within BoringCrypto or OpenSSL, but if there is >> need for it in the market before it can be developed then that makes >> sense. > > That code isn't upstream though, right? So even if hypothetically they > (will?) need ML-KEM in the kernel (for what?), that doesn't count for > upstream purposes. > > - Eric From shardul.b at mpiricsoftware.com Mon Apr 13 15:00:24 2026 From: shardul.b at mpiricsoftware.com (Shardul Bankar) Date: Mon, 13 Apr 2026 20:30:24 +0530 Subject: [PATCH] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit Message-ID: <20260413150024.1003490-1-shardul.b@mpiricsoftware.com> wg_netns_pre_exit() manually acquires rtnl_lock() inside the pernet .pre_exit callback. This causes a hung task when another thread holds rtnl_mutex - the cleanup_net workqueue (or the setup_net failure rollback path) blocks indefinitely in wg_netns_pre_exit() waiting to acquire the lock. Convert to .exit_rtnl, introduced in commit 7a60d91c690b ("net: Add ->exit_rtnl() hook to struct pernet_operations."), where the framework already holds RTNL and batches all callbacks under a single rtnl_lock()/rtnl_unlock() pair, eliminating the contention window. The rcu_assign_pointer(wg->creating_net, NULL) is safe to move from .pre_exit to .exit_rtnl (which runs after synchronize_rcu()) because all RCU readers of creating_net either use maybe_get_net() - which returns NULL for a dying namespace with zero refcount - or access net->user_ns which remains valid throughout the entire ops_undo_list sequence. Reported-by: syzbot+pFBD3bslSSshiJCd3rxy at syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?id=cb64c22a492202ca929e18262fdb8cb89e635c70 Signed-off-by: Shardul Bankar --- drivers/net/wireguard/device.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c index 46a71ec36af8..eb854c5294a3 100644 --- a/drivers/net/wireguard/device.c +++ b/drivers/net/wireguard/device.c @@ -411,12 +411,11 @@ static struct rtnl_link_ops link_ops __read_mostly = { .newlink = wg_newlink, }; -static void wg_netns_pre_exit(struct net *net) +static void wg_netns_exit_rtnl(struct net *net, struct list_head *dev_kill_list) { struct wg_device *wg; struct wg_peer *peer; - rtnl_lock(); list_for_each_entry(wg, &device_list, device_list) { if (rcu_access_pointer(wg->creating_net) == net) { pr_debug("%s: Creating namespace exiting\n", wg->dev->name); @@ -429,11 +428,10 @@ static void wg_netns_pre_exit(struct net *net) mutex_unlock(&wg->device_update_lock); } } - rtnl_unlock(); } static struct pernet_operations pernet_ops = { - .pre_exit = wg_netns_pre_exit + .exit_rtnl = wg_netns_exit_rtnl }; int __init wg_device_init(void) -- 2.34.1 From shardul.b at mpiricsoftware.com Mon Apr 13 15:12:32 2026 From: shardul.b at mpiricsoftware.com (Shardul Bankar) Date: Mon, 13 Apr 2026 20:42:32 +0530 Subject: [PATCH v2] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit Message-ID: <20260413151232.1004611-1-shardul.b@mpiricsoftware.com> wg_netns_pre_exit() manually acquires rtnl_lock() inside the pernet .pre_exit callback. This causes a hung task when another thread holds rtnl_mutex - the cleanup_net workqueue (or the setup_net failure rollback path) blocks indefinitely in wg_netns_pre_exit() waiting to acquire the lock. Convert to .exit_rtnl, introduced in commit 7a60d91c690b ("net: Add ->exit_rtnl() hook to struct pernet_operations."), where the framework already holds RTNL and batches all callbacks under a single rtnl_lock()/rtnl_unlock() pair, eliminating the contention window. The rcu_assign_pointer(wg->creating_net, NULL) is safe to move from .pre_exit to .exit_rtnl (which runs after synchronize_rcu()) because all RCU readers of creating_net either use maybe_get_net() - which returns NULL for a dying namespace with zero refcount - or access net->user_ns which remains valid throughout the entire ops_undo_list sequence. Reported-by: syzbot+f2fbf7478a35a94c8b7c at syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?id=cb64c22a492202ca929e18262fdb8cb89e635c70 Signed-off-by: Shardul Bankar --- v2: Fix incorrect Reported-by email address drivers/net/wireguard/device.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c index 46a71ec36af8..eb854c5294a3 100644 --- a/drivers/net/wireguard/device.c +++ b/drivers/net/wireguard/device.c @@ -411,12 +411,11 @@ static struct rtnl_link_ops link_ops __read_mostly = { .newlink = wg_newlink, }; -static void wg_netns_pre_exit(struct net *net) +static void wg_netns_exit_rtnl(struct net *net, struct list_head *dev_kill_list) { struct wg_device *wg; struct wg_peer *peer; - rtnl_lock(); list_for_each_entry(wg, &device_list, device_list) { if (rcu_access_pointer(wg->creating_net) == net) { pr_debug("%s: Creating namespace exiting\n", wg->dev->name); @@ -429,11 +428,10 @@ static void wg_netns_pre_exit(struct net *net) mutex_unlock(&wg->device_update_lock); } } - rtnl_unlock(); } static struct pernet_operations pernet_ops = { - .pre_exit = wg_netns_pre_exit + .exit_rtnl = wg_netns_exit_rtnl }; int __init wg_device_init(void) -- 2.34.1 From doug.hs at proton.me Mon Apr 13 21:41:11 2026 From: doug.hs at proton.me (Douglas Silva) Date: Mon, 13 Apr 2026 21:41:11 +0000 Subject: Android app: export configuration as a password-protected zip file In-Reply-To: <3uPzijiGmCFwzmGThO2Z2EhiLTEw1w-Jqx3eC5wTpEjGUfbAivno4-eIG9UV4Xqc9tUFSdKkobsWPYRBke-QuqkqGwylaPy4-ALihwtoe7Y=@proton.me> References: <3uPzijiGmCFwzmGThO2Z2EhiLTEw1w-Jqx3eC5wTpEjGUfbAivno4-eIG9UV4Xqc9tUFSdKkobsWPYRBke-QuqkqGwylaPy4-ALihwtoe7Y=@proton.me> Message-ID: <5OnExJASKzYVA1fiNjP_WBN5i5seMIJpGVOZrdCItPeaYKrmNr4Wist_6oHN8eYSDBM2JzSd7DooSQH4faJ4kt9ySoDMSZlmFRokIMPKJ04=@proton.me> An update: it seems that Seedvault can already backup this app's data, because it pretends to do a device-to-device transfer. [1] That's good enough for those running the likes of LineageOS, but I still think the password-protected zip would still be useful in case you don't like to use Auto Backup. [1] https://github.com/seedvault-app/seedvault/discussions/997#discussioncomment-16437606 On Saturday, August 9th, 2025 at 09:08, Douglas Silva wrote: > Greetings. > > This is a feature request for the Android app. I'd like to suggest two alternatives to address the issue of exporting an unencrypted zip-file containing all your private keys into the Downloads folder. > > 1. Export a password-protected zip-file instead, allowing us to choose a password in the app settings. This is what Syncthing does nowadays. > > 2. Optionally let Android Backup pick up our config (disabled by default). Google Drive isn't the only back-end available. Ever heard of Seedvault? It's the default on systems like LineageOS or CalyxOS. Seedvault does encrypted backups to any location; even offline, to a flash stick. Aegis Authenticator uses it, as long as the backup is advertised as encrypted. See [1], [2] and [3] and [4]. > > [1] https://developer.android.com/identity/data/autobackup#EnablingAutoBackup > [2] https://developer.android.com/identity/data/autobackup#define-device-conditions > [3] https://github.com/seedvault-app/seedvault/wiki/FAQ#why-do-some-apps-not-allow-to-get-backed-up > [4] https://github.com/beemdevelopment/Aegis/blob/master/app/src/main/AndroidManifest.xml#L22 > > > For option 1 (password-protected zip), I'd also like to suggest the addition of (optional) automatic exports to a chosen folder, to facilitate automatic backups with an external tool such as Syncthing. The messaging app Signal does something like this to export your messages (encrypted) and keep the last five versions of it. > > Thank you. From Jason at zx2c4.com Tue Apr 14 13:28:37 2026 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Tue, 14 Apr 2026 15:28:37 +0200 Subject: [PATCH v2] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit In-Reply-To: <20260413151232.1004611-1-shardul.b@mpiricsoftware.com> References: <20260413151232.1004611-1-shardul.b@mpiricsoftware.com> Message-ID: Hi Shardul, On Mon, Apr 13, 2026 at 5:13?PM Shardul Bankar wrote: > > wg_netns_pre_exit() manually acquires rtnl_lock() inside the > pernet .pre_exit callback. This causes a hung task when another > thread holds rtnl_mutex - the cleanup_net workqueue (or the > setup_net failure rollback path) blocks indefinitely in > wg_netns_pre_exit() waiting to acquire the lock. > > Convert to .exit_rtnl, introduced in commit 7a60d91c690b ("net: > Add ->exit_rtnl() hook to struct pernet_operations."), where the > framework already holds RTNL and batches all callbacks under a > single rtnl_lock()/rtnl_unlock() pair, eliminating the contention > window. > > The rcu_assign_pointer(wg->creating_net, NULL) is safe to move > from .pre_exit to .exit_rtnl (which runs after synchronize_rcu()) > because all RCU readers of creating_net either use maybe_get_net() > - which returns NULL for a dying namespace with zero refcount - or > access net->user_ns which remains valid throughout the entire > ops_undo_list sequence. > > Reported-by: syzbot+f2fbf7478a35a94c8b7c at syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?id=cb64c22a492202ca929e18262fdb8cb89e635c70 > Signed-off-by: Shardul Bankar Thanks. Applied to the wireguard tree, and also added the missing __net_exit and __read_mostly annotations in the process. Jason From kuba at kernel.org Tue Apr 14 15:18:24 2026 From: kuba at kernel.org (Jakub Kicinski) Date: Tue, 14 Apr 2026 08:18:24 -0700 Subject: [PATCH v2] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit In-Reply-To: References: <20260413151232.1004611-1-shardul.b@mpiricsoftware.com> Message-ID: <20260414081824.0edf6113@kernel.org> On Tue, 14 Apr 2026 15:28:37 +0200 Jason A. Donenfeld wrote: > Thanks. Applied to the wireguard tree, and also added the missing > __net_exit and __read_mostly annotations in the process. Hi Jason, while we have you - do you have a PR for us for wireguard? We're going to be sending the net-next PR later today.. From Jason at zx2c4.com Tue Apr 14 15:40:03 2026 From: Jason at zx2c4.com (Jason A. Donenfeld) Date: Tue, 14 Apr 2026 17:40:03 +0200 Subject: [PATCH v2] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit In-Reply-To: <20260414081824.0edf6113@kernel.org> References: <20260413151232.1004611-1-shardul.b@mpiricsoftware.com> <20260414081824.0edf6113@kernel.org> Message-ID: On Tue, Apr 14, 2026 at 5:18?PM Jakub Kicinski wrote: > > On Tue, 14 Apr 2026 15:28:37 +0200 Jason A. Donenfeld wrote: > > Thanks. Applied to the wireguard tree, and also added the missing > > __net_exit and __read_mostly annotations in the process. > > Hi Jason, while we have you - do you have a PR for us for wireguard? > We're going to be sending the net-next PR later today.. Sent! From kuba at kernel.org Tue Apr 14 15:44:06 2026 From: kuba at kernel.org (Jakub Kicinski) Date: Tue, 14 Apr 2026 08:44:06 -0700 Subject: [PATCH v2] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit In-Reply-To: References: <20260413151232.1004611-1-shardul.b@mpiricsoftware.com> <20260414081824.0edf6113@kernel.org> Message-ID: <20260414084406.779336af@kernel.org> On Tue, 14 Apr 2026 17:40:03 +0200 Jason A. Donenfeld wrote: > On Tue, Apr 14, 2026 at 5:18?PM Jakub Kicinski wrote: > > > > On Tue, 14 Apr 2026 15:28:37 +0200 Jason A. Donenfeld wrote: > > > Thanks. Applied to the wireguard tree, and also added the missing > > > __net_exit and __read_mostly annotations in the process. > > > > Hi Jason, while we have you - do you have a PR for us for wireguard? > > We're going to be sending the net-next PR later today.. > > Sent! Thanks! (I'll apply in a couple of hours once the CI had its way with it.)