From patchwork Sat Nov 29 13:43:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4649 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6c3:b0:7b1:439f:bdf with SMTP id j3csp5669536maw; Sat, 29 Nov 2025 05:43:52 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCUCS+jCGK4O+i2XvE5mP054Jo1c5rw5C+xHdfKYmK14xrf+7ZJQ6gxJI7y8uZnLLBEETw112C6OOyo=@openvpn.net X-Google-Smtp-Source: AGHT+IEI1vkQv3lgDGSWtJC5qEb4Fa5N4mLqJ3dzkbXv5ZAG/MBzL66myZVB88hmHeeWIzCn+nYl X-Received: by 2002:a05:6830:7199:b0:7c7:68d8:f702 with SMTP id 46e09a7af769-7c7c410c455mr9081784a34.9.1764423832625; Sat, 29 Nov 2025 05:43:52 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1764423832; cv=none; d=google.com; s=arc-20240605; b=g3WKZsitkUCcqsOFdl4FFhETUZ5lyTx+BG6aKf2QNrqONOQ0V+VXj9qTxJKxxT3/JW 4CibfxRNhjpuxtq8hVTVXv93rhh4v1i67HuI9xL4KHumH6MwSDCAiS/mMXdy6YmZeSlr suO/edqEGfqpaENCAEB38Fq3fJIPHu+pL6oVDaje61cG7/w7AvkHzL5LiGM/WzW5YcPL F2rBWS9bFT8NGXcejNS4i9ve0mloszUwm3pDfCakYHwDbKGV7jEN+n5J6aj4I5LkPYCM +qGmvnF5exT8jsCkFocIYTMxZi9uxeOLdXWJcpqCQUV2iLnITT4iz87Frtpt21LnLHfa O0Rw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:mime-version:message-id :to:from:date:dkim-signature:dkim-signature:dkim-signature; bh=oLfW5OlmHKCA1qJDseLQSSvlPtCse1EgpQTGrQLCrBo=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=PDxoBU6X69auOXQwx6kclWFgNuL9980nl0tyumTvPNJq1Tf/fhWXLsHiZ5vdodMXI8 Q/7XOfdHGkFTAVE8MgdBrpMKGHzOedp+rh9MxnoFCfLA8HSvTtxeNO1cS2twH0+6m/yo UUac370Jjz7+CZedfYnjYLE36ZE21i2F1WPbUexGP/ippL5ShHtY962Dp3Q7PKWEUSRB KCdyJpJUVn4DbBNLK+7hD3MspWuIF46mvcKo/CB5i3gkxmzzzOXIm4dzf9wvvbJHYwfu uHs+zcYkz+Re/Fn2gcAiDnNyuwFhwnVKwvsK1Yxff/8mdT49uEC5Gi66zGX/Ke282E4e aGLg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=MPybQtfl; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=C+CsRv1q; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=agxUWMAG; 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 46e09a7af769-7c90f5d4440si1253361a34.61.2025.11.29.05.43.51 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 29 Nov 2025 05:43:52 -0800 (PST) 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=MPybQtfl; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=C+CsRv1q; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=agxUWMAG; 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-Type:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:Subject:MIME-Version: Message-ID:To:From:Date:Sender:Reply-To:Cc:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner; bh=oLfW5OlmHKCA1qJDseLQSSvlPtCse1EgpQTGrQLCrBo=; b=MPybQtflHtYaVPzSMydMx4Iy1t DJIEGkm7LXodqqKdI3JJdavWBHaXiIsLkR84oSsAqxDXKim2hAxnRFoLQr6ZZoW4rMZez1tVO/5G4 MLy4YGNOoBAW+8bL3XAFE2OHqenBkhTFFHMw0kxlo/hNXPapxd6way2YpYKfp+v7iP0s=; Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1vPLEl-0002Iy-1V; Sat, 29 Nov 2025 13:43:43 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1vPLEi-0002Ih-Oe for openvpn-devel@lists.sourceforge.net; Sat, 29 Nov 2025 13:43:41 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:MIME-Version:Message-ID:Subject:To: From:Date:Sender:Reply-To:Cc:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=xo8v1dGSlyqyNuoBhoxvg+rRs4MO94zOSRg9Y6LQkQU=; b=C+CsRv1qNkcnLNjq4ehxY/M0CK DMOP3t3hFMknl4APG1h6Fjs/cjkrwfPI3/gAAkF9bI5v+P2RU/E0SNz3WSn51Orrihvnp4RS+yo4p O9W/wGyMXe7Nttqd+7QWqd4P9Rk0vNYa/r/fXdWtwKesgTN3HoSxk4UyUlEdOfuQLra4=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:MIME-Version:Message-ID:Subject:To:From:Date:Sender:Reply-To :Cc:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post: List-Owner:List-Archive; bh=xo8v1dGSlyqyNuoBhoxvg+rRs4MO94zOSRg9Y6LQkQU=; b=a gxUWMAGWKMRgoz7ymdZme96h+qErZJs7JBT1HyEhTBdlCjgp7RqG0n1pi9kEtcg9jHjnwRtbOz/Zb Ebpfxu06zbBEv6py6F13XOQ9trGQjJLxJAEI4uMSALhKKJ43Fjxm8gEw4Pbm3+tOcDTkTlZQyu4Hm jqn0wWudfS3m5KJs=; Received: from chekov.greenie.muc.de ([193.149.48.178]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1vPLEi-0001PK-7m for openvpn-devel@lists.sourceforge.net; Sat, 29 Nov 2025 13:43:41 +0000 Received: from chekov.greenie.muc.de (localhost [IPv6:0:0:0:0:0:0:0:1]) by chekov.greenie.muc.de (8.18.1/8.18.1) with ESMTPS id 5ATDhXdn074631 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO) for ; Sat, 29 Nov 2025 14:43:33 +0100 (CET) (envelope-from gert@chekov.greenie.muc.de) Received: (from gert@localhost) by chekov.greenie.muc.de (8.18.1/8.18.1/Submit) id 5ATDhXCZ074630 for openvpn-devel@lists.sourceforge.net; Sat, 29 Nov 2025 14:43:33 +0100 (CET) (envelope-from gert) Date: Sat, 29 Nov 2025 14:43:33 +0100 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Message-ID: MIME-Version: 1.0 X-mgetty-docs: http://mgetty.greenie.net/ X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-2.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: Hi, you might have seen 2.6.17 and 2.7_rc3 releases yesterday, mentioning - Windows/Interactive Service: CVE-2025-13751 fix bug where the interactive service would error-exit in certain error conditions instead of just logging the fact and continuing. After the error-exit, [...] Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- X-Headers-End: 1vPLEi-0001PK-7m Subject: [Openvpn-devel] CVE fix for Windows in 2.5, 2.6, 2.7_rc3 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: =?utf-8?q?1850132484739506490?= X-GMAIL-MSGID: =?utf-8?q?1850132484739506490?= Hi, you might have seen 2.6.17 and 2.7_rc3 releases yesterday, mentioning - Windows/Interactive Service: CVE-2025-13751 fix bug where the interactive service would error-exit in certain error conditions instead of just logging the fact and continuing. After the error-exit, OpenVPN connections will no longer work until the service is restarted (or the system rebooted). This can be triggered by any authenticated local user, and has thus been classified as a "local denial of service" attack. as usual for bugs that we classify as "we do not want them to leak before a fixed installer is out" the fix was developed & tested & reviewed in private (Lev, Selva, Heiko). Also, for the usual maximum transparency, I'll hereby send it to the list - attached is the 2.7 patch, which is commit 6088451b616be313bd47cfed8d82d47bd6e17d93 Author: Lev Stipakov Date: Mon Nov 24 12:09:23 2025 +0200 interactive.c: harden pipe handling against misbehaving clients the 2.6 patch is basically the same change, but the differences are wide character text handling (TEXT("") vs. L"") between 2.6 and 2.7 commit 29d8eccface918703b91dde230285ca869f95090 (release/2.6) Author: Lev Stipakov Date: Mon Nov 24 12:09:23 2025 +0200 interactive.c: harden pipe handling against misbehaving clients and, finally, the 2.5 patch is a direct cherrypick from 2.6 commit 1f4b444e1407450a1071a633d73d2a63a0af06c2 (release/2.5) Author: Lev Stipakov Date: Mon Nov 24 12:09:23 2025 +0200 interactive.c: harden pipe handling against misbehaving clients Note that we do not intend to publish new 2.5.x windows installers - but if someone is building their product on the 2.5 source tree, the fix is in. gert From 6088451b616be313bd47cfed8d82d47bd6e17d93 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Mon, 24 Nov 2025 12:09:23 +0200 Subject: [PATCH 1/2] interactive.c: harden pipe handling against misbehaving clients - Handle ConnectNamedPipe ERROR_NO_DATA as a normal connect/drop race: log the drop, disconnect/reset that instance, and keep listening instead of letting a trivial local DoS stop the service. - Add a timed peek for startup data so a client that connects and sends nothing is timed out (IO_TIMEOUT) and rejected, instead of leaving a worker thread blocked forever and piling up handles. - Protect the accept loop from resource exhaustion: before spawning a worker, check the wait set and reject the client if adding another handle would exceed MAXIMUM_WAIT_OBJECTS; also skip FlushFileBuffers when no startup data was received to avoid hangs on silent clients. Without these fixes, a malicious local windows user can make the OpenVPN Interactive Service exit-on-error, thus breaking all OpenVPN connections until the service is restarted (or the system rebooted). Thus this has been classified as "local denial of service" and CVE-2025-13751 has been assigned. CVE: 2025-13751 Change-Id: Id6a13b0c8124117bcea2926b16607ef39344015a Signed-off-by: Lev Stipakov Acked-by: Selva Nair --- src/openvpnserv/interactive.c | 60 +++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 220c0427..6f04f6b5 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -208,6 +208,7 @@ ResetOverlapped(LPOVERLAPPED overlapped) typedef enum { peek, + peek_timed, read, write } async_op_t; @@ -260,7 +261,7 @@ AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, goto out; } - if (op == peek) + if (op == peek || op == peek_timed) { PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL); } @@ -281,6 +282,12 @@ PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events) return AsyncPipeOp(peek, pipe, NULL, 0, count, events); } +static DWORD +PeekNamedPipeAsyncTimed(HANDLE pipe, DWORD count, LPHANDLE events) +{ + return AsyncPipeOp(peek_timed, pipe, NULL, 0, count, events); +} + static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events) { @@ -437,11 +444,11 @@ GetStartupData(HANDLE pipe, STARTUP_DATA *sud) WCHAR *data = NULL; DWORD bytes, read; - bytes = PeekNamedPipeAsync(pipe, 1, &exit_event); + bytes = PeekNamedPipeAsyncTimed(pipe, 1, &exit_event); if (bytes == 0) { - MsgToEventLog(M_SYSERR, L"PeekNamedPipeAsync failed"); - ReturnLastError(pipe, L"PeekNamedPipeAsync"); + MsgToEventLog(M_ERR, L"Timeout waiting for startup data"); + ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData (timeout)", 1, &exit_event); goto err; } @@ -3248,6 +3255,7 @@ RunOpenvpn(LPVOID p) size_t cmdline_size; undo_lists_t undo_lists; WCHAR errmsg[512] = L""; + BOOL flush_pipe = TRUE; SECURITY_ATTRIBUTES inheritable = { .nLength = sizeof(inheritable), .lpSecurityDescriptor = NULL, @@ -3267,6 +3275,7 @@ RunOpenvpn(LPVOID p) if (!GetStartupData(pipe, &sud)) { + flush_pipe = FALSE; /* client did not provide startup data */ goto out; } @@ -3562,7 +3571,10 @@ RunOpenvpn(LPVOID p) Undo(&undo_lists); out: - FlushFileBuffers(pipe); + if (flush_pipe) + { + FlushFileBuffers(pipe); + } DisconnectNamedPipe(pipe); free(ovpn_user); @@ -3834,11 +3846,30 @@ ServiceStartInteractive(DWORD dwArgc, LPWSTR *lpszArgv) while (TRUE) { - if (ConnectNamedPipe(pipe, &overlapped) == FALSE && GetLastError() != ERROR_PIPE_CONNECTED - && GetLastError() != ERROR_IO_PENDING) + if (!ConnectNamedPipe(pipe, &overlapped)) { - MsgToEventLog(M_SYSERR, L"Could not connect pipe"); - break; + DWORD connect_error = GetLastError(); + if (connect_error == ERROR_NO_DATA) + { + /* + * Client connected and disconnected before we could process it. + * Disconnect and retry instead of aborting the service. + */ + MsgToEventLog(M_ERR, L"ConnectNamedPipe returned ERROR_NO_DATA (client dropped)"); + DisconnectNamedPipe(pipe); + ResetOverlapped(&overlapped); + continue; + } + else if (connect_error == ERROR_PIPE_CONNECTED) + { + /* No async I/O pending in this case; signal manually. */ + SetEvent(overlapped.hEvent); + } + else if (connect_error != ERROR_IO_PENDING) + { + MsgToEventLog(M_SYSERR, L"Could not connect pipe"); + break; + } } error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE); @@ -3846,6 +3877,17 @@ ServiceStartInteractive(DWORD dwArgc, LPWSTR *lpszArgv) { /* Client connected, spawn a worker thread for it */ HANDLE next_pipe = CreateClientPipeInstance(); + + /* Avoid exceeding WaitForMultipleObjects MAXIMUM_WAIT_OBJECTS */ + if (handle_count + 1 > MAXIMUM_WAIT_OBJECTS) + { + ReturnError(pipe, ERROR_CANT_WAIT, L"Too many concurrent clients", 1, &exit_event); + CloseHandleEx(&pipe); + pipe = next_pipe; + ResetOverlapped(&overlapped); + continue; + } + HANDLE thread = CreateThread(NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL); if (thread) { -- 2.51.2