Line data Source code
1 : /* secmem.c - memory allocation from a secure heap
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3 : * 2003, 2007 Free Software Foundation, Inc.
4 : * Copyright (C) 2013 g10 Code GmbH
5 : *
6 : * This file is part of Libgcrypt.
7 : *
8 : * Libgcrypt is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU Lesser general Public License as
10 : * published by the Free Software Foundation; either version 2.1 of
11 : * the License, or (at your option) any later version.
12 : *
13 : * Libgcrypt is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU Lesser General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU Lesser General Public
19 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include <config.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <errno.h>
27 : #include <stdarg.h>
28 : #include <unistd.h>
29 : #include <stddef.h>
30 :
31 : #if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
32 : #include <sys/mman.h>
33 : #include <sys/types.h>
34 : #include <fcntl.h>
35 : #ifdef USE_CAPABILITIES
36 : #include <sys/capability.h>
37 : #endif
38 : #endif
39 :
40 : #include "g10lib.h"
41 : #include "secmem.h"
42 :
43 : #if defined (MAP_ANON) && ! defined (MAP_ANONYMOUS)
44 : #define MAP_ANONYMOUS MAP_ANON
45 : #endif
46 :
47 : #define MINIMUM_POOL_SIZE 16384
48 : #define STANDARD_POOL_SIZE 32768
49 : #define DEFAULT_PAGE_SIZE 4096
50 :
51 : typedef struct memblock
52 : {
53 : unsigned size; /* Size of the memory available to the
54 : user. */
55 : int flags; /* See below. */
56 : PROPERLY_ALIGNED_TYPE aligned;
57 : } memblock_t;
58 :
59 : /* This flag specifies that the memory block is in use. */
60 : #define MB_FLAG_ACTIVE (1 << 0)
61 :
62 : /* The pool of secure memory. */
63 : static void *pool;
64 :
65 : /* Size of POOL in bytes. */
66 : static size_t pool_size;
67 :
68 : /* True, if the memory pool is ready for use. May be checked in an
69 : atexit function. */
70 : static volatile int pool_okay;
71 :
72 : /* True, if the memory pool is mmapped. */
73 : static volatile int pool_is_mmapped;
74 :
75 : /* FIXME? */
76 : static int disable_secmem;
77 : static int show_warning;
78 : static int not_locked;
79 : static int no_warning;
80 : static int suspend_warning;
81 : static int no_mlock;
82 : static int no_priv_drop;
83 :
84 : /* Stats. */
85 : static unsigned int cur_alloced, cur_blocks;
86 :
87 : /* Lock protecting accesses to the memory pool. */
88 : GPGRT_LOCK_DEFINE (secmem_lock);
89 :
90 : /* Convenient macros. */
91 : #define SECMEM_LOCK gpgrt_lock_lock (&secmem_lock)
92 : #define SECMEM_UNLOCK gpgrt_lock_unlock (&secmem_lock)
93 :
94 : /* The size of the memblock structure; this does not include the
95 : memory that is available to the user. */
96 : #define BLOCK_HEAD_SIZE \
97 : offsetof (memblock_t, aligned)
98 :
99 : /* Convert an address into the according memory block structure. */
100 : #define ADDR_TO_BLOCK(addr) \
101 : (memblock_t *) (void *) ((char *) addr - BLOCK_HEAD_SIZE)
102 :
103 : /* Check whether P points into the pool. */
104 : static int
105 932 : ptr_into_pool_p (const void *p)
106 : {
107 : /* We need to convert pointers to addresses. This is required by
108 : C-99 6.5.8 to avoid undefined behaviour. See also
109 : http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
110 : */
111 932 : uintptr_t p_addr = (uintptr_t)p;
112 932 : uintptr_t pool_addr = (uintptr_t)pool;
113 :
114 932 : return p_addr >= pool_addr && p_addr < pool_addr + pool_size;
115 : }
116 :
117 : /* Update the stats. */
118 : static void
119 5 : stats_update (size_t add, size_t sub)
120 : {
121 5 : if (add)
122 : {
123 3 : cur_alloced += add;
124 3 : cur_blocks++;
125 : }
126 5 : if (sub)
127 : {
128 2 : cur_alloced -= sub;
129 2 : cur_blocks--;
130 : }
131 5 : }
132 :
133 : /* Return the block following MB or NULL, if MB is the last block. */
134 : static memblock_t *
135 14 : mb_get_next (memblock_t *mb)
136 : {
137 : memblock_t *mb_next;
138 :
139 14 : mb_next = (memblock_t *) (void *) ((char *) mb + BLOCK_HEAD_SIZE + mb->size);
140 :
141 14 : if (! ptr_into_pool_p (mb_next))
142 3 : mb_next = NULL;
143 :
144 14 : return mb_next;
145 : }
146 :
147 : /* Return the block preceding MB or NULL, if MB is the first
148 : block. */
149 : static memblock_t *
150 5 : mb_get_prev (memblock_t *mb)
151 : {
152 : memblock_t *mb_prev, *mb_next;
153 :
154 5 : if (mb == pool)
155 0 : mb_prev = NULL;
156 : else
157 : {
158 5 : mb_prev = (memblock_t *) pool;
159 : while (1)
160 : {
161 7 : mb_next = mb_get_next (mb_prev);
162 7 : if (mb_next == mb)
163 5 : break;
164 : else
165 2 : mb_prev = mb_next;
166 2 : }
167 : }
168 :
169 5 : return mb_prev;
170 : }
171 :
172 : /* If the preceding block of MB and/or the following block of MB
173 : exist and are not active, merge them to form a bigger block. */
174 : static void
175 5 : mb_merge (memblock_t *mb)
176 : {
177 : memblock_t *mb_prev, *mb_next;
178 :
179 5 : mb_prev = mb_get_prev (mb);
180 5 : mb_next = mb_get_next (mb);
181 :
182 5 : if (mb_prev && (! (mb_prev->flags & MB_FLAG_ACTIVE)))
183 : {
184 0 : mb_prev->size += BLOCK_HEAD_SIZE + mb->size;
185 0 : mb = mb_prev;
186 : }
187 5 : if (mb_next && (! (mb_next->flags & MB_FLAG_ACTIVE)))
188 2 : mb->size += BLOCK_HEAD_SIZE + mb_next->size;
189 5 : }
190 :
191 : /* Return a new block, which can hold SIZE bytes. */
192 : static memblock_t *
193 3 : mb_get_new (memblock_t *block, size_t size)
194 : {
195 : memblock_t *mb, *mb_split;
196 :
197 5 : for (mb = block; ptr_into_pool_p (mb); mb = mb_get_next (mb))
198 5 : if (! (mb->flags & MB_FLAG_ACTIVE) && mb->size >= size)
199 : {
200 : /* Found a free block. */
201 3 : mb->flags |= MB_FLAG_ACTIVE;
202 :
203 3 : if (mb->size - size > BLOCK_HEAD_SIZE)
204 : {
205 : /* Split block. */
206 :
207 3 : mb_split = (memblock_t *) (void *) (((char *) mb) + BLOCK_HEAD_SIZE
208 3 : + size);
209 3 : mb_split->size = mb->size - size - BLOCK_HEAD_SIZE;
210 3 : mb_split->flags = 0;
211 :
212 3 : mb->size = size;
213 :
214 3 : mb_merge (mb_split);
215 :
216 : }
217 :
218 3 : break;
219 : }
220 :
221 3 : if (! ptr_into_pool_p (mb))
222 : {
223 0 : gpg_err_set_errno (ENOMEM);
224 0 : mb = NULL;
225 : }
226 :
227 3 : return mb;
228 : }
229 :
230 : /* Print a warning message. */
231 : static void
232 0 : print_warn (void)
233 : {
234 0 : if (!no_warning)
235 0 : log_info (_("Warning: using insecure memory!\n"));
236 0 : }
237 :
238 : /* Lock the memory pages into core and drop privileges. */
239 : static void
240 1 : lock_pool (void *p, size_t n)
241 : {
242 : #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
243 : int err;
244 :
245 : {
246 : cap_t cap;
247 :
248 : if (!no_priv_drop)
249 : {
250 : cap = cap_from_text ("cap_ipc_lock+ep");
251 : cap_set_proc (cap);
252 : cap_free (cap);
253 : }
254 : err = no_mlock? 0 : mlock (p, n);
255 : if (err && errno)
256 : err = errno;
257 : if (!no_priv_drop)
258 : {
259 : cap = cap_from_text ("cap_ipc_lock+p");
260 : cap_set_proc (cap);
261 : cap_free(cap);
262 : }
263 : }
264 :
265 : if (err)
266 : {
267 : if (errno != EPERM
268 : #ifdef EAGAIN /* OpenBSD returns this */
269 : && errno != EAGAIN
270 : #endif
271 : #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
272 : && errno != ENOSYS
273 : #endif
274 : #ifdef ENOMEM /* Linux might return this. */
275 : && errno != ENOMEM
276 : #endif
277 : )
278 : log_error ("can't lock memory: %s\n", strerror (err));
279 : show_warning = 1;
280 : not_locked = 1;
281 : }
282 :
283 : #elif defined(HAVE_MLOCK)
284 : uid_t uid;
285 : int err;
286 :
287 1 : uid = getuid ();
288 :
289 : #ifdef HAVE_BROKEN_MLOCK
290 : /* Under HP/UX mlock segfaults if called by non-root. Note, we have
291 : noch checked whether mlock does really work under AIX where we
292 : also detected a broken nlock. Note further, that using plock ()
293 : is not a good idea under AIX. */
294 : if (uid)
295 : {
296 : errno = EPERM;
297 : err = errno;
298 : }
299 : else
300 : {
301 : err = no_mlock? 0 : mlock (p, n);
302 : if (err && errno)
303 : err = errno;
304 : }
305 : #else /* !HAVE_BROKEN_MLOCK */
306 1 : err = no_mlock? 0 : mlock (p, n);
307 1 : if (err && errno)
308 0 : err = errno;
309 : #endif /* !HAVE_BROKEN_MLOCK */
310 :
311 : /* Test whether we are running setuid(0). */
312 1 : if (uid && ! geteuid ())
313 : {
314 : /* Yes, we are. */
315 0 : if (!no_priv_drop)
316 : {
317 : /* Check that we really dropped the privs.
318 : * Note: setuid(0) should always fail */
319 0 : if (setuid (uid) || getuid () != geteuid () || !setuid (0))
320 0 : log_fatal ("failed to reset uid: %s\n", strerror (errno));
321 : }
322 : }
323 :
324 1 : if (err)
325 : {
326 0 : if (errno != EPERM
327 : #ifdef EAGAIN /* OpenBSD returns this. */
328 0 : && errno != EAGAIN
329 : #endif
330 : #ifdef ENOSYS /* Some SCOs return this (function not implemented). */
331 0 : && errno != ENOSYS
332 : #endif
333 : #ifdef ENOMEM /* Linux might return this. */
334 0 : && errno != ENOMEM
335 : #endif
336 : )
337 0 : log_error ("can't lock memory: %s\n", strerror (err));
338 0 : show_warning = 1;
339 0 : not_locked = 1;
340 : }
341 :
342 : #elif defined ( __QNX__ )
343 : /* QNX does not page at all, so the whole secure memory stuff does
344 : * not make much sense. However it is still of use because it
345 : * wipes out the memory on a free().
346 : * Therefore it is sufficient to suppress the warning. */
347 : (void)p;
348 : (void)n;
349 : #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
350 : /* It does not make sense to print such a warning, given the fact that
351 : * this whole Windows !@#$% and their user base are inherently insecure. */
352 : (void)p;
353 : (void)n;
354 : #elif defined (__riscos__)
355 : /* No virtual memory on RISC OS, so no pages are swapped to disc,
356 : * besides we don't have mmap, so we don't use it! ;-)
357 : * But don't complain, as explained above. */
358 : (void)p;
359 : (void)n;
360 : #else
361 : (void)p;
362 : (void)n;
363 : if (!no_mlock)
364 : log_info ("Please note that you don't have secure memory on this system\n");
365 : #endif
366 1 : }
367 :
368 : /* Initialize POOL. */
369 : static void
370 1 : init_pool (size_t n)
371 : {
372 : memblock_t *mb;
373 :
374 1 : pool_size = n;
375 :
376 1 : if (disable_secmem)
377 0 : log_bug ("secure memory is disabled");
378 :
379 :
380 : #if HAVE_MMAP
381 : {
382 : size_t pgsize;
383 : long int pgsize_val;
384 :
385 : # if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
386 1 : pgsize_val = sysconf (_SC_PAGESIZE);
387 : # elif defined(HAVE_GETPAGESIZE)
388 : pgsize_val = getpagesize ();
389 : # else
390 : pgsize_val = -1;
391 : # endif
392 1 : pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val:DEFAULT_PAGE_SIZE;
393 :
394 1 : pool_size = (pool_size + pgsize - 1) & ~(pgsize - 1);
395 : # ifdef MAP_ANONYMOUS
396 1 : pool = mmap (0, pool_size, PROT_READ | PROT_WRITE,
397 : MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
398 : # else /* map /dev/zero instead */
399 : {
400 : int fd;
401 :
402 : fd = open ("/dev/zero", O_RDWR);
403 : if (fd == -1)
404 : {
405 : log_error ("can't open /dev/zero: %s\n", strerror (errno));
406 : pool = (void *) -1;
407 : }
408 : else
409 : {
410 : pool = mmap (0, pool_size,
411 : (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
412 : close (fd);
413 : }
414 : }
415 : # endif
416 1 : if (pool == (void *) -1)
417 0 : log_info ("can't mmap pool of %u bytes: %s - using malloc\n",
418 0 : (unsigned) pool_size, strerror (errno));
419 : else
420 : {
421 1 : pool_is_mmapped = 1;
422 1 : pool_okay = 1;
423 : }
424 : }
425 : #endif /*HAVE_MMAP*/
426 :
427 1 : if (!pool_okay)
428 : {
429 0 : pool = malloc (pool_size);
430 0 : if (!pool)
431 0 : log_fatal ("can't allocate memory pool of %u bytes\n",
432 : (unsigned) pool_size);
433 : else
434 0 : pool_okay = 1;
435 : }
436 :
437 : /* Initialize first memory block. */
438 1 : mb = (memblock_t *) pool;
439 1 : mb->size = pool_size;
440 1 : mb->flags = 0;
441 1 : }
442 :
443 : void
444 1 : _gcry_secmem_set_flags (unsigned flags)
445 : {
446 : int was_susp;
447 :
448 1 : SECMEM_LOCK;
449 :
450 1 : was_susp = suspend_warning;
451 1 : no_warning = flags & GCRY_SECMEM_FLAG_NO_WARNING;
452 1 : suspend_warning = flags & GCRY_SECMEM_FLAG_SUSPEND_WARNING;
453 1 : no_mlock = flags & GCRY_SECMEM_FLAG_NO_MLOCK;
454 1 : no_priv_drop = flags & GCRY_SECMEM_FLAG_NO_PRIV_DROP;
455 :
456 : /* and now issue the warning if it is not longer suspended */
457 1 : if (was_susp && !suspend_warning && show_warning)
458 : {
459 0 : show_warning = 0;
460 0 : print_warn ();
461 : }
462 :
463 1 : SECMEM_UNLOCK;
464 1 : }
465 :
466 : unsigned int
467 2 : _gcry_secmem_get_flags (void)
468 : {
469 : unsigned flags;
470 :
471 2 : SECMEM_LOCK;
472 :
473 2 : flags = no_warning ? GCRY_SECMEM_FLAG_NO_WARNING : 0;
474 2 : flags |= suspend_warning ? GCRY_SECMEM_FLAG_SUSPEND_WARNING : 0;
475 2 : flags |= not_locked ? GCRY_SECMEM_FLAG_NOT_LOCKED : 0;
476 2 : flags |= no_mlock ? GCRY_SECMEM_FLAG_NO_MLOCK : 0;
477 2 : flags |= no_priv_drop ? GCRY_SECMEM_FLAG_NO_PRIV_DROP : 0;
478 :
479 2 : SECMEM_UNLOCK;
480 :
481 2 : return flags;
482 : }
483 :
484 :
485 : /* See _gcry_secmem_init. This function is expected to be called with
486 : the secmem lock held. */
487 : static void
488 1 : secmem_init (size_t n)
489 : {
490 1 : if (!n)
491 : {
492 : #ifdef USE_CAPABILITIES
493 : /* drop all capabilities */
494 : if (!no_priv_drop)
495 : {
496 : cap_t cap;
497 :
498 : cap = cap_from_text ("all-eip");
499 : cap_set_proc (cap);
500 : cap_free (cap);
501 : }
502 :
503 : #elif !defined(HAVE_DOSISH_SYSTEM)
504 : uid_t uid;
505 :
506 0 : disable_secmem = 1;
507 0 : uid = getuid ();
508 0 : if (uid != geteuid ())
509 : {
510 0 : if (setuid (uid) || getuid () != geteuid () || !setuid (0))
511 0 : log_fatal ("failed to drop setuid\n");
512 : }
513 : #endif
514 : }
515 : else
516 : {
517 1 : if (n < MINIMUM_POOL_SIZE)
518 0 : n = MINIMUM_POOL_SIZE;
519 1 : if (! pool_okay)
520 : {
521 1 : init_pool (n);
522 1 : lock_pool (pool, n);
523 : }
524 : else
525 0 : log_error ("Oops, secure memory pool already initialized\n");
526 : }
527 1 : }
528 :
529 :
530 :
531 : /* Initialize the secure memory system. If running with the necessary
532 : privileges, the secure memory pool will be locked into the core in
533 : order to prevent page-outs of the data. Furthermore allocated
534 : secure memory will be wiped out when released. */
535 : void
536 1 : _gcry_secmem_init (size_t n)
537 : {
538 1 : SECMEM_LOCK;
539 :
540 1 : secmem_init (n);
541 :
542 1 : SECMEM_UNLOCK;
543 1 : }
544 :
545 :
546 : gcry_err_code_t
547 31 : _gcry_secmem_module_init ()
548 : {
549 : /* Not anymore needed. */
550 31 : return 0;
551 : }
552 :
553 :
554 : static void *
555 3 : _gcry_secmem_malloc_internal (size_t size)
556 : {
557 : memblock_t *mb;
558 :
559 3 : if (!pool_okay)
560 : {
561 : /* Try to initialize the pool if the user forgot about it. */
562 0 : secmem_init (STANDARD_POOL_SIZE);
563 0 : if (!pool_okay)
564 : {
565 0 : log_info (_("operation is not possible without "
566 : "initialized secure memory\n"));
567 0 : gpg_err_set_errno (ENOMEM);
568 0 : return NULL;
569 : }
570 : }
571 3 : if (not_locked && fips_mode ())
572 : {
573 0 : log_info (_("secure memory pool is not locked while in FIPS mode\n"));
574 0 : gpg_err_set_errno (ENOMEM);
575 0 : return NULL;
576 : }
577 3 : if (show_warning && !suspend_warning)
578 : {
579 0 : show_warning = 0;
580 0 : print_warn ();
581 : }
582 :
583 : /* Blocks are always a multiple of 32. */
584 3 : size = ((size + 31) / 32) * 32;
585 :
586 3 : mb = mb_get_new ((memblock_t *) pool, size);
587 3 : if (mb)
588 3 : stats_update (size, 0);
589 :
590 3 : return mb ? &mb->aligned.c : NULL;
591 : }
592 :
593 : void *
594 3 : _gcry_secmem_malloc (size_t size)
595 : {
596 : void *p;
597 :
598 3 : SECMEM_LOCK;
599 3 : p = _gcry_secmem_malloc_internal (size);
600 3 : SECMEM_UNLOCK;
601 :
602 3 : return p;
603 : }
604 :
605 : static void
606 2 : _gcry_secmem_free_internal (void *a)
607 : {
608 : memblock_t *mb;
609 : int size;
610 :
611 2 : if (!a)
612 2 : return;
613 :
614 2 : mb = ADDR_TO_BLOCK (a);
615 2 : size = mb->size;
616 :
617 : /* This does not make much sense: probably this memory is held in the
618 : * cache. We do it anyway: */
619 : #define MB_WIPE_OUT(byte) \
620 : wipememory2 (((char *) mb + BLOCK_HEAD_SIZE), (byte), size);
621 :
622 2 : MB_WIPE_OUT (0xff);
623 2 : MB_WIPE_OUT (0xaa);
624 2 : MB_WIPE_OUT (0x55);
625 2 : MB_WIPE_OUT (0x00);
626 :
627 2 : stats_update (0, size);
628 :
629 2 : mb->flags &= ~MB_FLAG_ACTIVE;
630 :
631 : /* Update stats. */
632 :
633 2 : mb_merge (mb);
634 : }
635 :
636 : /* Wipe out and release memory. */
637 : void
638 2 : _gcry_secmem_free (void *a)
639 : {
640 2 : SECMEM_LOCK;
641 2 : _gcry_secmem_free_internal (a);
642 2 : SECMEM_UNLOCK;
643 2 : }
644 :
645 : /* Realloc memory. */
646 : void *
647 0 : _gcry_secmem_realloc (void *p, size_t newsize)
648 : {
649 : memblock_t *mb;
650 : size_t size;
651 : void *a;
652 :
653 0 : SECMEM_LOCK;
654 :
655 0 : mb = (memblock_t *) (void *) ((char *) p
656 : - ((size_t) &((memblock_t *) 0)->aligned.c));
657 0 : size = mb->size;
658 0 : if (newsize < size)
659 : {
660 : /* It is easier to not shrink the memory. */
661 0 : a = p;
662 : }
663 : else
664 : {
665 0 : a = _gcry_secmem_malloc_internal (newsize);
666 0 : if (a)
667 : {
668 0 : memcpy (a, p, size);
669 0 : memset ((char *) a + size, 0, newsize - size);
670 0 : _gcry_secmem_free_internal (p);
671 : }
672 : }
673 :
674 0 : SECMEM_UNLOCK;
675 :
676 0 : return a;
677 : }
678 :
679 :
680 : /* Return true if P points into the secure memory area. */
681 : int
682 75323472 : _gcry_private_is_secure (const void *p)
683 : {
684 75323472 : return pool_okay && ptr_into_pool_p (p);
685 : }
686 :
687 :
688 : /****************
689 : * Warning: This code might be called by an interrupt handler
690 : * and frankly, there should really be such a handler,
691 : * to make sure that the memory is wiped out.
692 : * We hope that the OS wipes out mlocked memory after
693 : * receiving a SIGKILL - it really should do so, otherwise
694 : * there is no chance to get the secure memory cleaned.
695 : */
696 : void
697 0 : _gcry_secmem_term ()
698 : {
699 0 : if (!pool_okay)
700 0 : return;
701 :
702 0 : wipememory2 (pool, 0xff, pool_size);
703 0 : wipememory2 (pool, 0xaa, pool_size);
704 0 : wipememory2 (pool, 0x55, pool_size);
705 0 : wipememory2 (pool, 0x00, pool_size);
706 : #if HAVE_MMAP
707 0 : if (pool_is_mmapped)
708 0 : munmap (pool, pool_size);
709 : #endif
710 0 : pool = NULL;
711 0 : pool_okay = 0;
712 0 : pool_size = 0;
713 0 : not_locked = 0;
714 : }
715 :
716 :
717 : void
718 0 : _gcry_secmem_dump_stats ()
719 : {
720 : #if 1
721 0 : SECMEM_LOCK;
722 :
723 0 : if (pool_okay)
724 0 : log_info ("secmem usage: %u/%lu bytes in %u blocks\n",
725 : cur_alloced, (unsigned long)pool_size, cur_blocks);
726 0 : SECMEM_UNLOCK;
727 : #else
728 : memblock_t *mb;
729 : int i;
730 :
731 : SECMEM_LOCK;
732 :
733 : for (i = 0, mb = (memblock_t *) pool;
734 : ptr_into_pool_p (mb);
735 : mb = mb_get_next (mb), i++)
736 : log_info ("SECMEM: [%s] block: %i; size: %i\n",
737 : (mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
738 : i,
739 : mb->size);
740 : SECMEM_UNLOCK;
741 : #endif
742 0 : }
|