clang/gcc优化密码变量清除功能

Mic*_*ael 5 c gcc clang

我们担心恶意程序会尝试从RAM中读取密码.所以我们写了一个函数来覆盖密码变量,然后释放它.我们担心的是像clang或gcc这样的智能编译器会优化这个函数中的代码.该函数将字符串中的每个字符更改为空字节,然后释放该变量.

void free_pword(char* pword) {
    char* pword_original = pword;
    char c;

    while ((c = *(pword++))) {
        *pword = '\0';
    }

    free(pword_original);
}
Run Code Online (Sandbox Code Playgroud)

现在我们的问题.我们需要这样做吗?如果没有,为什么?如果我们确实需要这样做,我们怎样才能确保覆盖不会被优化掉?

###########编辑1:(2015年2月11日)

来自未来的亲爱的人:这是我们到目前为止已经想到的......

我查看了原始汇编代码(来自gcc)以确定代码是否被优化掉了,事实并非如此.我决定添加volatile,以防优化器在更新中发生变化.

测试了gcc的版本.

$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
Run Code Online (Sandbox Code Playgroud)

我没有接受我自己的答案,因为我不是100%确定这对所有编译器都是安全的.编译专家可能会肯定地回答.

如果您需要像释放前那样安全地删除密码,请使用编译器测试此函数并查看原始程序集.您不必了解程序集,只需确保调用___bzero函数(memset)和_free函数.

目前的工作版本:

void free_pword(char * pword) {
    //instead of changing the argument to the function, I added a volatile variable
    //this was I don't have to change the calls to this function to remove warnings
    char volatile * volatile_pword = pword;
    memset((char *)volatile_pword, 0, strlen((char *)volatile_pword));
    free((char *)volatile_pword);
}
Run Code Online (Sandbox Code Playgroud)

nwe*_*hof 2

编译器完全有可能优化对away 的调用memset。这就是为什么有像memset_s(C11) 和explicit_bzero(BSD) 这样的函数可以安全地擦除内存块。

我还认为使用 易失性函数指针比转换为易失性指针更可靠:

void *(*volatile forced_memset)(void *, int, size_t) = memset;
Run Code Online (Sandbox Code Playgroud)

更多技巧,如插入语句或内存屏障,可以在musl 邮件列表上的asm这个很棒的帖子中找到。在那里您还可以找到这篇有趣的文章的链接,该文章介绍了如何便携式测试这些方法是否有效