On 19/02/2019 11:23, P J P wrote:
Hello,
-> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87210
This RFE is about providing gcc option(s) to eliminate information leakage
issues from programs. Information leakage via uninitialised memory has beena
chronic/recurring issue across all software. They are found quite often andmay
lead to severe effects if found in system software/kernel, OR an
applicationwhich handles sensitive information.
Various projects/efforts are underway to keep such information exposurefrom
happening
* STACKLEAK - http://lkml.iu.edu/hypermail/linux/kernel/1810.3/00522.html
* KLEAK - https://netbsd.org/gallery/presentations/maxv/kleak.pdf*
https://j00ru.vexillium.org/papers/2018/bochspwn_reloaded.pdf
But these are still external corrections to improve specific project
and/orsoftware. It does not help to fix/eliminate all information leakage
issues.
Automatic memory initialisation:
* https://lists.llvm.org/pipermail/cfe-dev/2018-November/060172.html
* https://reviews.llvm.org/D54604
It'd be immensely helpful and welcome if gcc(1) could provide compile/buildtime
options to enable/disable - automatic memory initialisation.
Could we please consider it as more viable/useful option?
Thank you.---
-P J P
http://feedmug.com
This strikes me as getting the issue completely backwards.
It is not lack of initialisation of stack variables that leads to
information leakage - it is a failure to clear the important data left
behind on the stack.
The problem with information leakage is when you have something like:
void foo(void) {
char key[20];
strcpy(key, "Top secret!");
usekey(&key);
memset(key, 0, sizeof(key)); // optimised away by DSE
}
void bar(void) {
foo();
char stolen_key[40]; // Covering "key" and other stack
steal_key(&stolen_key);
}
Forcing "stolen_key" to be zero initialised does not help anyone -
options for that just make code slower and hide errors that would occur
with other compiler options. The challenge is to make sure /key/ is
zeroed out after use - no matter what optimisations, and whether or not
the "memset" is called.
gcc already has mechanisms for handling this.
First, there is a way to tell gcc that something in memory will be read,
even though it doesn't look like it:
void foo(void) {
char key[20];
strcpy(key, "Top secret");
usekey(key);
memset(key, 0, sizeof(key));
{
typedef struct { char x[20]; } XS;
XS *p = (XS *) key;
asm("" : "+m" (*p));
}
}
Next, to automate the clearing of the key regardless of how and when the
function "foo" is exited and whether or not "memset" is called, we can
use the "cleanup" attribute:
static void clearKey(char (*key)[20]) {
memset(key, 0, 20);
{
typedef struct { char x[20]; } XS;
XS *p = (XS *) key;
asm("" : "+m" (*p));
}
}
void foo2(void) {
char key[20] __attribute__((cleanup(clearKey)));
strcpy(key, "Top secret");
usekey(key);
}
This stops information leakage where it should be stopped - once the
information is no longer used. Forcing initialisation of stack
variables would put it in the wrong place, when the stack space is reused.
And the code generated here is as good as it gets - no efficiency is lost.
So as far as I can see, gcc has all the bits it needs - it just needs a
nicer and simpler syntax. Something like an attribute "secure" which
will generate and use an appropriately sized zeroing function on scope
exit. Ideally, this could be attached to a type as well as a variable.
(I have no idea how simple or difficult this task might be.)