Browse Source

by popular demand, malloc guard pages. insert an unreadable/unwriteable

page after each page size allocation to detect overrun.  this is
somewhat electric fence like, while attempting to be mostly usable in
production.  also, use tdeval's chunk randomization code.
enabled with the G option.
ok deraadt and co.
OPENBSD_3_5
tedu 21 years ago
parent
commit
b2f289ed65
2 changed files with 52 additions and 5 deletions
  1. +7
    -1
      src/lib/libc/stdlib/malloc.3
  2. +45
    -4
      src/lib/libc/stdlib/malloc.c

+ 7
- 1
src/lib/libc/stdlib/malloc.3 View File

@ -30,7 +30,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: malloc.3,v 1.31 2003/09/26 05:57:02 millert Exp $
.\" $OpenBSD: malloc.3,v 1.32 2003/10/16 17:05:04 tedu Exp $
.\" .\"
.Dd August 27, 1996 .Dd August 27, 1996
.Dt MALLOC 3 .Dt MALLOC 3
@ -193,6 +193,12 @@ at exit.
This option requires the library to have been compiled with -DMALLOC_STATS in This option requires the library to have been compiled with -DMALLOC_STATS in
order to have any effect. order to have any effect.
.Pp .Pp
.It Cm G
Enable guard pages and chunk randomization.
Each page size or larger allocation is followed by a guard page that will
cause a segmentation fault upon any access.
Smaller than page size chunks are returned in a random order.
.Pp
.It Cm J .It Cm J
.Dq Junk . .Dq Junk .
Fill some junk into the area allocated. Fill some junk into the area allocated.


+ 45
- 4
src/lib/libc/stdlib/malloc.c View File

@ -8,7 +8,7 @@
*/ */
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
static char rcsid[] = "$OpenBSD: malloc.c,v 1.63 2003/10/15 21:37:01 tedu Exp $";
static char rcsid[] = "$OpenBSD: malloc.c,v 1.64 2003/10/16 17:05:05 tedu Exp $";
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
/* /*
@ -193,6 +193,12 @@ static int malloc_silent;
/* always realloc ? */ /* always realloc ? */
static int malloc_realloc; static int malloc_realloc;
/* mprotect free pages PROT_NONE? */
static int malloc_freeprot;
/* use guard pages after allocations? */
static int malloc_guard = 0;
#if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE)) #if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE))
/* pass the kernel a hint on free pages ? */ /* pass the kernel a hint on free pages ? */
static int malloc_hint; static int malloc_hint;
@ -386,7 +392,7 @@ map_pages(size_t pages)
errno = ENOMEM; errno = ENOMEM;
return (NULL); return (NULL);
} }
tail = result + pages;
tail = result + pages + malloc_guard;
if (brk(tail) == (char *)-1) { if (brk(tail) == (char *)-1) {
#ifdef MALLOC_EXTRA_SANITY #ifdef MALLOC_EXTRA_SANITY
@ -394,6 +400,8 @@ map_pages(size_t pages)
#endif /* MALLOC_EXTRA_SANITY */ #endif /* MALLOC_EXTRA_SANITY */
return (NULL); return (NULL);
} }
if (malloc_guard)
mprotect(result + pages, malloc_pagesize, PROT_NONE);
last_index = ptr2index(tail) - 1; last_index = ptr2index(tail) - 1;
malloc_brk = tail; malloc_brk = tail;
@ -500,6 +508,10 @@ malloc_init(void)
case 'd': malloc_stats = 0; break; case 'd': malloc_stats = 0; break;
case 'D': malloc_stats = 1; break; case 'D': malloc_stats = 1; break;
#endif /* MALLOC_STATS */ #endif /* MALLOC_STATS */
case 'f': malloc_freeprot = 0; break;
case 'F': malloc_freeprot = 1; break;
case 'g': malloc_guard = 0; break;
case 'G': malloc_guard = malloc_pagesize; break;
#if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE)) #if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE))
case 'h': malloc_hint = 0; break; case 'h': malloc_hint = 0; break;
case 'H': malloc_hint = 1; break; case 'H': malloc_hint = 1; break;
@ -586,7 +598,7 @@ malloc_pages(size_t size)
struct pgfree *pf; struct pgfree *pf;
u_long index; u_long index;
size = pageround(size);
size = pageround(size) + malloc_guard;
p = NULL; p = NULL;
/* Look for free pages before asking for more */ /* Look for free pages before asking for more */
@ -627,11 +639,16 @@ malloc_pages(size_t size)
break; break;
} }
size -= malloc_guard;
#ifdef MALLOC_EXTRA_SANITY #ifdef MALLOC_EXTRA_SANITY
if (p != NULL && page_dir[ptr2index(p)] != MALLOC_FREE) if (p != NULL && page_dir[ptr2index(p)] != MALLOC_FREE)
wrterror("(ES): allocated non-free page on free-list\n"); wrterror("(ES): allocated non-free page on free-list\n");
#endif /* MALLOC_EXTRA_SANITY */ #endif /* MALLOC_EXTRA_SANITY */
if ((malloc_guard || malloc_freeprot) && p != NULL)
mprotect(p, size, PROT_READ|PROT_WRITE);
size >>= malloc_pageshift; size >>= malloc_pageshift;
/* Map new pages */ /* Map new pages */
@ -798,6 +815,26 @@ malloc_bytes(size_t size)
u += u; u += u;
k++; k++;
} }
if (malloc_guard) {
/* Walk to a random position. */
i = arc4random() % bp->free;
while (i > 0) {
u += u;
k++;
if (k >= MALLOC_BITS) {
lp++;
u = 1;
k = 0;
}
#ifdef MALLOC_EXTRA_SANITY
if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS)
wrterror("chunk overflow\n");
#endif /* MALLOC_EXTRA_SANITY */
if (*lp & u)
i--;
}
}
*lp ^= u; *lp ^= u;
/* If there are no more free, remove from free-list */ /* If there are no more free, remove from free-list */
@ -992,13 +1029,17 @@ free_pages(void *ptr, int index, struct pginfo *info)
madvise(ptr, l, MADV_FREE); madvise(ptr, l, MADV_FREE);
#endif #endif
l += malloc_guard;
tail = (char *)ptr+l; tail = (char *)ptr+l;
if (malloc_freeprot)
mprotect(ptr, tail - ptr, PROT_NONE);
/* add to free-list */ /* add to free-list */
if (px == NULL) if (px == NULL)
px = imalloc(sizeof *px); /* This cannot fail... */ px = imalloc(sizeof *px); /* This cannot fail... */
px->page = ptr; px->page = ptr;
px->end = tail;
px->end = tail;
px->size = l; px->size = l;
if (free_list.next == NULL) { if (free_list.next == NULL) {


Loading…
Cancel
Save