misc/124410: malloc exposes previously free'd memory
Rene Schickbauer
rene.schickbauer at magnapowertrain.com
Mon Jun 9 08:40:02 UTC 2008
>Number: 124410
>Category: misc
>Synopsis: malloc exposes previously free'd memory
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Mon Jun 09 08:40:01 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator: Rene Schickbauer
>Release: 7.0-stable
>Organization:
Magna Powertrain
>Environment:
FreeBSD magic3.magicbooks.org 7.0-STABLE FreeBSD 7.0-STABLE #1: Thu Mar 20 15:43:26 CET 2008 root at magic3.magicbooks.org:/usr/obj/usr/src/sys/MAGIC3 i386
>Description:
malloc() exposes memory content from previous malloc/memory operations/free cycles.
This can pose a security risk under certain circumstances. For example, a program generates a key, and forgets to memset() before it frees the memory. The memory contents (and the key) *may* be exposed on subsequent library calls or through unsafe network operations. E.g. this may expose security related data within a running process even after the process has "disposed" all of that data.
While the stand-alone risk may (or may not) be very low, this security leak may work in conjuction with other software bugs to create a deep security hole.
This especially the case, as many software developers seem to think that a free() disposes of the data.
>How-To-Repeat:
Source code of test program:
[cavac at magic3 ~/src/memtest]$ cat main.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NUM_SEGMENTS 10
#define SIZE_SEGMENTS 1000
int main() {
FILE *fh;
printf("Opening file...\n");
fh = fopen("test.dat", "wb");
if(!fh) {
fprintf(stderr, "Can't open file for writing!\n");
exit(1);
}
// Test malloc'ing multiple segments
printf("Test 1: Multiple segments\n");
void *mem[10];
for(int i=0; i < NUM_SEGMENTS; i++) {
printf(" %d / %d\n", i+1, NUM_SEGMENTS);
void *xmem = malloc(SIZE_SEGMENTS);
if(!xmem) {
fprintf(stderr, "Out of memory (or other malloc problem)!\n");
exit(2);
}
fwrite(xmem, SIZE_SEGMENTS, 1, fh);
mem[i] = xmem;
}
// Free mem again
for(int i=0; i < NUM_SEGMENTS; i++) {
free(mem[i]);
}
// Test malloc'ing multiple segments
printf("Test 2: malloc/free cycle with memset(mem,1,SIZE_SEGMENT)\nbefore free\n");
for(int i=0; i < NUM_SEGMENTS; i++) {
printf(" %d / %d\n", i+1, NUM_SEGMENTS);
void *mem = malloc(SIZE_SEGMENTS);
if(!mem) {
fprintf(stderr, "Out of memory (or other malloc problem)!\n");
exit(2);
}
fwrite(mem, SIZE_SEGMENTS, 1, fh);
memset(mem,1,SIZE_SEGMENTS);
free(mem);
}
printf("Closing file...\n");
fclose(fh);
printf("DONE\n");
}
Compile with:
g++ -o memtest main.cpp
And run as:
./memtest
This creates a file "test.dat", which holds all data that we got in "malloc()"
Then run "hexdump":
[cavac at magic3 ~/src/memtest]$ hexdump -C test.dat
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00002af0 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 |................|
00002b00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 |................|
*
00004e20
As shown by hexdump, it gives cleared memory on first malloc (test 1), but holds data (in test 2) previously written before free().
>Fix:
The safest fix would be to change free() to memset() the allocated memory before freeing it. Also, malloc() should memset() in all cases.
As this will decrease system performance, it should be configureable.
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list