I have an struct variable which is passed like as follows:
//function definition
void function1(const Node* aVAR1)
{
Node* value=NULL;
.....
}
int main()
{
Node* aVAR=NULL;
aVAR=x.value;
function1(aVAR);
}
Here, when I run this in gdb, and step into function1()
, I see for variable aVAR
one temporary memory address is created.
GDB:
21 aVAR=x.value;
(gdb) p aVAR
$5 = (Node *) 0x654321
(gdb) n
Breakpoint 1, function1(aVAR1=0x7ffffffffebcdf ) at debug/../abc.c:12
12 {
(gdb) p aVAR1
$6 = (const Node *) 0x7ffffffffebcdf
For example,
0x654321
function1()
is not executed, aVAR1
is kept in some temporary address like 0x7ffffffffebcdf
.Node* value=NULL;
which is first instruction in the function1()
, the aVar1
's address is 0x654321
again.0x7ffffffffebcdf
) address is not cleaned up: even after the function exits, 0x7ffffffffebcdf
is not clearedI want 0x7ffffffffebcdf
to be cleared after function exits but that 0x7ffffffffebcdf
address does not have a pointer through which I can access this memory. Is there any option while linking in GCC through which I can prevent this?
If I add a malloc for aVAR and clear it later using memset and free, the problem gets resolved BUT logically when I see , I lose the reference to the memory block allocated by malloc() , and I won't be able to free() the allocated memory (causing memory leak ).
I want 0x7ffffffffebcdf to be cleared after function exits...
I have a limited imagination, but among the reasons I can imagine you want this is:
So, given [3] there are two choices; change your code to zero it before main returns; or change your main() to be mymain():
int mymain() {
Node* aVAR=NULL;
aVAR=x.value;
function1(aVAR);
return something;
}
void clearstack() {
int data[1000];
int fd;
if ((fd = open("/dev/zero", O_RDONLY)) != -1) {
read(fd, data, sizeof data);
close(fd);
}
}
int main() {
int r = mymain();
clearstack();
return r;
}
this works because the stack addresses will overlay between the two function calls, so your 0x7f-febcdf will land in the middle of data[]. The choir of implementation defined behaviour should be warming up now. but really, you would be better off with:
int mymain() {
Node* aVAR=NULL;
aVAR=x.value;
function1(aVAR);
aVAR = 0;
dummyfunction(&aVAR);
return aVAR == 0;
}
Note that by providing the address of aVAR to dummyfunction, you preturb the compilers ability to remove what it might consider useless. This sort of behavior is difficult to predict, however, because it binds your program source to whatever version of whatever compiler is at your disposal; not a great prospect.
If volatile had any sort of rigor in its definition, it would be useful here, but it hasn't.
A little better would be to use malloc() to acquire the variable, then you are bound by a contract that this is memory [ whereas a local variable could be register only ], and you can scrub it before freeing it. It would be at the outer reaches of unacceptable behavior for the compiler to optimize out the scrub. It still might leave data sitting in some registers, which might leak out.
All this said; if an attacker is really out for uncovering secrets that are plaintext in your program, you might not be able to stop them. They could start your program under a debugger or hypervisor, and inspect the data at will.
There are concepts in some modern processors where the cpu can construct a sort of enclave where secrets can be safely unwrapped; but there are many flaws. ARM TrustZone's Secure/Normal world vs. OS's kernel/user mode or x86's Ring0/1/2/3? has more info.