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

Keane, Erich via cfe-dev cfe-dev at lists.llvm.org
Thu Jan 3 08:03:14 PST 2019


I do not know PPC assembly, however note that Godbolt WILL highlight (with color) which assembly is the result of each line of code. See here: https://godbolt.org/z/PNPK4G

I note that changing the mem-set value is altering the load-immeidate line that is currently "li 4, 0".  Perhaps this is just being inlined?
-----Original Message-----
From: cfe-dev [mailto:cfe-dev-bounces at lists.llvm.org] On Behalf Of myLC at gmx.de via cfe-dev
Sent: Thursday, January 3, 2019 7:48 AM
To: cfe-dev at lists.llvm.org
Subject: [cfe-dev] Security fail (memset being optimized away)

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

_______________________________________________
cfe-dev mailing list
cfe-dev at lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


More information about the cfe-dev mailing list