2012-11-08 83 views
9

是否存在與RtlSecureZeroMemory/SecureZeroMemory等效的Mac OS X,這是一種將內存塊清零的函數,但編譯器不會優化該調用?相當於SecureZeroMemory/RtlSecureZeroMemory的Mac OS X?

+1

FWIW,如果您使用的是OpenSSL,它提供了'OPENSSL_cleanse'函數,它可以用僞隨機數據安全地覆蓋一塊內存。 –

+3

考慮到OpenSSL確實(和AFAIK,**仍然在**)使用堆棧中未初始化的對象作爲熵源,我會毫不猶豫地將它用於這種嚴肅的安全性......作者不明白安全使用C.(這個問題在Debian修正它們的bug時引起了熵產生鍵的災難性損失。) –

+0

R,你說的並不完全正確。 Debian刪除了堆棧變量**和其他一些有效的熵源的使用,剩下的只是進程pid。這不是OpenSSL的錯,並且使用未初始化的變量作爲**額外的**熵源非常好。 – virco

回答

14

自己寫的函數:

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

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

編輯:這個問題的意見,爲什麼不memset?如果數組對象沒有被訪問,那麼編譯器可以優化memset函數調用。

需要注意的是C11增加了(可選)功能memset_s和標準保證了函數調用不能被優化掉:

(C11,K.3.7.4.1p4)「[...] memset的不同,任何對memset_s函數的調用都應嚴格按照(5.1.2.3)中所述的抽象機器的規則進行評估,也就是說,對memset_s函數的任何調用都應假定s和n指示的內存可以被訪問在將來,因此必須包含由c表示的值。「

+0

似乎compwecated和臃腫。爲什麼不memset? –

+4

@ Daij-Djan *爲什麼不是memset *:因爲如果數組對象沒有被進一步訪問,編譯器可以優化掉該調用。 *看起來很好的編譯和臃腫*:這是一種編寫'memset'函數的經典方法,我覺得它優雅和簡潔。 – ouah

+0

Dowvoter(如果不是@ Daij-Djan),謝謝你解釋爲什麼你低估了。 – ouah

3

是否有一個Mac OS X相當於RtlSecureZeroMemory/SecureZeroMemory,其中零的內存塊的功能,但通話不會被編譯器優化掉?

在更新版本的C運行時,您有memset_s。它保證不會被優化掉。

#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還包含bzero函數。但bzero(3) man pages不會陳述它的而不是可以被優化器移除。

避免使用volatile限定符的技巧,因爲它不便攜。它在Windows上按預期工作,但GCC人員將volatile解釋爲由I/O硬件支持的內存。所以你不應該使用volatile來馴服優化器。


這是您可以使用的內聯彙編實現。奇怪的是,在ASM語句和塊上的__volatile__都可以。它在OS X上正常工作(這是它最初編寫的地方)。

// 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; 
}