Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/redzone.c
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
SYSCTL_ULONG(_vm_redzone, OID_AUTO, extra_mem, CTLFLAG_RD, &redzone_extra_mem, | SYSCTL_ULONG(_vm_redzone, OID_AUTO, extra_mem, CTLFLAG_RD, &redzone_extra_mem, | ||||
0, "Extra memory allocated by redzone"); | 0, "Extra memory allocated by redzone"); | ||||
static int redzone_panic = 0; | static int redzone_panic = 0; | ||||
SYSCTL_INT(_vm_redzone, OID_AUTO, panic, CTLFLAG_RWTUN, &redzone_panic, 0, | SYSCTL_INT(_vm_redzone, OID_AUTO, panic, CTLFLAG_RWTUN, &redzone_panic, 0, | ||||
"Panic when buffer corruption is detected"); | "Panic when buffer corruption is detected"); | ||||
#define REDZONE_CHSIZE (16) | #define REDZONE_CHSIZE (16) | ||||
#define REDZONE_CFSIZE (16) | #define REDZONE_CFSIZE (16) | ||||
#define REDZONE_HSIZE (sizeof(struct stack) + sizeof(u_long) + REDZONE_CHSIZE) | #define REDZONE_HSIZE (sizeof(struct stack) + sizeof(u_long) + \ | ||||
sizeof(void *) + REDZONE_CHSIZE) | |||||
#define REDZONE_FSIZE (REDZONE_CFSIZE) | #define REDZONE_FSIZE (REDZONE_CFSIZE) | ||||
static u_long | static u_long | ||||
redzone_roundup(u_long n) | redzone_roundup(u_long n) | ||||
{ | { | ||||
if (n < REDZONE_HSIZE) | if (n < REDZONE_HSIZE) | ||||
n = REDZONE_HSIZE; | n = REDZONE_HSIZE; | ||||
Show All 10 Lines | redzone_roundup(u_long n) | ||||
return (PAGE_SIZE); | return (PAGE_SIZE); | ||||
} | } | ||||
u_long | u_long | ||||
redzone_get_size(caddr_t naddr) | redzone_get_size(caddr_t naddr) | ||||
{ | { | ||||
u_long nsize; | u_long nsize; | ||||
bcopy(naddr - REDZONE_CHSIZE - sizeof(u_long), &nsize, sizeof(nsize)); | bcopy(naddr - (REDZONE_CHSIZE + sizeof(void *) + sizeof(u_long)), | ||||
&nsize, sizeof(nsize)); | |||||
return (nsize); | return (nsize); | ||||
} | } | ||||
u_long | u_long | ||||
redzone_size_ntor(u_long nsize) | redzone_size_ntor(u_long nsize) | ||||
{ | { | ||||
return (nsize + redzone_roundup(nsize) + REDZONE_FSIZE); | return (nsize + redzone_roundup(nsize) + REDZONE_FSIZE); | ||||
} | } | ||||
void * | void * | ||||
redzone_addr_ntor(caddr_t naddr) | redzone_addr_ntor(caddr_t naddr) | ||||
{ | { | ||||
return (naddr - redzone_roundup(redzone_get_size(naddr))); | return (naddr - redzone_roundup(redzone_get_size(naddr))); | ||||
} | } | ||||
/* | /* | ||||
* Set redzones and remember allocation backtrace. | * Set redzones and remember allocation backtrace. | ||||
*/ | */ | ||||
void * | void * | ||||
redzone_setup(caddr_t raddr, u_long nsize) | redzone_setup(caddr_t raddr, u_long nsize, const void *ctx) | ||||
{ | { | ||||
struct stack st; | struct stack st; | ||||
caddr_t haddr, faddr; | caddr_t haddr, faddr; | ||||
atomic_add_long(&redzone_extra_mem, redzone_size_ntor(nsize) - nsize); | atomic_add_long(&redzone_extra_mem, redzone_size_ntor(nsize) - nsize); | ||||
haddr = raddr + redzone_roundup(nsize) - REDZONE_HSIZE; | haddr = raddr + redzone_roundup(nsize) - REDZONE_HSIZE; | ||||
faddr = haddr + REDZONE_HSIZE + nsize; | faddr = haddr + REDZONE_HSIZE + nsize; | ||||
/* Redzone header. */ | /* Redzone header. */ | ||||
stack_save(&st); | stack_save(&st); | ||||
bcopy(&st, haddr, sizeof(st)); | bcopy(&st, haddr, sizeof(st)); | ||||
haddr += sizeof(st); | haddr += sizeof(st); | ||||
bcopy(&nsize, haddr, sizeof(nsize)); | bcopy(&nsize, haddr, sizeof(nsize)); | ||||
haddr += sizeof(nsize); | haddr += sizeof(nsize); | ||||
bcopy(&ctx, haddr, sizeof(ctx)); | |||||
haddr += sizeof(ctx); | |||||
memset(haddr, 0x42, REDZONE_CHSIZE); | memset(haddr, 0x42, REDZONE_CHSIZE); | ||||
haddr += REDZONE_CHSIZE; | haddr += REDZONE_CHSIZE; | ||||
/* Redzone footer. */ | /* Redzone footer. */ | ||||
memset(faddr, 0x42, REDZONE_CFSIZE); | memset(faddr, 0x42, REDZONE_CFSIZE); | ||||
return (haddr); | return (haddr); | ||||
} | } | ||||
/* | /* | ||||
* Verify redzones. | * Verify redzones. | ||||
* This function is called on free() and realloc(). | * This function is called on free() and realloc(). | ||||
*/ | */ | ||||
void | void | ||||
redzone_check(caddr_t naddr) | redzone_check(caddr_t naddr, const void *ctx) | ||||
{ | { | ||||
struct stack ast, fst; | struct stack ast, fst; | ||||
const void *actx; | |||||
caddr_t haddr, faddr; | caddr_t haddr, faddr; | ||||
u_int ncorruptions; | u_int ncorruptions, total; | ||||
u_long nsize; | u_long nsize; | ||||
int i; | int i; | ||||
total = 0; | |||||
haddr = naddr - REDZONE_HSIZE; | haddr = naddr - REDZONE_HSIZE; | ||||
bcopy(haddr, &ast, sizeof(ast)); | bcopy(haddr, &ast, sizeof(ast)); | ||||
haddr += sizeof(ast); | haddr += sizeof(ast); | ||||
bcopy(haddr, &nsize, sizeof(nsize)); | bcopy(haddr, &nsize, sizeof(nsize)); | ||||
haddr += sizeof(nsize); | haddr += sizeof(nsize); | ||||
bcopy(haddr, &actx, sizeof(actx)); | |||||
haddr += sizeof(actx); | |||||
atomic_subtract_long(&redzone_extra_mem, | atomic_subtract_long(&redzone_extra_mem, | ||||
redzone_size_ntor(nsize) - nsize); | redzone_size_ntor(nsize) - nsize); | ||||
/* Check for context match. */ | |||||
if (ctx != actx) { | |||||
printf("REDZONE: Context mismatch. alloc=%p, free=%p\n", actx, | |||||
ctx); | |||||
total++; | |||||
} | |||||
/* Look for buffer underflow. */ | /* Look for buffer underflow. */ | ||||
ncorruptions = 0; | ncorruptions = 0; | ||||
for (i = 0; i < REDZONE_CHSIZE; i++, haddr++) { | for (i = 0; i < REDZONE_CHSIZE; i++, haddr++) { | ||||
if (*(u_char *)haddr != 0x42) | if (*(u_char *)haddr != 0x42) | ||||
ncorruptions++; | ncorruptions++; | ||||
} | } | ||||
if (ncorruptions > 0) { | if (ncorruptions > 0) | ||||
printf("REDZONE: Buffer underflow detected. %u byte%s " | printf("REDZONE: Buffer underflow detected. %u byte%s " | ||||
"corrupted before %p (%lu bytes allocated).\n", | "corrupted before %p (%lu bytes allocated).\n", | ||||
ncorruptions, ncorruptions == 1 ? "" : "s", naddr, nsize); | ncorruptions, ncorruptions == 1 ? "" : "s", naddr, nsize); | ||||
printf("Allocation backtrace:\n"); | total += ncorruptions; | ||||
stack_print_ddb(&ast); | |||||
printf("Free backtrace:\n"); | |||||
stack_save(&fst); | |||||
stack_print_ddb(&fst); | |||||
if (redzone_panic) | |||||
panic("Stopping here."); | |||||
} | |||||
faddr = naddr + nsize; | faddr = naddr + nsize; | ||||
/* Look for buffer overflow. */ | /* Look for buffer overflow. */ | ||||
ncorruptions = 0; | ncorruptions = 0; | ||||
for (i = 0; i < REDZONE_CFSIZE; i++, faddr++) { | for (i = 0; i < REDZONE_CFSIZE; i++, faddr++) { | ||||
if (*(u_char *)faddr != 0x42) | if (*(u_char *)faddr != 0x42) | ||||
ncorruptions++; | ncorruptions++; | ||||
} | } | ||||
if (ncorruptions > 0) { | if (ncorruptions > 0) | ||||
printf("REDZONE: Buffer overflow detected. %u byte%s corrupted " | printf("REDZONE: Buffer overflow detected. %u byte%s corrupted " | ||||
"after %p (%lu bytes allocated).\n", ncorruptions, | "after %p (%lu bytes allocated).\n", ncorruptions, | ||||
ncorruptions == 1 ? "" : "s", naddr + nsize, nsize); | ncorruptions == 1 ? "" : "s", naddr + nsize, nsize); | ||||
total += ncorruptions; | |||||
if (total > 0) { | |||||
printf("Allocation backtrace:\n"); | printf("Allocation backtrace:\n"); | ||||
stack_print_ddb(&ast); | stack_print_ddb(&ast); | ||||
printf("Free backtrace:\n"); | printf("Free backtrace:\n"); | ||||
stack_save(&fst); | stack_save(&fst); | ||||
stack_print_ddb(&fst); | stack_print_ddb(&fst); | ||||
if (redzone_panic) | if (redzone_panic) | ||||
panic("Stopping here."); | panic("Stopping here."); | ||||
} | } | ||||
} | } |