From d98536c1359a3673ad8cbb46bb2bb856ab6c0f84 Mon Sep 17 00:00:00 2001 From: tdeval <> Date: Tue, 30 Oct 2001 17:01:07 +0000 Subject: [PATCH] mprotect allocations sized at 0 bytes. This will cause a fault for access to such, permitting them to be discovered, instead of exploited as the ssh crc insertion detector was. Idea by theo, written by tdeval. --- src/lib/libc/stdlib/malloc.3 | 4 +- src/lib/libc/stdlib/malloc.c | 83 ++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/lib/libc/stdlib/malloc.3 b/src/lib/libc/stdlib/malloc.3 index e6566856..2f7e0c61 100644 --- a/src/lib/libc/stdlib/malloc.3 +++ b/src/lib/libc/stdlib/malloc.3 @@ -34,7 +34,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $OpenBSD: malloc.3,v 1.20 2000/10/25 15:23:15 aaron Exp $ +.\" $OpenBSD: malloc.3,v 1.21 2001/10/30 17:01:07 tdeval Exp $ .\" .Dd August 27, 1996 .Dt MALLOC 3 @@ -79,6 +79,8 @@ If the space is of or larger, the memory returned will be page-aligned. .Pp Allocation of a zero size object returns a pointer to a zero size object. +This zero size object is access protected, so any access to it will +generate an exception (SIGSEGV) .Pp The .Fn calloc diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index deef0864..3833bab5 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c @@ -8,7 +8,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$OpenBSD: malloc.c,v 1.42 2001/05/11 15:30:14 art Exp $"; +static char rcsid[] = "$OpenBSD: malloc.c,v 1.43 2001/10/30 17:01:07 tdeval Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -63,28 +63,8 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.42 2001/05/11 15:30:14 art Exp $"; * */ -#if defined(__i386__) && defined(__FreeBSD__) -# define malloc_pageshift 12U -# define malloc_minsize 16U -#endif /* __i386__ && __FreeBSD__ */ - -#if defined(__sparc__) && !defined(__OpenBSD__) -# define malloc_pageshift 12U -# define malloc_minsize 16U -# define MAP_ANON (0) -# define USE_DEV_ZERO -# define MADV_FREE MADV_DONTNEED -#endif /* __sparc__ */ - -/* Insert your combination here... */ -#if defined(__FOOCPU__) && defined(__BAROS__) -# define malloc_pageshift 12U -# define malloc_minsize 16U -#endif /* __FOOCPU__ && __BAROS__ */ - -#if defined(__OpenBSD__) && !defined(__sparc__) -# define malloc_pageshift (PGSHIFT) -# define malloc_minsize 16U +#if defined(__OpenBSD__) && defined(__sparc__) +# define malloc_pageshift 13U #endif /* __OpenBSD__ */ #ifdef _THREAD_SAFE @@ -164,7 +144,7 @@ struct pgfree { #define MALLOC_MAGIC ((struct pginfo*) 4) #ifndef malloc_pageshift -#define malloc_pageshift 12U +#define malloc_pageshift (PGSHIFT) #endif #ifndef malloc_minsize @@ -730,7 +710,13 @@ malloc_make_chunks(bits) (((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS); /* Don't waste more than two chunks on this */ - if ((1UL<<(bits)) <= l+l) { + /* + * If we are to allocate a memory protected page for the malloc(0) + * case (when bits=0), it must be from a different page than the + * pginfo page. + * --> Treat it like the big chunk alloc, get a second data page. + */ + if (bits != 0 && (1UL<<(bits)) <= l+l) { bp = (struct pginfo *)pp; } else { bp = (struct pginfo *)imalloc(l); @@ -745,6 +731,16 @@ malloc_make_chunks(bits) bp->total = bp->free = malloc_pagesize >> bits; bp->page = pp; + /* memory protect the page allocated in the malloc(0) case */ + if (bits == 0) { + k = mprotect(pp, malloc_pagesize, PROT_NONE); + if (k < 0) { + ifree(pp); + ifree(bp); + return 0; + } + } + /* set all valid bits in the bitmap */ k = bp->total; i = 0; @@ -792,14 +788,19 @@ malloc_bytes(size) u_long *lp; /* Don't bother with anything less than this */ - if (size < malloc_minsize) + /* unless we have a malloc(0) requests */ + if (size != 0 && size < malloc_minsize) size = malloc_minsize; /* Find the right bucket */ - j = 1; - i = size-1; - while (i >>= 1) - j++; + if (size == 0) + j=0; + else { + j = 1; + i = size-1; + while (i >>= 1) + j++; + } /* If it's empty, make a page more of that size chunks */ if (!page_dir[j] && !malloc_make_chunks(j)) @@ -830,7 +831,7 @@ malloc_bytes(size) k += (lp-bp->bits)*MALLOC_BITS; k <<= bp->shift; - if (malloc_junk) + if (malloc_junk && bp->shift != 0) memset((char *)bp->page + k, SOME_JUNK, bp->size); return (u_char *)bp->page + k; @@ -955,10 +956,13 @@ irealloc(ptr, size) if (p) { /* copy the lesser of the two sizes, and free the old one */ - if (osize < size) - memcpy(p, ptr, osize); - else - memcpy(p, ptr, size); + /* Don't move from/to 0 sized region !!! */ + if (osize != 1 && size != 0) { + if (osize < size) + memcpy(p, ptr, osize); + else + memcpy(p, ptr, size); + } ifree(ptr); } return p; @@ -1127,7 +1131,7 @@ free_bytes(ptr, index, info) return; } - if (malloc_junk) + if (malloc_junk && info->shift != 0) memset(ptr, SOME_JUNK, info->size); info->bits[i/MALLOC_BITS] |= 1UL<<(i%MALLOC_BITS); @@ -1163,6 +1167,13 @@ free_bytes(ptr, index, info) /* Free the page & the info structure if need be */ page_dir[ptr2index(info->page)] = MALLOC_FIRST; + + /* If the page was mprotected, unprotect it before releasing it */ + if (info->shift == 0) { + mprotect(info->page, malloc_pagesize, PROT_READ|PROT_WRITE); + /* Do we have to care if mprotect succeeds here ? */ + } + vp = info->page; /* Order is important ! */ if(vp != (void*)info) ifree(info);