1155086Spjd/*- 2155086Spjd * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3155086Spjd * All rights reserved. 4155086Spjd * 5155086Spjd * Redistribution and use in source and binary forms, with or without 6155086Spjd * modification, are permitted provided that the following conditions 7155086Spjd * are met: 8155086Spjd * 1. Redistributions of source code must retain the above copyright 9155086Spjd * notice, this list of conditions and the following disclaimer. 10155086Spjd * 2. Redistributions in binary form must reproduce the above copyright 11155086Spjd * notice, this list of conditions and the following disclaimer in the 12155086Spjd * documentation and/or other materials provided with the distribution. 13155086Spjd * 14155086Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15155086Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16155086Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17155086Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18155086Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19155086Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20155086Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21155086Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22155086Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23155086Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24155086Spjd * SUCH DAMAGE. 25155086Spjd */ 26155086Spjd 27155086Spjd#include <sys/cdefs.h> 28155086Spjd__FBSDID("$FreeBSD$"); 29155086Spjd 30155086Spjd#include <sys/param.h> 31155086Spjd#include <sys/systm.h> 32155086Spjd#include <sys/kernel.h> 33155086Spjd#include <sys/stack.h> 34155086Spjd#include <sys/sysctl.h> 35155086Spjd 36155086Spjd#include <vm/redzone.h> 37155086Spjd 38155086Spjd 39227309Sedstatic SYSCTL_NODE(_vm, OID_AUTO, redzone, CTLFLAG_RW, NULL, "RedZone data"); 40155086Spjdstatic u_long redzone_extra_mem = 0; 41155086SpjdSYSCTL_ULONG(_vm_redzone, OID_AUTO, extra_mem, CTLFLAG_RD, &redzone_extra_mem, 42155086Spjd 0, "Extra memory allocated by redzone"); 43155086Spjdstatic int redzone_panic = 0; 44155086SpjdTUNABLE_INT("vm.redzone.panic", &redzone_panic); 45155086SpjdSYSCTL_INT(_vm_redzone, OID_AUTO, panic, CTLFLAG_RW, &redzone_panic, 0, 46155086Spjd "Panic when buffer corruption is detected"); 47155086Spjd 48155086Spjd#define REDZONE_CHSIZE (16) 49155086Spjd#define REDZONE_CFSIZE (16) 50155086Spjd#define REDZONE_HSIZE (sizeof(struct stack) + sizeof(u_long) + REDZONE_CHSIZE) 51155086Spjd#define REDZONE_FSIZE (REDZONE_CFSIZE) 52155086Spjd 53155086Spjdstatic u_long 54155086Spjdredzone_roundup(u_long n) 55155086Spjd{ 56155086Spjd 57181693Semaste if (n < REDZONE_HSIZE) 58181693Semaste n = REDZONE_HSIZE; 59155086Spjd if (n <= 128) 60155086Spjd return (128); 61155086Spjd else if (n <= 256) 62155086Spjd return (256); 63155086Spjd else if (n <= 512) 64155086Spjd return (512); 65155086Spjd else if (n <= 1024) 66155086Spjd return (1024); 67155086Spjd else if (n <= 2048) 68155086Spjd return (2048); 69155086Spjd return (PAGE_SIZE); 70155086Spjd} 71155086Spjd 72155086Spjdu_long 73155086Spjdredzone_get_size(caddr_t naddr) 74155086Spjd{ 75155086Spjd u_long nsize; 76155086Spjd 77155086Spjd bcopy(naddr - REDZONE_CHSIZE - sizeof(u_long), &nsize, sizeof(nsize)); 78155086Spjd return (nsize); 79155086Spjd} 80155086Spjd 81155086Spjdu_long 82155086Spjdredzone_size_ntor(u_long nsize) 83155086Spjd{ 84155086Spjd 85155086Spjd return (nsize + redzone_roundup(nsize) + REDZONE_FSIZE); 86155086Spjd} 87155086Spjd 88155086Spjdvoid * 89155086Spjdredzone_addr_ntor(caddr_t naddr) 90155086Spjd{ 91155086Spjd 92155086Spjd return (naddr - redzone_roundup(redzone_get_size(naddr))); 93155086Spjd} 94155086Spjd 95155086Spjd/* 96155086Spjd * Set redzones and remember allocation backtrace. 97155086Spjd */ 98155086Spjdvoid * 99155086Spjdredzone_setup(caddr_t raddr, u_long nsize) 100155086Spjd{ 101155086Spjd struct stack st; 102155086Spjd caddr_t haddr, faddr; 103155086Spjd 104155086Spjd atomic_add_long(&redzone_extra_mem, redzone_size_ntor(nsize) - nsize); 105155086Spjd 106155086Spjd haddr = raddr + redzone_roundup(nsize) - REDZONE_HSIZE; 107155086Spjd faddr = haddr + REDZONE_HSIZE + nsize; 108155086Spjd 109155086Spjd /* Redzone header. */ 110155086Spjd stack_save(&st); 111155086Spjd bcopy(&st, haddr, sizeof(st)); 112155086Spjd haddr += sizeof(st); 113155086Spjd bcopy(&nsize, haddr, sizeof(nsize)); 114155086Spjd haddr += sizeof(nsize); 115155086Spjd memset(haddr, 0x42, REDZONE_CHSIZE); 116155086Spjd haddr += REDZONE_CHSIZE; 117155086Spjd 118155086Spjd /* Redzone footer. */ 119155086Spjd memset(faddr, 0x42, REDZONE_CFSIZE); 120155086Spjd 121155086Spjd return (haddr); 122155086Spjd} 123155086Spjd 124155086Spjd/* 125155086Spjd * Verify redzones. 126155086Spjd * This function is called on free() and realloc(). 127155086Spjd */ 128155086Spjdvoid 129155086Spjdredzone_check(caddr_t naddr) 130155086Spjd{ 131155086Spjd struct stack ast, fst; 132155086Spjd caddr_t haddr, faddr; 133155086Spjd u_int ncorruptions; 134155086Spjd u_long nsize; 135155086Spjd int i; 136155086Spjd 137155086Spjd haddr = naddr - REDZONE_HSIZE; 138155086Spjd bcopy(haddr, &ast, sizeof(ast)); 139155086Spjd haddr += sizeof(ast); 140155086Spjd bcopy(haddr, &nsize, sizeof(nsize)); 141155086Spjd haddr += sizeof(nsize); 142155086Spjd 143155086Spjd atomic_subtract_long(&redzone_extra_mem, 144155086Spjd redzone_size_ntor(nsize) - nsize); 145155086Spjd 146155086Spjd /* Look for buffer underflow. */ 147155086Spjd ncorruptions = 0; 148155086Spjd for (i = 0; i < REDZONE_CHSIZE; i++, haddr++) { 149155086Spjd if (*(u_char *)haddr != 0x42) 150155086Spjd ncorruptions++; 151155086Spjd } 152155086Spjd if (ncorruptions > 0) { 153155086Spjd printf("REDZONE: Buffer underflow detected. %u byte%s " 154155086Spjd "corrupted before %p (%lu bytes allocated).\n", 155155086Spjd ncorruptions, ncorruptions == 1 ? "" : "s", naddr, nsize); 156155086Spjd printf("Allocation backtrace:\n"); 157174137Srwatson stack_print_ddb(&ast); 158155086Spjd printf("Free backtrace:\n"); 159155086Spjd stack_save(&fst); 160174137Srwatson stack_print_ddb(&fst); 161155086Spjd if (redzone_panic) 162155086Spjd panic("Stopping here."); 163155086Spjd } 164155086Spjd faddr = naddr + nsize; 165155086Spjd /* Look for buffer overflow. */ 166155086Spjd ncorruptions = 0; 167155086Spjd for (i = 0; i < REDZONE_CFSIZE; i++, faddr++) { 168155086Spjd if (*(u_char *)faddr != 0x42) 169155086Spjd ncorruptions++; 170155086Spjd } 171155086Spjd if (ncorruptions > 0) { 172155086Spjd printf("REDZONE: Buffer overflow detected. %u byte%s corrupted " 173155086Spjd "after %p (%lu bytes allocated).\n", ncorruptions, 174155086Spjd ncorruptions == 1 ? "" : "s", naddr + nsize, nsize); 175155086Spjd printf("Allocation backtrace:\n"); 176174137Srwatson stack_print_ddb(&ast); 177155086Spjd printf("Free backtrace:\n"); 178155086Spjd stack_save(&fst); 179174137Srwatson stack_print_ddb(&fst); 180155086Spjd if (redzone_panic) 181155086Spjd panic("Stopping here."); 182155086Spjd } 183155086Spjd} 184