xref: /dragonfly/sbin/cryptdisks/safe_mem.c (revision 8accc937)
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 void *
54 _alloc_safe_mem(size_t req_sz, const char *file, int line)
55 {
56 	struct safe_mem_hdr *hdr, *hdrp;
57 	struct safe_mem_tail *tail;
58 	size_t alloc_sz;
59 	char *mem, *user_mem;
60 
61 	alloc_sz = req_sz + sizeof(*hdr) + sizeof(*tail);
62 	if ((mem = malloc(alloc_sz)) == NULL)
63 		return NULL;
64 
65 	if (mlock(mem, alloc_sz) < 0) {
66 		free(mem);
67 		return NULL;
68 	}
69 
70 	memset(mem, 0, alloc_sz);
71 
72 	hdr = (struct safe_mem_hdr *)mem;
73 	tail = (struct safe_mem_tail *)(mem + alloc_sz - sizeof(*tail));
74 	user_mem = mem + sizeof(*hdr);
75 
76 	strcpy(hdr->sig, "SAFEMEM");
77 	strcpy(tail->sig, "SAFEMEM");
78 	hdr->tail = tail;
79 	hdr->alloc_sz = alloc_sz;
80 	hdr->file = file;
81 	hdr->line = line;
82 	hdr->next = NULL;
83 
84 	if (safe_mem_hdr_first == NULL) {
85 		safe_mem_hdr_first = hdr;
86 	} else {
87 		hdrp = safe_mem_hdr_first;
88 		while (hdrp->next != NULL)
89 			hdrp = hdrp->next;
90 		hdr->prev = hdrp;
91 		hdrp->next = hdr;
92 	}
93 
94 	return user_mem;
95 }
96 
97 void
98 _free_safe_mem(void *mem_ptr, const char *file, int line)
99 {
100 	struct safe_mem_hdr *hdr;
101 	struct safe_mem_tail *tail;
102 	size_t alloc_sz;
103 	char *mem = mem_ptr;
104 
105 	mem -= sizeof(*hdr);
106 	hdr = (struct safe_mem_hdr *)mem;
107 	tail = (struct safe_mem_tail *)(mem + hdr->alloc_sz - sizeof(*tail));
108 
109 #ifdef DEBUG
110 	fprintf(stderr, "freeing safe_mem (hdr): %#lx (%s:%d)\n",
111 		    (unsigned long)(void *)hdr, hdr->file, hdr->line);
112 #endif
113 
114 	if (hdr->alloc_sz == 0) {
115 		fprintf(stderr, "BUG: double-free at %s:%d !!!\n", file, line);
116 		return;
117 	}
118 
119 	/* Integrity checks */
120 	if ((memcmp(hdr->sig, "SAFEMEM\0", 8) != 0) ||
121 	    (memcmp(tail->sig, "SAFEMEM\0", 8) != 0)) {
122 		fprintf(stderr, "BUG: safe_mem buffer under- or overflow at "
123 		    "%s:%d !!!\n", file, line);
124 		return;
125 	}
126 
127 	if (safe_mem_hdr_first == NULL) {
128 		fprintf(stderr, "BUG: safe_mem list should not be empty at "
129 		    "%s:%d !!!\n", file, line);
130 		return;
131 	}
132 
133 	if (hdr->prev != NULL)
134 		hdr->prev->next = hdr->next;
135 	if (hdr->next != NULL)
136 		hdr->next->prev = hdr->prev;
137 	if (safe_mem_hdr_first == hdr)
138 		safe_mem_hdr_first = hdr->next;
139 
140 	alloc_sz = hdr->alloc_sz;
141 	memset(mem, 0xFF, alloc_sz);
142 	memset(mem, 0, alloc_sz);
143 
144 	free(mem);
145 }
146 
147 void
148 check_and_purge_safe_mem(void)
149 {
150 	struct safe_mem_hdr *hdr;
151 	char *mem;
152 #ifdef DEBUG
153 	int ok;
154 #endif
155 
156 	if (safe_mem_hdr_first == NULL)
157 		return;
158 
159 	hdr = safe_mem_hdr_first;
160 	while ((hdr = safe_mem_hdr_first) != NULL) {
161 #ifdef DEBUG
162 		if ((hdr->alloc_sz > 0) &&
163 		    (memcmp(hdr->sig, "SAFEMEM\0", 8) == 0) &&
164 		    (memcmp(hdr->tail->sig, "SAFEMEM\0", 8) == 0))
165 			ok = 1;
166 		else
167 			ok = 0;
168 
169 		fprintf(stderr, "un-freed safe_mem: %#lx (%s:%d) [integrity=%s]\n",
170 		    (unsigned long)(void *)hdr, hdr->file, hdr->line,
171 		    ok? "ok" : "failed");
172 #endif
173 		mem = (void *)hdr;
174 		mem += sizeof(*hdr);
175 		_free_safe_mem(mem, "check_and_purge_safe_mem", 0);
176 	}
177 }
178