2012-11-08 15 views
9

RtlSecureZeroMemory/SecureZeroMemoryに相当するMac OS Xがあります。これは、メモリブロックをゼロにする機能ですが、呼び出しはコンパイラによって最適化されません。Mac OS X相当のSecureZeroMemory/RtlSecureZeroMemory?

+1

FWIWあなたはOpenSSLを使用している場合、それはしっかりと擬似ランダム・データでメモリのブロックを上書き 'OPENSSL_cleanse'機能を提供します。 –

+3

OpenSSLが(そしてAFAIK、**はまだ**でも)エントロピー源としてスタック上の初期化されていないオブジェクトを使用していることを考えると、私はこのような重大なセキュリティのために使用することを躊躇します... (この問題は、Debianがバグを修正したときにキーを生成するエントロピーの致命的な損失を引き起こしました。) –

+0

R、あなたが言うことは完全に真実ではありません。 Debianはスタック変数**と**いくつかの他の有効なエントロピーソースの使用法を削除しました。残っているのはプロセスPIDだけです。 OpenSSLの誤りではありませんでした。**追加の**エントロピーソースとして初期化されていない変数を使用することは、まったく問題ありません。 – virco

答えて

14

は、独自の機能を書く:

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

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

EDIT:コメントに質問、なぜmemsetか? memset関数呼び出しは、配列オブジェクトにさらにアクセスする必要がない場合、コンパイラによって最適化されます。 C11(オプション)機能memset_sを追加し、標準関数呼び出しを保証

注意を離れて最適化することができません。

(C11、K.3.7.4.1p4)「[...]のmemsetとは異なりmemset_s関数への呼び出しは、(5.1.2.3)で説明した抽象マシンの規則に従って厳密に評価されなければならない。すなわち、memset_s関数の呼び出しは、sとnで示されるメモリがアクセス可能であると仮定するcで示される値を含む必要があります。

+0

はひどくまとまって膨らんでいるようです。なぜmemsetですか? –

+4

@ Daij-Djan *なぜmemset *:なぜなら、配列オブジェクトがそれ以上アクセスされなければ、コンパイラは呼び出しを最適化することができるからです。 *これは古典的な方法で 'memset'関数を書いています。私はそれをエレガントで簡潔にしています。 – ouah

+0

Dowvoter(@ Daij-Djanでない場合)、あなたがdownvoted理由を説明してくれてありがとう。 – ouah

3

RtlSecureZeroMemory/SecureZeroMemory、メモリのブロックをゼロに機能するのMac OS Xと同等はありますが、コールは、コンパイラによって離れて最適化されないのだろうか?

最新バージョンの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; 
}