From 0f8a4eb48527f5d487f1dc03bf5df1e41c63a0d1 Mon Sep 17 00:00:00 2001 From: tsunagi Date: Mon, 21 Sep 2026 12:28:28 +0100 Subject: [PATCH] Issue no privileged ioctl when attaching to a prepared interface The tun crate runs configure() by default (ensure_root_privileges is true), which is harmless today because it only acts on fields that were set, and the attach path sets none. Saying so explicitly documents the intent and keeps it true if the crate changes. Also records why packet information stays off: `ip tuntap add ... mode tun` defaults to no packet information too, so the TUNSETIFF flags match when attaching and reads and writes stay raw IP packets. Co-Authored-By: Claude Opus 5 (1M context) --- src/dataplane/wireguard/tun.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/dataplane/wireguard/tun.rs b/src/dataplane/wireguard/tun.rs index e846d80..5859eb2 100644 --- a/src/dataplane/wireguard/tun.rs +++ b/src/dataplane/wireguard/tun.rs @@ -337,12 +337,20 @@ mod system { let mut config = tun::Configuration::default(); config.tun_name(&request.name); - if !existed { - // Only configure what we are creating ourselves. - // Reconfiguring somebody else's prepared interface would - // need privileges we are trying not to require. + if existed { + // Attach only. Reconfiguring an interface somebody + // prepared for us would need exactly the privileges we + // are avoiding, so no ioctl beyond TUNSETIFF is issued. + config.platform_config(|platform| { + platform.ensure_root_privileges(false); + }); + } else { + // We are creating it, so we configure it. config.mtu(request.mtu as u16).up(); } + // Packet information stays off, so reads and writes are raw IP + // packets. `ip tuntap add ... mode tun` also defaults to no + // packet information, so the flags match when attaching. let device = tun::create_as_async(&config).map_err(|err| { let hint = if existed {