[cfe-dev] Security fail (memset being optimized away)

myLC@gmx.de via cfe-dev cfe-dev at lists.llvm.org
Thu Jan 3 07:47:32 PST 2019


A few days ago Ilja van Sprundel held a talk at the 35C3 (Chaos Computer Club
annual convention) calling it "Memsad - why clearing memory is hard".
It can be found here:

https://media.ccc.de/v/35c3-9788-memsad
or here:
https://www.youtube.com/watch?v=0WzjAKABSDk

The problem he described arises, when you have a buffer with sensitive content
(crypto key) and try to clear this from memory, before the buffer goes out of
scope:


#include <string.h>

void foo( int x ) {
     char buf[ 10 ];
     size_t i;
     for( i = 0; i < sizeof( buf ); ++i )
         buf[ i ] = x++;
// ...
     memset( buf, 0, sizeof( buf ) );	// rightfully removed by optimizer
}


He showed how this sort of code could be found in many implementations, thus
"leaking" sensitive information into memory (core dumps), which was intended
to be overwritten. He described the problematic of finding a portable solution
for a "forced memset".


Purely out of curiosity, this made me wonder about how to force the execution
of a function that would otherwise be optimized away - in a portable manner.
I came up with these unsophisticated lines:


#include <string.h>

void foo( int x ) {
     char buf[ 10 ];
     size_t i;
     for( i = 0; i < sizeof( buf ); ++i )
         buf[ i ] = x++;
// ...
     // Declare volvar as volatile pointer to function (void*, int, size_t ) returning void*:
     void* ( *volatile volvar )( void*, int, size_t ) = &memset;
     // Call memset from within this "black box":
     ( *volvar )( buf, 0, sizeof( buf ) );
}


The idea behind this is simple. "volvar" is a volatile variable. Therefore,
the compiler can make no assumptions on its contents at compile time. It
cannot remove the function call, which is based on that variable's content
(at that given time).

This code looks portable to me. I tested it on "Compiler Explorer"
( https://godbolt.org/ ). It compiles without warnings on all targets I
tested. Except for one, all contain the reference to memset and display the
call. The exception is the PowerPC platform in conjunction with CLANG
("power64le clang - trunk" and "powerpc64 clang - trunk". I'm guessing, that
this is running "some version" of memset (inlined?) as well, but references
to ".LC0 at toc@ha" and such leave me puzzled.


Without wanting to disturb too much, I'm asking about your opinion.
Is this solution portable?
Does it assure that the function call will not be optimized away?
And - does the CLANG PowerPC version work as well?


Thank you very much and a happy new year!
	LC



More information about the cfe-dev mailing list