From 453920093835d64ba6e7f803bbf4bf53ed6ab479 Mon Sep 17 00:00:00 2001 From: Damian Rickard Date: Tue, 7 Jul 2026 20:33:42 -0400 Subject: [PATCH] Add Memory::SecureErase and use it for BufferPtr::Erase BufferPtr::Erase() was an alias for Zero(), i.e. a plain memset(), which the compiler may remove as a dead store when the buffer is not read afterwards. Every current BufferPtr::Erase() call site wipes secrets -- typed passwords (TextUserInterface, VolumePasswordPanel) and security token keyfile data (TextUserInterface, SecurityTokenKeyfilesDialog) -- so an elided wipe can leave them in memory. Introduce a dedicated secure erasure primitive, Memory::SecureErase(), implemented with the same volatile-write burn() loop that Buffer::Erase() already uses, and route both BufferPtr::Erase() and Buffer::Erase() through it. Memory::Zero() remains a plain memset() for generic zero initialization, so bulk zero-fill paths such as VolumeCreator's outputBuffer.Zero() before encryption are unaffected. A case-by-case review of the remaining call sites found no other changes needed: all .Zero() calls in the tree are genuine zero-initialization (header buffers before serialization, keyfile pool padding, RNG self-test pool reset, FAT formatter scratch sectors, POD struct init), and all .Erase() calls are genuine wipes, which now reach burn() in every case. --- src/Platform/Buffer.cpp | 2 +- src/Platform/Buffer.h | 2 +- src/Platform/Memory.cpp | 8 ++++++++ src/Platform/Memory.h | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Platform/Buffer.cpp b/src/Platform/Buffer.cpp index ac55c7bb93..ddbe33d596 100644 --- a/src/Platform/Buffer.cpp +++ b/src/Platform/Buffer.cpp @@ -77,7 +77,7 @@ namespace VeraCrypt void Buffer::Erase () { if (DataSize > 0) - burn (DataPtr, DataSize); + Memory::SecureErase (DataPtr, DataSize); } void Buffer::Free () diff --git a/src/Platform/Buffer.h b/src/Platform/Buffer.h index 5e5e989527..431b00ee8a 100644 --- a/src/Platform/Buffer.h +++ b/src/Platform/Buffer.h @@ -53,7 +53,7 @@ namespace VeraCrypt operator uint8 * () const { return DataPtr; } void CopyFrom (const ConstBufferPtr &bufferPtr) const; - void Erase () const { Zero(); } + void Erase () const { Memory::SecureErase (DataPtr, DataSize); } uint8 *Get () const { return DataPtr; } BufferPtr GetRange (size_t offset, size_t size) const; void Set (uint8 *data, size_t size) { DataPtr = data; DataSize = size; } diff --git a/src/Platform/Memory.cpp b/src/Platform/Memory.cpp index 8d2f6e19a1..aeb29b4c9c 100644 --- a/src/Platform/Memory.cpp +++ b/src/Platform/Memory.cpp @@ -61,6 +61,14 @@ namespace VeraCrypt memcpy (memoryDestination, memorySource, size); } + // Secure erasure of sensitive data: the volatile writes of burn() cannot + // be elided by the optimiser even when the buffer is not read afterwards. + // Use Zero() instead for ordinary zero-initialization. + void Memory::SecureErase (void *memory, size_t size) + { + burn (memory, size); + } + void Memory::Zero (void *memory, size_t size) { memset (memory, 0, size); diff --git a/src/Platform/Memory.h b/src/Platform/Memory.h index de6a64a841..fb6c1f761e 100644 --- a/src/Platform/Memory.h +++ b/src/Platform/Memory.h @@ -79,6 +79,7 @@ namespace VeraCrypt static void Copy (void *memoryDestination, const void *memorySource, size_t size); static void Free (void *memory); static void FreeAligned (void *memory); + static void SecureErase (void *memory, size_t size); static void Zero (void *memory, size_t size); };