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 30 #include <sys/types.h> 31 #include <sys/mman.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <string.h> 35 36 #include "tcplay.h" 37 38 struct safe_mem_hdr { 39 struct safe_mem_hdr *prev; 40 struct safe_mem_hdr *next; 41 struct safe_mem_tail *tail; 42 const char *file; 43 int line; 44 size_t alloc_sz; 45 char sig[8]; /* SAFEMEM */ 46 }; 47 48 struct safe_mem_tail { 49 char sig[8]; /* SAFEMEM */ 50 }; 51 52 static struct safe_mem_hdr *safe_mem_hdr_first = NULL; 53 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 void 99 _free_safe_mem(void *mem_ptr, const char *file, int line) 100 { 101 struct safe_mem_hdr *hdr; 102 struct safe_mem_tail *tail; 103 size_t alloc_sz; 104 char *mem = mem_ptr; 105 106 mem -= sizeof(*hdr); 107 hdr = (struct safe_mem_hdr *)mem; 108 tail = (struct safe_mem_tail *)(mem + hdr->alloc_sz - sizeof(*tail)); 109 110 #ifdef DEBUG 111 fprintf(stderr, "freeing safe_mem (hdr): %#lx (%s:%d)\n", 112 (unsigned long)(void *)hdr, hdr->file, hdr->line); 113 #endif 114 115 if (hdr->alloc_sz == 0) { 116 fprintf(stderr, "BUG: double-free at %s:%d !!!\n", file, line); 117 return; 118 } 119 120 /* Integrity checks */ 121 if ((memcmp(hdr->sig, "SAFEMEM\0", 8) != 0) || 122 (memcmp(tail->sig, "SAFEMEM\0", 8) != 0)) { 123 fprintf(stderr, "BUG: safe_mem buffer under- or overflow at " 124 "%s:%d !!!\n", file, line); 125 return; 126 } 127 128 if (safe_mem_hdr_first == NULL) { 129 fprintf(stderr, "BUG: safe_mem list should not be empty at " 130 "%s:%d !!!\n", file, line); 131 return; 132 } 133 134 if (hdr->prev != NULL) 135 hdr->prev->next = hdr->next; 136 if (hdr->next != NULL) 137 hdr->next->prev = hdr->prev; 138 if (safe_mem_hdr_first == hdr) 139 safe_mem_hdr_first = hdr->next; 140 141 alloc_sz = hdr->alloc_sz; 142 memset(mem, 0xFF, alloc_sz); 143 memset(mem, 0, alloc_sz); 144 145 free(mem); 146 } 147 148 void * 149 _strdup_safe_mem(const char *in, const char *file, int line) 150 { 151 char *out; 152 size_t sz; 153 154 sz = strlen(in)+1; 155 156 if ((out = _alloc_safe_mem(sz, file, line)) == NULL) { 157 return NULL; 158 } 159 160 memcpy(out, in, sz); 161 out[sz-1] = '\0'; 162 163 return out; 164 } 165 166 void 167 check_and_purge_safe_mem(void) 168 { 169 struct safe_mem_hdr *hdr; 170 char *mem; 171 #ifdef DEBUG 172 int ok; 173 #endif 174 175 if (safe_mem_hdr_first == NULL) 176 return; 177 178 hdr = safe_mem_hdr_first; 179 while ((hdr = safe_mem_hdr_first) != NULL) { 180 #ifdef DEBUG 181 if ((hdr->alloc_sz > 0) && 182 (memcmp(hdr->sig, "SAFEMEM\0", 8) == 0) && 183 (memcmp(hdr->tail->sig, "SAFEMEM\0", 8) == 0)) 184 ok = 1; 185 else 186 ok = 0; 187 188 fprintf(stderr, "un-freed safe_mem: %#lx (%s:%d) [integrity=%s]\n", 189 (unsigned long)(void *)hdr, hdr->file, hdr->line, 190 ok? "ok" : "failed"); 191 #endif 192 mem = (void *)hdr; 193 mem += sizeof(*hdr); 194 _free_safe_mem(mem, "check_and_purge_safe_mem", 0); 195 } 196 } 197