diff options
Diffstat (limited to 'monitor_mm.c')
-rw-r--r-- | monitor_mm.c | 357 |
1 files changed, 0 insertions, 357 deletions
diff --git a/monitor_mm.c b/monitor_mm.c deleted file mode 100644 index aa47b2ed5..000000000 --- a/monitor_mm.c +++ /dev/null | |||
@@ -1,357 +0,0 @@ | |||
1 | /* $OpenBSD: monitor_mm.c,v 1.21 2015/02/06 23:21:59 millert Exp $ */ | ||
2 | /* | ||
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
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 the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | #include "includes.h" | ||
28 | |||
29 | #include <sys/types.h> | ||
30 | #ifdef HAVE_SYS_MMAN_H | ||
31 | #include <sys/mman.h> | ||
32 | #endif | ||
33 | #include "openbsd-compat/sys-tree.h" | ||
34 | |||
35 | #include <errno.h> | ||
36 | #include <stdarg.h> | ||
37 | #include <stddef.h> | ||
38 | #ifdef HAVE_STDINT_H | ||
39 | #include <stdint.h> | ||
40 | #endif | ||
41 | #include <stdlib.h> | ||
42 | #include <string.h> | ||
43 | |||
44 | #include "xmalloc.h" | ||
45 | #include "ssh.h" | ||
46 | #include "log.h" | ||
47 | #include "monitor_mm.h" | ||
48 | |||
49 | static int | ||
50 | mm_compare(struct mm_share *a, struct mm_share *b) | ||
51 | { | ||
52 | ptrdiff_t diff = (char *)a->address - (char *)b->address; | ||
53 | |||
54 | if (diff == 0) | ||
55 | return (0); | ||
56 | else if (diff < 0) | ||
57 | return (-1); | ||
58 | else | ||
59 | return (1); | ||
60 | } | ||
61 | |||
62 | RB_GENERATE(mmtree, mm_share, next, mm_compare) | ||
63 | |||
64 | static struct mm_share * | ||
65 | mm_make_entry(struct mm_master *mm, struct mmtree *head, | ||
66 | void *address, size_t size) | ||
67 | { | ||
68 | struct mm_share *tmp, *tmp2; | ||
69 | |||
70 | if (mm->mmalloc == NULL) | ||
71 | tmp = xcalloc(1, sizeof(struct mm_share)); | ||
72 | else | ||
73 | tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share)); | ||
74 | tmp->address = address; | ||
75 | tmp->size = size; | ||
76 | |||
77 | tmp2 = RB_INSERT(mmtree, head, tmp); | ||
78 | if (tmp2 != NULL) | ||
79 | fatal("mm_make_entry(%p): double address %p->%p(%zu)", | ||
80 | mm, tmp2, address, size); | ||
81 | |||
82 | return (tmp); | ||
83 | } | ||
84 | |||
85 | /* Creates a shared memory area of a certain size */ | ||
86 | |||
87 | struct mm_master * | ||
88 | mm_create(struct mm_master *mmalloc, size_t size) | ||
89 | { | ||
90 | void *address; | ||
91 | struct mm_master *mm; | ||
92 | |||
93 | if (mmalloc == NULL) | ||
94 | mm = xcalloc(1, sizeof(struct mm_master)); | ||
95 | else | ||
96 | mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); | ||
97 | |||
98 | /* | ||
99 | * If the memory map has a mm_master it can be completely | ||
100 | * shared including authentication between the child | ||
101 | * and the client. | ||
102 | */ | ||
103 | mm->mmalloc = mmalloc; | ||
104 | |||
105 | address = xmmap(size); | ||
106 | if (address == (void *)MAP_FAILED) | ||
107 | fatal("mmap(%zu): %s", size, strerror(errno)); | ||
108 | |||
109 | mm->address = address; | ||
110 | mm->size = size; | ||
111 | |||
112 | RB_INIT(&mm->rb_free); | ||
113 | RB_INIT(&mm->rb_allocated); | ||
114 | |||
115 | mm_make_entry(mm, &mm->rb_free, address, size); | ||
116 | |||
117 | return (mm); | ||
118 | } | ||
119 | |||
120 | /* Frees either the allocated or the free list */ | ||
121 | |||
122 | static void | ||
123 | mm_freelist(struct mm_master *mmalloc, struct mmtree *head) | ||
124 | { | ||
125 | struct mm_share *mms, *next; | ||
126 | |||
127 | for (mms = RB_ROOT(head); mms; mms = next) { | ||
128 | next = RB_NEXT(mmtree, head, mms); | ||
129 | RB_REMOVE(mmtree, head, mms); | ||
130 | if (mmalloc == NULL) | ||
131 | free(mms); | ||
132 | else | ||
133 | mm_free(mmalloc, mms); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* Destroys a memory mapped area */ | ||
138 | |||
139 | void | ||
140 | mm_destroy(struct mm_master *mm) | ||
141 | { | ||
142 | mm_freelist(mm->mmalloc, &mm->rb_free); | ||
143 | mm_freelist(mm->mmalloc, &mm->rb_allocated); | ||
144 | |||
145 | #ifdef HAVE_MMAP | ||
146 | if (munmap(mm->address, mm->size) == -1) | ||
147 | fatal("munmap(%p, %zu): %s", mm->address, mm->size, | ||
148 | strerror(errno)); | ||
149 | #else | ||
150 | fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported", | ||
151 | __func__); | ||
152 | #endif | ||
153 | if (mm->mmalloc == NULL) | ||
154 | free(mm); | ||
155 | else | ||
156 | mm_free(mm->mmalloc, mm); | ||
157 | } | ||
158 | |||
159 | void * | ||
160 | mm_xmalloc(struct mm_master *mm, size_t size) | ||
161 | { | ||
162 | void *address; | ||
163 | |||
164 | address = mm_malloc(mm, size); | ||
165 | if (address == NULL) | ||
166 | fatal("%s: mm_malloc(%zu)", __func__, size); | ||
167 | memset(address, 0, size); | ||
168 | return (address); | ||
169 | } | ||
170 | |||
171 | |||
172 | /* Allocates data from a memory mapped area */ | ||
173 | |||
174 | void * | ||
175 | mm_malloc(struct mm_master *mm, size_t size) | ||
176 | { | ||
177 | struct mm_share *mms, *tmp; | ||
178 | |||
179 | if (size == 0) | ||
180 | fatal("mm_malloc: try to allocate 0 space"); | ||
181 | if (size > SIZE_MAX - MM_MINSIZE + 1) | ||
182 | fatal("mm_malloc: size too big"); | ||
183 | |||
184 | size = ((size + (MM_MINSIZE - 1)) / MM_MINSIZE) * MM_MINSIZE; | ||
185 | |||
186 | RB_FOREACH(mms, mmtree, &mm->rb_free) { | ||
187 | if (mms->size >= size) | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | if (mms == NULL) | ||
192 | return (NULL); | ||
193 | |||
194 | /* Debug */ | ||
195 | memset(mms->address, 0xd0, size); | ||
196 | |||
197 | tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size); | ||
198 | |||
199 | /* Does not change order in RB tree */ | ||
200 | mms->size -= size; | ||
201 | mms->address = (char *)mms->address + size; | ||
202 | |||
203 | if (mms->size == 0) { | ||
204 | RB_REMOVE(mmtree, &mm->rb_free, mms); | ||
205 | if (mm->mmalloc == NULL) | ||
206 | free(mms); | ||
207 | else | ||
208 | mm_free(mm->mmalloc, mms); | ||
209 | } | ||
210 | |||
211 | return (tmp->address); | ||
212 | } | ||
213 | |||
214 | /* Frees memory in a memory mapped area */ | ||
215 | |||
216 | void | ||
217 | mm_free(struct mm_master *mm, void *address) | ||
218 | { | ||
219 | struct mm_share *mms, *prev, tmp; | ||
220 | |||
221 | tmp.address = address; | ||
222 | mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp); | ||
223 | if (mms == NULL) | ||
224 | fatal("mm_free(%p): can not find %p", mm, address); | ||
225 | |||
226 | /* Debug */ | ||
227 | memset(mms->address, 0xd0, mms->size); | ||
228 | |||
229 | /* Remove from allocated list and insert in free list */ | ||
230 | RB_REMOVE(mmtree, &mm->rb_allocated, mms); | ||
231 | if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL) | ||
232 | fatal("mm_free(%p): double address %p", mm, address); | ||
233 | |||
234 | /* Find previous entry */ | ||
235 | prev = mms; | ||
236 | if (RB_LEFT(prev, next)) { | ||
237 | prev = RB_LEFT(prev, next); | ||
238 | while (RB_RIGHT(prev, next)) | ||
239 | prev = RB_RIGHT(prev, next); | ||
240 | } else { | ||
241 | if (RB_PARENT(prev, next) && | ||
242 | (prev == RB_RIGHT(RB_PARENT(prev, next), next))) | ||
243 | prev = RB_PARENT(prev, next); | ||
244 | else { | ||
245 | while (RB_PARENT(prev, next) && | ||
246 | (prev == RB_LEFT(RB_PARENT(prev, next), next))) | ||
247 | prev = RB_PARENT(prev, next); | ||
248 | prev = RB_PARENT(prev, next); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | /* Check if range does not overlap */ | ||
253 | if (prev != NULL && MM_ADDRESS_END(prev) > address) | ||
254 | fatal("mm_free: memory corruption: %p(%zu) > %p", | ||
255 | prev->address, prev->size, address); | ||
256 | |||
257 | /* See if we can merge backwards */ | ||
258 | if (prev != NULL && MM_ADDRESS_END(prev) == address) { | ||
259 | prev->size += mms->size; | ||
260 | RB_REMOVE(mmtree, &mm->rb_free, mms); | ||
261 | if (mm->mmalloc == NULL) | ||
262 | free(mms); | ||
263 | else | ||
264 | mm_free(mm->mmalloc, mms); | ||
265 | } else | ||
266 | prev = mms; | ||
267 | |||
268 | if (prev == NULL) | ||
269 | return; | ||
270 | |||
271 | /* Check if we can merge forwards */ | ||
272 | mms = RB_NEXT(mmtree, &mm->rb_free, prev); | ||
273 | if (mms == NULL) | ||
274 | return; | ||
275 | |||
276 | if (MM_ADDRESS_END(prev) > mms->address) | ||
277 | fatal("mm_free: memory corruption: %p < %p(%zu)", | ||
278 | mms->address, prev->address, prev->size); | ||
279 | if (MM_ADDRESS_END(prev) != mms->address) | ||
280 | return; | ||
281 | |||
282 | prev->size += mms->size; | ||
283 | RB_REMOVE(mmtree, &mm->rb_free, mms); | ||
284 | |||
285 | if (mm->mmalloc == NULL) | ||
286 | free(mms); | ||
287 | else | ||
288 | mm_free(mm->mmalloc, mms); | ||
289 | } | ||
290 | |||
291 | static void | ||
292 | mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree, | ||
293 | struct mm_master *mm, struct mm_master *mmold) | ||
294 | { | ||
295 | struct mm_master *mmalloc = mm->mmalloc; | ||
296 | struct mm_share *mms, *new; | ||
297 | |||
298 | /* Sync free list */ | ||
299 | RB_FOREACH(mms, mmtree, oldtree) { | ||
300 | /* Check the values */ | ||
301 | mm_memvalid(mmold, mms, sizeof(struct mm_share)); | ||
302 | mm_memvalid(mm, mms->address, mms->size); | ||
303 | |||
304 | new = mm_xmalloc(mmalloc, sizeof(struct mm_share)); | ||
305 | memcpy(new, mms, sizeof(struct mm_share)); | ||
306 | RB_INSERT(mmtree, newtree, new); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | void | ||
311 | mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc) | ||
312 | { | ||
313 | struct mm_master *mm; | ||
314 | struct mm_master *mmalloc; | ||
315 | struct mm_master *mmold; | ||
316 | struct mmtree rb_free, rb_allocated; | ||
317 | |||
318 | debug3("%s: Share sync", __func__); | ||
319 | |||
320 | mm = *pmm; | ||
321 | mmold = mm->mmalloc; | ||
322 | mm_memvalid(mmold, mm, sizeof(*mm)); | ||
323 | |||
324 | mmalloc = mm_create(NULL, mm->size); | ||
325 | mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); | ||
326 | memcpy(mm, *pmm, sizeof(struct mm_master)); | ||
327 | mm->mmalloc = mmalloc; | ||
328 | |||
329 | rb_free = mm->rb_free; | ||
330 | rb_allocated = mm->rb_allocated; | ||
331 | |||
332 | RB_INIT(&mm->rb_free); | ||
333 | RB_INIT(&mm->rb_allocated); | ||
334 | |||
335 | mm_sync_list(&rb_free, &mm->rb_free, mm, mmold); | ||
336 | mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold); | ||
337 | |||
338 | mm_destroy(mmold); | ||
339 | |||
340 | *pmm = mm; | ||
341 | *pmmalloc = mmalloc; | ||
342 | |||
343 | debug3("%s: Share sync end", __func__); | ||
344 | } | ||
345 | |||
346 | void | ||
347 | mm_memvalid(struct mm_master *mm, void *address, size_t size) | ||
348 | { | ||
349 | void *end = (char *)address + size; | ||
350 | |||
351 | if (address < mm->address) | ||
352 | fatal("mm_memvalid: address too small: %p", address); | ||
353 | if (end < address) | ||
354 | fatal("mm_memvalid: end < address: %p < %p", end, address); | ||
355 | if (end > MM_ADDRESS_END(mm)) | ||
356 | fatal("mm_memvalid: address too large: %p", address); | ||
357 | } | ||