1 /* 2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 #include <sys/types.h> 30 #include <sys/mman.h> 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <string.h> 34 35 #include "safe_mem.h" 36 37 struct safe_mem_hdr { 38 struct safe_mem_hdr *prev; 39 struct safe_mem_hdr *next; 40 struct safe_mem_tail *tail; 41 const char *file; 42 int line; 43 size_t alloc_sz; 44 char sig[8]; /* SAFEMEM */ 45 }; 46 47 struct safe_mem_tail { 48 char sig[8]; /* SAFEMEM */ 49 }; 50 51 static struct safe_mem_hdr *safe_mem_hdr_first = NULL; 52 53 #pragma weak _alloc_safe_mem 54 void * 55 _alloc_safe_mem(size_t req_sz, const char *file, int line) 56 { 57 struct safe_mem_hdr *hdr, *hdrp; 58 struct safe_mem_tail *tail; 59 size_t alloc_sz; 60 char *mem, *user_mem; 61 62 alloc_sz = req_sz + sizeof(*hdr) + sizeof(*tail); 63 if ((mem = malloc(alloc_sz)) == NULL) 64 return NULL; 65 66 if (mlock(mem, alloc_sz) < 0) { 67 free(mem); 68 return NULL; 69 } 70 71 memset(mem, 0, alloc_sz); 72 73 hdr = (struct safe_mem_hdr *)mem; 74 tail = (struct safe_mem_tail *)(mem + alloc_sz - sizeof(*tail)); 75 user_mem = mem + sizeof(*hdr); 76 77 strcpy(hdr->sig, "SAFEMEM"); 78 strcpy(tail->sig, "SAFEMEM"); 79 hdr->tail = tail; 80 hdr->alloc_sz = alloc_sz; 81 hdr->file = file; 82 hdr->line = line; 83 hdr->next = NULL; 84 85 if (safe_mem_hdr_first == NULL) { 86 safe_mem_hdr_first = hdr; 87 } else { 88 hdrp = safe_mem_hdr_first; 89 while (hdrp->next != NULL) 90 hdrp = hdrp->next; 91 hdr->prev = hdrp; 92 hdrp->next = hdr; 93 } 94 95 return user_mem; 96 } 97 98 #pragma weak _free_safe_mem 99 void 100 _free_safe_mem(void *mem_ptr, const char *file, int line) 101 { 102 struct safe_mem_hdr *hdr; 103 struct safe_mem_tail *tail; 104 size_t alloc_sz; 105 char *mem = mem_ptr; 106 107 mem -= sizeof(*hdr); 108 hdr = (struct safe_mem_hdr *)mem; 109 tail = (struct safe_mem_tail *)(mem + hdr->alloc_sz - sizeof(*tail)); 110 111 #ifdef DEBUG 112 fprintf(stderr, "freeing safe_mem (hdr): %#lx (%s:%d)\n", 113 (unsigned long)(void *)hdr, hdr->file, hdr->line); 114 #endif 115 116 if (hdr->alloc_sz == 0) { 117 fprintf(stderr, "BUG: double-free at %s:%d !!!\n", file, line); 118 return; 119 } 120 121 /* Integrity checks */ 122 if ((memcmp(hdr->sig, "SAFEMEM\0", 8) != 0) || 123 (memcmp(tail->sig, "SAFEMEM\0", 8) != 0)) { 124 fprintf(stderr, "BUG: safe_mem buffer under- or overflow at " 125 "%s:%d !!!\n", file, line); 126 return; 127 } 128 129 if (safe_mem_hdr_first == NULL) { 130 fprintf(stderr, "BUG: safe_mem list should not be empty at " 131 "%s:%d !!!\n", file, line); 132 return; 133 } 134 135 if (hdr->prev != NULL) 136 hdr->prev->next = hdr->next; 137 if (hdr->next != NULL) 138 hdr->next->prev = hdr->prev; 139 if (safe_mem_hdr_first == hdr) 140 safe_mem_hdr_first = hdr->next; 141 142 alloc_sz = hdr->alloc_sz; 143 memset(mem, 0xFF, alloc_sz); 144 memset(mem, 0, alloc_sz); 145 146 free(mem); 147 } 148 149 #pragma weak check_and_purge_safe_mem 150 void 151 check_and_purge_safe_mem(void) 152 { 153 struct safe_mem_hdr *hdr; 154 char *mem; 155 #ifdef DEBUG 156 int ok; 157 #endif 158 159 if (safe_mem_hdr_first == NULL) 160 return; 161 162 hdr = safe_mem_hdr_first; 163 while ((hdr = safe_mem_hdr_first) != NULL) { 164 #ifdef DEBUG 165 if ((hdr->alloc_sz > 0) && 166 (memcmp(hdr->sig, "SAFEMEM\0", 8) == 0) && 167 (memcmp(hdr->tail->sig, "SAFEMEM\0", 8) == 0)) 168 ok = 1; 169 else 170 ok = 0; 171 172 fprintf(stderr, "un-freed safe_mem: %#lx (%s:%d) [integrity=%s]\n", 173 (unsigned long)(void *)hdr, hdr->file, hdr->line, 174 ok? "ok" : "failed"); 175 #endif 176 mem = (void *)hdr; 177 mem += sizeof(*hdr); 178 _free_safe_mem(mem, "check_and_purge_safe_mem", 0); 179 } 180 } 181