1 /* $OpenBSD: monitor_mm.c,v 1.21 2015/02/06 23:21:59 millert Exp $ */
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_MMAN_H
33 #include "openbsd-compat/sys-tree.h"
47 #include "monitor_mm.h"
50 mm_compare(struct mm_share
*a
, struct mm_share
*b
)
52 ptrdiff_t diff
= (char *)a
->address
- (char *)b
->address
;
62 RB_GENERATE(mmtree
, mm_share
, next
, mm_compare
)
64 static struct mm_share
*
65 mm_make_entry(struct mm_master
*mm
, struct mmtree
*head
,
66 void *address
, size_t size
)
68 struct mm_share
*tmp
, *tmp2
;
70 if (mm
->mmalloc
== NULL
)
71 tmp
= xcalloc(1, sizeof(struct mm_share
));
73 tmp
= mm_xmalloc(mm
->mmalloc
, sizeof(struct mm_share
));
74 tmp
->address
= address
;
77 tmp2
= RB_INSERT(mmtree
, head
, tmp
);
79 fatal("mm_make_entry(%p): double address %p->%p(%zu)",
80 mm
, tmp2
, address
, size
);
85 /* Creates a shared memory area of a certain size */
88 mm_create(struct mm_master
*mmalloc
, size_t size
)
94 mm
= xcalloc(1, sizeof(struct mm_master
));
96 mm
= mm_xmalloc(mmalloc
, sizeof(struct mm_master
));
99 * If the memory map has a mm_master it can be completely
100 * shared including authentication between the child
103 mm
->mmalloc
= mmalloc
;
105 address
= xmmap(size
);
106 if (address
== (void *)MAP_FAILED
)
107 fatal("mmap(%zu): %s", size
, strerror(errno
));
109 mm
->address
= address
;
112 RB_INIT(&mm
->rb_free
);
113 RB_INIT(&mm
->rb_allocated
);
115 mm_make_entry(mm
, &mm
->rb_free
, address
, size
);
120 /* Frees either the allocated or the free list */
123 mm_freelist(struct mm_master
*mmalloc
, struct mmtree
*head
)
125 struct mm_share
*mms
, *next
;
127 for (mms
= RB_ROOT(head
); mms
; mms
= next
) {
128 next
= RB_NEXT(mmtree
, head
, mms
);
129 RB_REMOVE(mmtree
, head
, mms
);
133 mm_free(mmalloc
, mms
);
137 /* Destroys a memory mapped area */
140 mm_destroy(struct mm_master
*mm
)
142 mm_freelist(mm
->mmalloc
, &mm
->rb_free
);
143 mm_freelist(mm
->mmalloc
, &mm
->rb_allocated
);
146 if (munmap(mm
->address
, mm
->size
) == -1)
147 fatal("munmap(%p, %zu): %s", mm
->address
, mm
->size
,
150 fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported",
153 if (mm
->mmalloc
== NULL
)
156 mm_free(mm
->mmalloc
, mm
);
160 mm_xmalloc(struct mm_master
*mm
, size_t size
)
164 address
= mm_malloc(mm
, size
);
166 fatal("%s: mm_malloc(%zu)", __func__
, size
);
167 memset(address
, 0, size
);
172 /* Allocates data from a memory mapped area */
175 mm_malloc(struct mm_master
*mm
, size_t size
)
177 struct mm_share
*mms
, *tmp
;
180 fatal("mm_malloc: try to allocate 0 space");
181 if (size
> SIZE_MAX
- MM_MINSIZE
+ 1)
182 fatal("mm_malloc: size too big");
184 size
= ((size
+ (MM_MINSIZE
- 1)) / MM_MINSIZE
) * MM_MINSIZE
;
186 RB_FOREACH(mms
, mmtree
, &mm
->rb_free
) {
187 if (mms
->size
>= size
)
195 memset(mms
->address
, 0xd0, size
);
197 tmp
= mm_make_entry(mm
, &mm
->rb_allocated
, mms
->address
, size
);
199 /* Does not change order in RB tree */
201 mms
->address
= (char *)mms
->address
+ size
;
203 if (mms
->size
== 0) {
204 RB_REMOVE(mmtree
, &mm
->rb_free
, mms
);
205 if (mm
->mmalloc
== NULL
)
208 mm_free(mm
->mmalloc
, mms
);
211 return (tmp
->address
);
214 /* Frees memory in a memory mapped area */
217 mm_free(struct mm_master
*mm
, void *address
)
219 struct mm_share
*mms
, *prev
, tmp
;
221 tmp
.address
= address
;
222 mms
= RB_FIND(mmtree
, &mm
->rb_allocated
, &tmp
);
224 fatal("mm_free(%p): can not find %p", mm
, address
);
227 memset(mms
->address
, 0xd0, mms
->size
);
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
);
234 /* Find previous entry */
236 if (RB_LEFT(prev
, next
)) {
237 prev
= RB_LEFT(prev
, next
);
238 while (RB_RIGHT(prev
, next
))
239 prev
= RB_RIGHT(prev
, next
);
241 if (RB_PARENT(prev
, next
) &&
242 (prev
== RB_RIGHT(RB_PARENT(prev
, next
), next
)))
243 prev
= RB_PARENT(prev
, next
);
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
);
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
);
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
)
264 mm_free(mm
->mmalloc
, mms
);
271 /* Check if we can merge forwards */
272 mms
= RB_NEXT(mmtree
, &mm
->rb_free
, prev
);
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
)
282 prev
->size
+= mms
->size
;
283 RB_REMOVE(mmtree
, &mm
->rb_free
, mms
);
285 if (mm
->mmalloc
== NULL
)
288 mm_free(mm
->mmalloc
, mms
);
292 mm_sync_list(struct mmtree
*oldtree
, struct mmtree
*newtree
,
293 struct mm_master
*mm
, struct mm_master
*mmold
)
295 struct mm_master
*mmalloc
= mm
->mmalloc
;
296 struct mm_share
*mms
, *new;
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
);
304 new = mm_xmalloc(mmalloc
, sizeof(struct mm_share
));
305 memcpy(new, mms
, sizeof(struct mm_share
));
306 RB_INSERT(mmtree
, newtree
, new);
311 mm_share_sync(struct mm_master
**pmm
, struct mm_master
**pmmalloc
)
313 struct mm_master
*mm
;
314 struct mm_master
*mmalloc
;
315 struct mm_master
*mmold
;
316 struct mmtree rb_free
, rb_allocated
;
318 debug3("%s: Share sync", __func__
);
322 mm_memvalid(mmold
, mm
, sizeof(*mm
));
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
;
329 rb_free
= mm
->rb_free
;
330 rb_allocated
= mm
->rb_allocated
;
332 RB_INIT(&mm
->rb_free
);
333 RB_INIT(&mm
->rb_allocated
);
335 mm_sync_list(&rb_free
, &mm
->rb_free
, mm
, mmold
);
336 mm_sync_list(&rb_allocated
, &mm
->rb_allocated
, mm
, mmold
);
343 debug3("%s: Share sync end", __func__
);
347 mm_memvalid(struct mm_master
*mm
, void *address
, size_t size
)
349 void *end
= (char *)address
+ size
;
351 if (address
< mm
->address
)
352 fatal("mm_memvalid: address too small: %p", 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
);