Skip to content

Commit 5f7d7a8

Browse files
authored
Merge pull request livecode#5338 from peter-b/bugfix-17097
[Bug 17097] libfoundation: Add MCMemoryClearSecure()
2 parents bd2a751 + 9d132a2 commit 5f7d7a8

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

libfoundation/include/foundation-span.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,13 @@ inline MCSpan<ElementType> MCDataGetSpan(MCDataRef p_data)
209209
* Span-based overloads for pointer+range libfoundation functions
210210
* ---------------------------------------------------------------- */
211211

212+
template <typename ElementType>
213+
inline void MCMemoryClearSecure(MCSpan<ElementType> x_span)
214+
{
215+
MCMemoryClearSecure(reinterpret_cast<byte_t*>(x_span.data()),
216+
x_span.sizeBytes());
217+
}
218+
212219
MC_DLLEXPORT
213220
hash_t MCHashBytes(MCSpan<const byte_t> bytes);
214221

libfoundation/include/foundation.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,11 @@ extern "C" {
998998
// Clear the given block of memory to all 0's.
999999
inline void MCMemoryClear(void *dst, size_t size) { memset(dst, 0, size); }
10001000

1001+
// Clear the given block of memory to all 0's, ensuring that the
1002+
// compiler never optimises it out. Use this when clearing sensitive
1003+
// data from memory.
1004+
MC_DLLEXPORT void MCMemoryClearSecure(byte_t* dst, size_t size);
1005+
10011006
// Fill the given block of memory with the given (byte) value.
10021007
inline void MCMemoryFill(void *dst, size_t size, uint8_t value) { memset(dst, value, size); }
10031008

@@ -1025,6 +1030,14 @@ template <typename T> void inline MCMemoryClear(T&p_struct)
10251030
MCMemoryClear(&p_struct, sizeof(T));
10261031
}
10271032

1033+
// Securely clear the memory of the given structure to all 0's
1034+
template <typename T>
1035+
void inline MCMemoryClearSecure(T& p_struct)
1036+
{
1037+
MCMemoryClearSecure(reinterpret_cast<byte_t*>(&p_struct),
1038+
sizeof(p_struct));
1039+
}
1040+
10281041
// Re-initialise an object to its default-constructed state
10291042
template <typename T> void inline MCMemoryReinit(T& p_object)
10301043
{

libfoundation/src/foundation-core.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
2222
#include "foundation-hash.h"
2323
#include "foundation-string-hash.h"
2424

25+
#if defined(__WINDOWS__)
26+
# include <Windows.h>
27+
#endif
28+
2529
////////////////////////////////////////////////////////////////////////////////
2630

2731
#ifdef __LINUX__
@@ -215,6 +219,25 @@ void MCMemoryDeleteArray(void *p_array)
215219

216220
////////////////////////////////////////////////////////////////////////////////
217221

222+
/* Securely clear the memory located at dst, using volatile to try to
223+
* ensure that the compiler doesn't optimise it out. */
224+
MC_DLLEXPORT
225+
void MCMemoryClearSecure(byte_t* dst,
226+
size_t size)
227+
{
228+
#if defined(__WINDOWS__)
229+
SecureZeroMemory(dst, size);
230+
#else
231+
MCMemoryClear(dst, size);
232+
/* Add a barrier to prevent the compiler from optimizing the above
233+
* MCMemoryClear() call away. Without this, both clang and GCC
234+
* will optimise out the memory clear.*/
235+
__asm__ __volatile__ ( "" : : "r"(dst) : "memory" );
236+
#endif
237+
}
238+
239+
////////////////////////////////////////////////////////////////////////////////
240+
218241
MC_DLLEXPORT_DEF
219242
hash_t MCHashBool(bool b)
220243
{

0 commit comments

Comments
 (0)