Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mac OS X equivalent of SecureZeroMemory / RtlSecureZeroMemory?

Is there a Mac OS X equivalent of RtlSecureZeroMemory / SecureZeroMemory, a function which zeroes a block of memory, but the call will not be optimized away by the compiler?

like image 584
Daniel Trebbien Avatar asked Nov 08 '12 23:11

Daniel Trebbien


2 Answers

Write your own function:

void secure_zero(void *s, size_t n)
{
    volatile char *p = s;

    while (n--) *p++ = 0;
}

EDIT: to the question in the comments, why not memset? The memset function call could be optimized away by the compiler if the array object is no futher accessed.

Note that C11 adds the (optional) function memset_s and the Standard guarantees the function call cannot be optimized away:

(C11, K.3.7.4.1p4) "[...] Unlike memset, any call to the memset_s function shall be evaluated strictly according to the rules of the abstract machine as described in (5.1.2.3). That is, any call to the memset_s function shall assume that the memory indicated by s and n may be accessible in the future and thus must contain the values indicated by c."

like image 194
ouah Avatar answered Oct 19 '22 21:10

ouah


Is there a Mac OS X equivalent of RtlSecureZeroMemory / SecureZeroMemory, a function which zeroes a block of memory, but the call will not be optimized away by the compiler?

In more recent version of the C runtime, you have memset_s. Its guaranteed not to be optimized away.

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
errno_t memset_s(void * restrict s, rsize_t smax, int c, rsize_t n)

OS X also includes the bzero function. But the bzero(3) man pages don't state its not subject to removal by the optimizer.

Avoid the tricks with the volatile qualifier because its not portable. It works as expected on Windows, but the GCC folks interpret volatile to mean memory backed by hardware for I/O. So you're not supposed to use volatile to tame the optimizer.


Here's an inline assembly implementation you can use. Oddly, __volatile__ on ASM statements and blocks are OK. It works fine on OS X (that's where it was originally written).

// g++ -Og -g3 -m64 wipe.cpp -o wipe.exe
// g++ -Og -g3 -m32 wipe.cpp -o wipe.exe    
// g++ -Os -g2 -S -m64 wipe.cpp -o wipe.exe.S
// g++ -Os -g2 -S -m32 wipe.cpp -o wipe.exe.S

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
    string s("Hello world");
    cout << "S: " << s << endl;

    char* ptr = &s[0];
    size_t size = s.length();

    if(ptr && size)
    {
        /* Needed because we can't just say to GCC, */
        /*   "give me a register that you choose".  */
        void* dummy;

        __asm__ __volatile__
        (
         "%=:\n\t"                /* generate a unique label for TOP */

#if (__WORDSIZE == 64)
         "subq $1, %2\n\t"        /* 0-based index */
#elif (__WORDSIZE == 32)
         "subl $1, %2\n\t"        /* 0-based index */
#elif (__WORDSIZE == 16)
         "subw $1, %2\n\t"        /* 0-based index */
#else
# error Unknown machine word size
#endif

         "lea (%1, %2), %0\n\t"   /* calcualte ptr[idx] */
         "movb $0, (%0)\n\t"      /* 0 -> ptr[size - 1] .. ptr[0] */
         "jnz %=b\n\t"            /* Back to TOP if non-zero */

         : "=&r" (dummy)
         :  "r" (ptr), "r" (size)
         : "0", "1", "2", "cc"
         );
    }

#if 0
    cout.setf(ios::hex, ios::basefield);
    cout.fill('0');

    for(size_t i = 0; i < s.length(); i++)
        cout << "0x" << setw(2) << ((int)s[i] & 0xff) << " ";

    cout << endl;
#endif

    cout << "S: " << s << endl;

    return 0;
}
like image 23
jww Avatar answered Oct 19 '22 21:10

jww