21.03.2013 Views

Problem - Kevin Tafuro

Problem - Kevin Tafuro

Problem - Kevin Tafuro

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

memory location will generally still have the unaltered data, up until the point where<br />

the memory manager reallocates the data and the program overwrites the value.<br />

Another pitfall is that functions like memset( ) may fail to wipe data because of compiler<br />

optimizations.<br />

Compiler writers have worked hard to implement optimizations into their compilers<br />

to help make code run faster (or compile to smaller machine code). Some of these<br />

optimizations can realize significant performance gains, but sometimes they also<br />

come at a cost. One such optimization is dead-code elimination, where the optimizer<br />

attempts to identify code that does nothing and eliminate it. Only relatively<br />

new compilers seem to implement this optimization; these include the current versions<br />

of GCC and Microsoft’s Visual C++ compiler, as well as some other less commonly<br />

used compilers.<br />

Unfortunately, this optimization can cause problems when writing secure code. Most<br />

commonly, code that “erases” a piece of memory that contains sensitive information<br />

such as a password or passphrase in plaintext is often eliminated by this optimization.<br />

As a result, the sensitive information is left in memory, providing an attacker a<br />

temptation that can be difficult to ignore.<br />

Functions like memset( ) do useful work, so why would dead-code elimination passes<br />

remove them? Many compilers implement such functions as built-ins, which means<br />

that the compiler has knowledge of what the function does. In addition, situations in<br />

which such calls would be eliminated are restricted to times when the compiler can<br />

be sure that the data written by these functions is never read again. For example:<br />

int get_and_verify_password(char *real_password) {<br />

int result;<br />

char *user_password[64];<br />

/* WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING<br />

*<br />

* This is an example of unsafe code. In particular, note the use of memset( ),<br />

* which is exactly what we are discussing as being a problem in this recipe.<br />

*/<br />

get_password_from_user_somehow(user_password, sizeof(user_password));<br />

result = !strcmp(user_password, real_password);<br />

memset(user_password, 0, strlen(user_password));<br />

return result;<br />

}<br />

In this example, the variable user_password exists solely within the function get_and_<br />

verify_password( ). After the memset( ), it’s never used again, and because memset( )<br />

only writes the data, the compiler can “safely” remove it.<br />

Several solutions to this particular problem exist, but the code that we’ve provided<br />

here is the most correct when used with a compiler that conforms to at least the<br />

Erasing Data from Memory Securely | 705<br />

This is the Title of the Book, eMatter Edition<br />

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!