From dc5860d96963fdc4ea3a5104989e5fb062171cbd Mon Sep 17 00:00:00 2001 From: rabbit Date: Tue, 21 Apr 2026 09:14:18 +0000 Subject: [PATCH] Fix undefined behavior in StartElevated stderr read loop (#1550) The read loop that captures stderr from the sudo child process used `vector buffer(4096); buffer.clear();` followed by `read(fd, &buffer[0], buffer.capacity())`. This has two instances of undefined behavior: 1. `operator[](0)` on a vector with `size() == 0` violates the C++ standard precondition `n < size()`. libstdc++ built with `-D_GLIBCXX_ASSERTIONS` aborts the process with: stl_vector.h:1128: Assertion '__n < this->size()' failed. 2. `buffer.begin() + bytesRead` on the same empty vector constructs an iterator past `end()`, also UB. `-D_GLIBCXX_ASSERTIONS` is in the default build flags of Arch Linux, Fedora, and several other distributions. On those systems, the unprivileged helper process aborts as soon as sudo writes anything to stderr (a password prompt, a 'user is not in the sudoers file' error, etc.). The main process then sees EOF on the service output pipe, and throws `InsufficientData`, which renders to the user as 'Not enough data available'. A second mount attempt fails at `File::Write` because the helper is dead and the pipe is broken, producing the bare message 'VeraCrypt::File::Write:395'. Fix by replacing `buffer` with a plain `char[4096]` and using `reserve(4096)` on `errOutput` to preserve the original pre-allocation intent. No behavioral change on systems where the UB happened to work; aborts are eliminated on systems where the assertions fire. Reported-by: multiple users, see veracrypt/VeraCrypt#1550, veracrypt/VeraCrypt#1446, veracrypt/VeraCrypt#844 --- src/Core/Unix/CoreService.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Core/Unix/CoreService.cpp b/src/Core/Unix/CoreService.cpp index e4e9b5e3d5..dca2cfa066 100644 --- a/src/Core/Unix/CoreService.cpp +++ b/src/Core/Unix/CoreService.cpp @@ -503,9 +503,9 @@ namespace VeraCrypt throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, O_NONBLOCK) == -1); throw_sys_if (fcntl (errPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1); - vector buffer (4096), errOutput (4096); - buffer.clear (); - errOutput.clear (); + char buffer[4096]; + vector errOutput; + errOutput.reserve (4096); Poller poller (outPipe->GetReadFD(), errPipe.GetReadFD()); int status, waitRes; @@ -518,10 +518,10 @@ namespace VeraCrypt ssize_t bytesRead = 0; foreach (int fd, poller.WaitForData (timeout)) { - bytesRead = read (fd, &buffer[0], buffer.capacity()); + bytesRead = read (fd, buffer, sizeof (buffer)); if (bytesRead > 0 && fd == errPipe.GetReadFD()) { - errOutput.insert (errOutput.end(), buffer.begin(), buffer.begin() + bytesRead); + errOutput.insert (errOutput.end(), buffer, buffer + bytesRead); if (bytesRead > 5 && bytesRead < 80) // Short message captured timeout = 200;