From patchwork Tue Sep 1 15:10:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 5307 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:c317:b0:87d:ab56:3700 with SMTP id jk23csp4773062mab; Tue, 1 Sep 2026 08:10:34 -0700 (PDT) X-Forwarded-Encrypted: i=2; AHgh+RqynVmY0dtSjKz84giDgnNyNZ2xkFBLSO1XnK1wUlZB2cowJi4JWZDRDjdWuQ/JqgKqlhyeJy6ctvw=@openvpn.net X-Received: by 2002:a05:6808:15a8:b0:495:eb86:6e8f with SMTP id 5614622812f47-4b5b821be0amr9310666b6e.14.1788275434021; Tue, 01 Sep 2026 08:10:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1788275434; cv=none; d=google.com; s=arc-20260327; b=SANjaIqGChUd1Cv5Lhaat+KgKgPeqyJZgWGKKX8CQfl3DOAF1lM6nACzHrppNn4WbC YzeBdMOlDEHqWO5Vo6gNz0gR8kdawVRcW9HS9M7fB5CF5MjYK7B7Y8cISK2WZAOERq1i 5pSlTMXWMmzHADg/W0+MtoakclT3MKR+VMIm7qZ7ua8IAVD/PZ4QzurDw71Rsxs8UOda OiNEsXqvURBx9C4WpzqKzVUuG6oEOxDBDBpQu4QNL71XvsJvvOhdw3oMb6NvHyp3LpHe lqcYiMed7LMouiIdFuOi489NM8Acuxlh7H9p8URXv8Yd4GPabJ0GXQsON4kdOPacxZCk RQFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature:dkim-signature; bh=cxY2dmHUUEpBffRqXf5kxpwkoRp0rJ+1Fl0aaPu32LM=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=PD4yUKl2zxZ0ySlP1ofNPCVTVZr/lDIJE5aqGy9vAEViwBDXUtsI9T3qhXtmLDlHEY 4wN2WFgmRT/aT+Pqx+2+LX3Hmn/xvP5KIS3zL+MYf/yOLhaaqLdal673ZYTQHnlM23u0 kHXBEUGPRl5k6hnWo58ADFUSF3wPnTBJD7yT3ZmB0yyk3ZOwwtVRvx7I6kpLBaGDEDJa XhgSHGutw/2RaQvfDsEGuk5U6bQANToRrSQ/9I8S028EdsTMpvAkWM8XTyiQscZHbUlu wMu+zmiQJ5LVVF76is8daIBXUdq36n+2q+IZchJNsRfngrVxKlnvC3KIFom57kJ5dy5p OlfA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=KTSgRcvf; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=McSbKm6g; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Lzp+vhUM; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 5614622812f47-4b3a1ae4317si19920028b6e.74.2026.09.01.08.10.33 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 01 Sep 2026 08:10:33 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=KTSgRcvf; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=McSbKm6g; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Lzp+vhUM; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender: Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=cxY2dmHUUEpBffRqXf5kxpwkoRp0rJ+1Fl0aaPu32LM=; b=KTSgRcvfKyOXKVCT/IXSO8/t89 yvgH0z/S3VcDnbZC1bpjT/4pgwqnKMFs+N+LpWXE08WfZbd8jayr1eD74p+g3QvILNJ6Q8zfavegq z2/LmouByic1ubf91Rn+gCNW8kArFiywgYE8rcoSmpPSoQIA25RsECAazz4CFfLl2D70=; Received: from [127.0.0.1] (helo=sfs-ml-3.v29.lw.sourceforge.com) by sfs-ml-3.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1x1Q83-0001Hh-At; Tue, 01 Sep 2026 15:10:28 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-3.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1x1Q82-0001Hb-0p for openvpn-devel@lists.sourceforge.net; Tue, 01 Sep 2026 15:10:26 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=j1kkZ2e4mpUNhA7V1EZTJfetsJ0MkwSGa24anZye4pM=; b=McSbKm6gVmHtGMU1W8GMx1fIta miXluCUNIwgXwZOxA3h/GczTIIqWAZAuGV6vaKG73EpwpNk5CeWSgprPXEtDf1O1I+DOPx5Zek05L aMIxhObHp+jzru5S4V/gDNjtpfQibT2ZyQ2HiGMfMCMZZZ9+gaUAx00GeXogCw5mgRsU=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=j1kkZ2e4mpUNhA7V1EZTJfetsJ0MkwSGa24anZye4pM=; b=Lzp+vhUMmtENPKFBIV4JjotMon wGRvlOc80zPV+hAZV2fZ8III9+xX7ZxRJ8jdB59A+t216BYuNX4ZNCv1rAEDuWgl7O9sKi72MowKk FIbDzCxZogWETFLLiSf491A8A+QqGYn4a+iScd1LnZX+Ef010N4qNbj4Hd2nEiHhFLeY=; Received: from [193.149.48.129] (helo=blue.greenie.muc.de) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1x1Q81-0003bG-1J for openvpn-devel@lists.sourceforge.net; Tue, 01 Sep 2026 15:10:26 +0000 Received: from blue.greenie.muc.de (localhost [127.0.0.1]) by blue.greenie.muc.de (8.18.1/8.18.1) with ESMTP id 681FAHcq016234 for ; Tue, 1 Sep 2026 17:10:17 +0200 Received: (from gert@localhost) by blue.greenie.muc.de (8.18.2/8.18.1/Submit) id 681FAHwP016233 for openvpn-devel@lists.sourceforge.net; Tue, 1 Sep 2026 17:10:17 +0200 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Tue, 1 Sep 2026 17:10:10 +0200 Message-ID: <20260901151017.16221-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Score: 1.3 (+) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-1.hosts.colo.sdot.me", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Antonio Quartulli sitnl_send() passed every well-formed reply to the callback without checking it matched the outstanding request: the seq/pid check was commented out and the sequence number came from time(NULL). Content analysis details: (1.3 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 1.3 RDNS_NONE Delivered to internal network by a host with no rDNS X-Headers-End: 1x1Q81-0003bG-1J Subject: [Openvpn-devel] [PATCH v3] networking_sitnl: validate netlink replies against the request X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: 1875115590695690831 X-GMAIL-MSGID: 1875142701808609541 From: Antonio Quartulli sitnl_send() passed every well-formed reply to the callback without checking it matched the outstanding request: the seq/pid check was commented out and the sequence number came from time(NULL). Seed a monotonically increasing sequence number and drop any message that is not from the kernel (nl_pid 0) or does not echo our port id and sequence number. Change-Id: Ie7352dd136cccda2bd6b6e1a36db1a5f27afd8f7 GitHub: fixes OpenVPN/openvpn-private-issues#9 Signed-off-by: Antonio Quartulli Acked-by: Ralf Lici Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1782 --- This change was reviewed on Gerrit and approved by at least one developer. I request to merge it to master. Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1782 This mail reflects revision 3 of this Change. Acked-by according to Gerrit (reflected above): Ralf Lici diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c index e6e72d0..a396255 100644 --- a/src/openvpn/networking_sitnl.c +++ b/src/openvpn/networking_sitnl.c @@ -197,7 +197,7 @@ * Bind socket to Netlink subsystem */ static int -sitnl_bind(int fd, uint32_t groups) +sitnl_bind(int fd, uint32_t groups, uint32_t *local_pid) { socklen_t addr_len; struct sockaddr_nl local; @@ -232,6 +232,14 @@ return -EINVAL; } + /* We bound with nl_pid=0, so the kernel assigned this socket a unique port + * id (it is not the process pid - a process may own several netlink + * sockets). getsockname() above is the only way to learn it: hand it back + * to the caller, which uses it to check that replies are addressed to this + * socket. + */ + *local_pid = local.nl_pid; + return 0; } @@ -243,6 +251,7 @@ void *arg_cb) { int fd, ret; + uint32_t local_pid = 0; struct sockaddr_nl nladdr; struct nlmsgerr *err; struct nlmsghdr *h; @@ -264,11 +273,17 @@ nladdr.nl_pid = peer; nladdr.nl_groups = groups; - /* NB: We currently do not verify seq and pid on answers. - * If we ever want to start with that we probably need to come up - * with something better than "seconds since epoch"... + /* Match replies to requests with a monotonically increasing sequence + * number, seeded once from wall-clock time so it differs between runs. + * The kernel echoes this seq (and our port id) in its replies, letting the + * receive loop below discard any unrelated or spoofed message. */ - payload->nlmsg_seq = (uint32_t)time(NULL); + static uint32_t sitnl_seq; + if (!sitnl_seq) + { + sitnl_seq = (uint32_t)time(NULL); + } + payload->nlmsg_seq = ++sitnl_seq; /* no need to send reply */ if (!cb) @@ -283,7 +298,7 @@ return -errno; } - if (sitnl_bind(fd, 0) < 0) + if (sitnl_bind(fd, 0, &local_pid) < 0) { msg(M_WARN | M_ERRNO, "%s: can't bind rtnl socket", __func__); ret = -errno; @@ -357,18 +372,23 @@ goto out; } - /* if (((int)nladdr.nl_pid != peer) || (h->nlmsg_pid != nladdr.nl_pid) - * || (h->nlmsg_seq != seq)) - * { - * rcv_len -= NLMSG_ALIGN(len); - * h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); - * msg(M_DEBUG, "%s: skipping unrelated message. nl_pid:%d (peer:%d) - * nl_msg_pid:%d nl_seq:%d seq:%d", - * __func__, (int)nladdr.nl_pid, peer, h->nlmsg_pid, - * h->nlmsg_seq, seq); - * continue; - * } + /* Discard any message that did not come from the kernel or does + * not match the request we sent: only the kernel (nl_pid 0) can + * legitimately reply, and a valid reply echoes our port id and + * sequence number. This prevents a local process from injecting a + * spoofed reply that the callback would otherwise act on. */ + if ((nladdr.nl_pid != 0) || (h->nlmsg_pid != local_pid) + || (h->nlmsg_seq != payload->nlmsg_seq)) + { + msg(D_RTNL, + "%s: skipping unrelated message. nl_pid:%u nlmsg_pid:%u (local:%u) nlmsg_seq:%u (seq:%u)", + __func__, nladdr.nl_pid, h->nlmsg_pid, local_pid, h->nlmsg_seq, + payload->nlmsg_seq); + rcv_len -= NLMSG_ALIGN(len); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); + continue; + } if (h->nlmsg_type == NLMSG_DONE) {