diff --git a/libfoundation/include/foundation-span.h b/libfoundation/include/foundation-span.h index 2499cde56e8..e5560a1fdd6 100644 --- a/libfoundation/include/foundation-span.h +++ b/libfoundation/include/foundation-span.h @@ -209,6 +209,13 @@ inline MCSpan MCDataGetSpan(MCDataRef p_data) * Span-based overloads for pointer+range libfoundation functions * ---------------------------------------------------------------- */ +template +inline void MCMemoryClearSecure(MCSpan x_span) +{ + MCMemoryClearSecure(reinterpret_cast(x_span.data()), + x_span.sizeBytes()); +} + MC_DLLEXPORT hash_t MCHashBytes(MCSpan bytes); diff --git a/libfoundation/include/foundation.h b/libfoundation/include/foundation.h index ab45ee2366f..05b63a6e4e0 100644 --- a/libfoundation/include/foundation.h +++ b/libfoundation/include/foundation.h @@ -998,6 +998,11 @@ extern "C" { // Clear the given block of memory to all 0's. inline void MCMemoryClear(void *dst, size_t size) { memset(dst, 0, size); } +// Clear the given block of memory to all 0's, ensuring that the +// compiler never optimises it out. Use this when clearing sensitive +// data from memory. +MC_DLLEXPORT void MCMemoryClearSecure(byte_t* dst, size_t size); + // Fill the given block of memory with the given (byte) value. inline void MCMemoryFill(void *dst, size_t size, uint8_t value) { memset(dst, value, size); } @@ -1025,6 +1030,14 @@ template void inline MCMemoryClear(T&p_struct) MCMemoryClear(&p_struct, sizeof(T)); } +// Securely clear the memory of the given structure to all 0's +template +void inline MCMemoryClearSecure(T& p_struct) +{ + MCMemoryClearSecure(reinterpret_cast(&p_struct), + sizeof(p_struct)); +} + // Re-initialise an object to its default-constructed state template void inline MCMemoryReinit(T& p_object) { diff --git a/libfoundation/src/foundation-core.cpp b/libfoundation/src/foundation-core.cpp index 34e50cfbc5f..fc26b4d3702 100644 --- a/libfoundation/src/foundation-core.cpp +++ b/libfoundation/src/foundation-core.cpp @@ -22,6 +22,10 @@ along with LiveCode. If not see . */ #include "foundation-hash.h" #include "foundation-string-hash.h" +#if defined(__WINDOWS__) +# include +#endif + //////////////////////////////////////////////////////////////////////////////// #ifdef __LINUX__ @@ -215,6 +219,25 @@ void MCMemoryDeleteArray(void *p_array) //////////////////////////////////////////////////////////////////////////////// +/* Securely clear the memory located at dst, using volatile to try to + * ensure that the compiler doesn't optimise it out. */ +MC_DLLEXPORT +void MCMemoryClearSecure(byte_t* dst, + size_t size) +{ +#if defined(__WINDOWS__) + SecureZeroMemory(dst, size); +#else + MCMemoryClear(dst, size); + /* Add a barrier to prevent the compiler from optimizing the above + * MCMemoryClear() call away. Without this, both clang and GCC + * will optimise out the memory clear.*/ + __asm__ __volatile__ ( "" : : "r"(dst) : "memory" ); +#endif +} + +//////////////////////////////////////////////////////////////////////////////// + MC_DLLEXPORT_DEF hash_t MCHashInteger(integer_t i) {