Browse Source

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.
OPENBSD_3_1
tdeval 23 years ago
parent
commit
d98536c135
2 changed files with 50 additions and 37 deletions
  1. +3
    -1
      src/lib/libc/stdlib/malloc.3
  2. +47
    -36
      src/lib/libc/stdlib/malloc.c

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

@ -34,7 +34,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.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 .Dd August 27, 1996
.Dt MALLOC 3 .Dt MALLOC 3
@ -79,6 +79,8 @@ If the space is of
or larger, the memory returned will be page-aligned. or larger, the memory returned will be page-aligned.
.Pp .Pp
Allocation of a zero size object returns a pointer to a zero size object. 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 .Pp
The The
.Fn calloc .Fn calloc


+ 47
- 36
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.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 */ #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__ */ #endif /* __OpenBSD__ */
#ifdef _THREAD_SAFE #ifdef _THREAD_SAFE
@ -164,7 +144,7 @@ struct pgfree {
#define MALLOC_MAGIC ((struct pginfo*) 4) #define MALLOC_MAGIC ((struct pginfo*) 4)
#ifndef malloc_pageshift #ifndef malloc_pageshift
#define malloc_pageshift 12U
#define malloc_pageshift (PGSHIFT)
#endif #endif
#ifndef malloc_minsize #ifndef malloc_minsize
@ -730,7 +710,13 @@ malloc_make_chunks(bits)
(((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS); (((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS);
/* Don't waste more than two chunks on this */ /* 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; bp = (struct pginfo *)pp;
} else { } else {
bp = (struct pginfo *)imalloc(l); bp = (struct pginfo *)imalloc(l);
@ -745,6 +731,16 @@ malloc_make_chunks(bits)
bp->total = bp->free = malloc_pagesize >> bits; bp->total = bp->free = malloc_pagesize >> bits;
bp->page = pp; 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 */ /* set all valid bits in the bitmap */
k = bp->total; k = bp->total;
i = 0; i = 0;
@ -792,14 +788,19 @@ malloc_bytes(size)
u_long *lp; u_long *lp;
/* Don't bother with anything less than this */ /* 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; size = malloc_minsize;
/* Find the right bucket */ /* 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 it's empty, make a page more of that size chunks */
if (!page_dir[j] && !malloc_make_chunks(j)) if (!page_dir[j] && !malloc_make_chunks(j))
@ -830,7 +831,7 @@ malloc_bytes(size)
k += (lp-bp->bits)*MALLOC_BITS; k += (lp-bp->bits)*MALLOC_BITS;
k <<= bp->shift; k <<= bp->shift;
if (malloc_junk)
if (malloc_junk && bp->shift != 0)
memset((char *)bp->page + k, SOME_JUNK, bp->size); memset((char *)bp->page + k, SOME_JUNK, bp->size);
return (u_char *)bp->page + k; return (u_char *)bp->page + k;
@ -955,10 +956,13 @@ irealloc(ptr, size)
if (p) { if (p) {
/* copy the lesser of the two sizes, and free the old one */ /* 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); ifree(ptr);
} }
return p; return p;
@ -1127,7 +1131,7 @@ free_bytes(ptr, index, info)
return; return;
} }
if (malloc_junk)
if (malloc_junk && info->shift != 0)
memset(ptr, SOME_JUNK, info->size); memset(ptr, SOME_JUNK, info->size);
info->bits[i/MALLOC_BITS] |= 1UL<<(i%MALLOC_BITS); 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 */ /* Free the page & the info structure if need be */
page_dir[ptr2index(info->page)] = MALLOC_FIRST; 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 ! */ vp = info->page; /* Order is important ! */
if(vp != (void*)info) if(vp != (void*)info)
ifree(info); ifree(info);


Loading…
Cancel
Save