1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* egg-secure-memory.h - library for allocating memory that is non-pageable
4 Copyright (C) 2007 Stefan Walter
6 The Gnome Keyring Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The Gnome Keyring Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the Gnome Library; see the file COPYING.LIB. If not,
18 see <http://www.gnu.org/licenses/>.
20 Author: Stef Walter <stef@memberwebs.com>
24 * IMPORTANT: This is pure vanila standard C, no glib. We need this
25 * because certain consumers of this protocol need to be built
26 * without linking in any special libraries. ie: the PKCS#11 module.
31 #include "egg-secure-memory.h"
33 #include <sys/types.h>
44 #include <valgrind/valgrind.h>
45 #include <valgrind/memcheck.h>
48 #define DEBUG_SECURE_MEMORY 0
50 #if DEBUG_SECURE_MEMORY
51 #define DEBUG_ALLOC(msg, n) fprintf(stderr, "%s %lu bytes\n", msg, n);
53 #define DEBUG_ALLOC(msg, n)
56 #define DEFAULT_BLOCK_SIZE 16384
58 /* Use our own assert to guarantee no glib allocations */
60 #ifdef G_DISABLE_ASSERT
63 #define ASSERT(x) assert(x)
68 EGG_SECURE_GLOBALS.lock ();
71 EGG_SECURE_GLOBALS.unlock ();
73 static int show_warning = 1;
74 int egg_secure_warnings = 1;
77 * We allocate all memory in units of sizeof(void*). This
78 * is our definition of 'word'.
82 /* The amount of extra words we can allocate */
86 * Track allocated memory or a free block. This structure is not stored
87 * in the secure memory area. It is allocated from a pool of other
88 * memory. See meta_pool_xxx ().
90 typedef struct _Cell {
91 word_t *words; /* Pointer to secure memory */
92 size_t n_words; /* Amount of secure memory in words */
93 size_t requested; /* Amount actually requested by app, in bytes, 0 if unused */
94 const char *tag; /* Tag which describes the allocation */
95 struct _Cell *next; /* Next in memory ring */
96 struct _Cell *prev; /* Previous in memory ring */
100 * A block of secure memory. This structure is the header in that block.
102 typedef struct _Block {
103 word_t *words; /* Actual memory hangs off here */
104 size_t n_words; /* Number of words in block */
105 size_t n_used; /* Number of used allocations */
106 struct _Cell* used_cells; /* Ring of used allocations */
107 struct _Cell* unused_cells; /* Ring of unused allocations */
108 struct _Block *next; /* Next block in list */
111 /* -----------------------------------------------------------------------------
116 unused_push (void **stack, void *ptr)
120 *((void**)ptr) = *stack;
125 unused_pop (void **stack)
130 *stack = *(void**)ptr;
136 unused_peek (void **stack)
142 /* -----------------------------------------------------------------------------
143 * POOL META DATA ALLOCATION
145 * A pool for memory meta data. We allocate fixed size blocks. There are actually
146 * two different structures stored in this pool: Cell and Block. Cell is allocated
147 * way more often, and is bigger so we just allocate that size for both.
150 /* Pool allocates this data type */
151 typedef union _Item {
156 typedef struct _Pool {
157 struct _Pool *next; /* Next pool in list */
158 size_t length; /* Length in bytes of the pool */
159 size_t used; /* Number of cells used in pool */
160 void *unused; /* Unused stack of unused stuff */
161 size_t n_items; /* Total number of items in pool */
162 Item items[1]; /* Actual items hang off here */
172 if (!EGG_SECURE_GLOBALS.pool_version ||
173 strcmp (EGG_SECURE_GLOBALS.pool_version, EGG_SECURE_POOL_VER_STR) != 0) {
174 if (show_warning && egg_secure_warnings)
175 fprintf (stderr, "the secure memory pool version does not match the code '%s' != '%s'\n",
176 EGG_SECURE_GLOBALS.pool_version ? EGG_SECURE_GLOBALS.pool_version : "(null)",
177 EGG_SECURE_POOL_VER_STR);
182 /* A pool with an available item */
183 for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
184 if (unused_peek (&pool->unused))
188 /* Create a new pool */
190 len = getpagesize () * 2;
191 pages = mmap (0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
192 if (pages == MAP_FAILED)
195 /* Fill in the block header, and inlude in block list */
197 pool->next = EGG_SECURE_GLOBALS.pool_data;
198 EGG_SECURE_GLOBALS.pool_data = pool;
203 /* Fill block with unused items */
204 pool->n_items = (len - sizeof (Pool)) / sizeof (Item);
205 for (i = 0; i < pool->n_items; ++i)
206 unused_push (&pool->unused, pool->items + i);
209 VALGRIND_CREATE_MEMPOOL(pool, 0, 0);
214 ASSERT (unused_peek (&pool->unused));
215 item = unused_pop (&pool->unused);
218 VALGRIND_MEMPOOL_ALLOC (pool, item, sizeof (Item));
221 return memset (item, 0, sizeof (Item));
225 pool_free (void* item)
228 char *ptr, *beg, *end;
232 /* Find which block this one belongs to */
233 for (at = (Pool **)&EGG_SECURE_GLOBALS.pool_data, pool = *at;
234 pool != NULL; at = &pool->next, pool = *at) {
235 beg = (char*)pool->items;
236 end = (char*)pool + pool->length - sizeof (Item);
237 if (ptr >= beg && ptr <= end) {
238 ASSERT ((ptr - beg) % sizeof (Item) == 0);
243 /* Otherwise invalid meta */
246 ASSERT (pool->used > 0);
248 /* No more meta cells used in this block, remove from list, destroy */
249 if (pool->used == 1) {
253 VALGRIND_DESTROY_MEMPOOL (pool);
256 munmap (pool, pool->length);
261 VALGRIND_MEMPOOL_FREE (pool, item);
262 VALGRIND_MAKE_MEM_UNDEFINED (item, sizeof (Item));
266 memset (item, 0xCD, sizeof (Item));
267 unused_push (&pool->unused, item);
270 #ifndef G_DISABLE_ASSERT
273 pool_valid (void* item)
276 char *ptr, *beg, *end;
280 /* Find which block this one belongs to */
281 for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
282 beg = (char*)pool->items;
283 end = (char*)pool + pool->length - sizeof (Item);
284 if (ptr >= beg && ptr <= end)
285 return (pool->used && (ptr - beg) % sizeof (Item) == 0);
291 #endif /* G_DISABLE_ASSERT */
293 /* -----------------------------------------------------------------------------
296 * Each memory cell begins and ends with a pointer to its metadata. These are also
297 * used as guards or red zones. Since they're treated as redzones by valgrind we
298 * have to jump through a few hoops before reading and/or writing them.
302 sec_size_to_words (size_t length)
304 return (length % sizeof (void*) ? 1 : 0) + (length / sizeof (void*));
308 sec_write_guards (Cell *cell)
311 VALGRIND_MAKE_MEM_UNDEFINED (cell->words, sizeof (word_t));
312 VALGRIND_MAKE_MEM_UNDEFINED (cell->words + cell->n_words - 1, sizeof (word_t));
315 ((void**)cell->words)[0] = (void*)cell;
316 ((void**)cell->words)[cell->n_words - 1] = (void*)cell;
319 VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t));
320 VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t));
325 sec_check_guards (Cell *cell)
328 VALGRIND_MAKE_MEM_DEFINED (cell->words, sizeof (word_t));
329 VALGRIND_MAKE_MEM_DEFINED (cell->words + cell->n_words - 1, sizeof (word_t));
332 ASSERT(((void**)cell->words)[0] == (void*)cell);
333 ASSERT(((void**)cell->words)[cell->n_words - 1] == (void*)cell);
336 VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t));
337 VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t));
342 sec_insert_cell_ring (Cell **ring, Cell *cell)
346 ASSERT (cell != *ring);
347 ASSERT (cell->next == NULL);
348 ASSERT (cell->prev == NULL);
350 /* Insert back into the mix of available memory */
352 cell->next = (*ring)->next;
354 cell->next->prev = cell;
355 cell->prev->next = cell;
362 ASSERT (cell->next->prev == cell);
363 ASSERT (cell->prev->next == cell);
367 sec_remove_cell_ring (Cell **ring, Cell *cell)
374 ASSERT (cell->next->prev == cell);
375 ASSERT (cell->prev->next == cell);
379 if (cell->next == cell) {
380 ASSERT (cell->prev == cell);
383 /* Just pointing to this meta */
385 ASSERT (cell->prev != cell);
390 cell->next->prev = cell->prev;
391 cell->prev->next = cell->next;
392 cell->next = cell->prev = NULL;
394 ASSERT (*ring != cell);
398 sec_cell_to_memory (Cell *cell)
400 return cell->words + 1;
404 sec_is_valid_word (Block *block, word_t *word)
406 return (word >= block->words && word < block->words + block->n_words);
410 sec_clear_undefined (void *memory,
417 VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
419 memset (ptr + from, 0, to - from);
421 VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
425 sec_clear_noaccess (void *memory, size_t from, size_t to)
430 VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
432 memset (ptr + from, 0, to - from);
434 VALGRIND_MAKE_MEM_NOACCESS (ptr + from, to - from);
439 sec_neighbor_before (Block *block, Cell *cell)
446 word = cell->words - 1;
447 if (!sec_is_valid_word (block, word))
451 VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
455 sec_check_guards (cell);
458 VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
465 sec_neighbor_after (Block *block, Cell *cell)
472 word = cell->words + cell->n_words;
473 if (!sec_is_valid_word (block, word))
477 VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
481 sec_check_guards (cell);
484 VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
491 sec_alloc (Block *block,
503 if (!block->unused_cells)
507 * Each memory allocation is aligned to a pointer size, and
508 * then, sandwidched between two pointers to its meta data.
509 * These pointers also act as guards.
511 * We allocate memory in units of sizeof (void*)
514 n_words = sec_size_to_words (length) + 2;
516 /* Look for a cell of at least our required size */
517 cell = block->unused_cells;
518 while (cell->n_words < n_words) {
520 if (cell == block->unused_cells) {
529 ASSERT (cell->tag == NULL);
530 ASSERT (cell->requested == 0);
532 ASSERT (cell->words);
533 sec_check_guards (cell);
535 /* Steal from the cell if it's too long */
536 if (cell->n_words > n_words + WASTE) {
537 other = pool_alloc ();
540 other->n_words = n_words;
541 other->words = cell->words;
542 cell->n_words -= n_words;
543 cell->words += n_words;
545 sec_write_guards (other);
546 sec_write_guards (cell);
552 sec_remove_cell_ring (&block->unused_cells, cell);
556 cell->requested = length;
557 sec_insert_cell_ring (&block->used_cells, cell);
558 memory = sec_cell_to_memory (cell);
561 VALGRIND_MAKE_MEM_UNDEFINED (memory, length);
564 return memset (memory, 0, length);
568 sec_free (Block *block, void *memory)
580 VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
583 /* Lookup the meta for this memory block (using guard pointer) */
584 ASSERT (sec_is_valid_word (block, word));
585 ASSERT (pool_valid (*word));
589 VALGRIND_MAKE_MEM_DEFINED (cell->words, cell->n_words * sizeof (word_t));
592 sec_check_guards (cell);
593 sec_clear_noaccess (memory, 0, cell->requested);
595 sec_check_guards (cell);
596 ASSERT (cell->requested > 0);
597 ASSERT (cell->tag != NULL);
599 /* Remove from the used cell ring */
600 sec_remove_cell_ring (&block->used_cells, cell);
602 /* Find previous unallocated neighbor, and merge if possible */
603 other = sec_neighbor_before (block, cell);
604 if (other && other->requested == 0) {
605 ASSERT (other->tag == NULL);
606 ASSERT (other->next && other->prev);
607 other->n_words += cell->n_words;
608 sec_write_guards (other);
613 /* Find next unallocated neighbor, and merge if possible */
614 other = sec_neighbor_after (block, cell);
615 if (other && other->requested == 0) {
616 ASSERT (other->tag == NULL);
617 ASSERT (other->next && other->prev);
618 other->n_words += cell->n_words;
619 other->words = cell->words;
621 sec_remove_cell_ring (&block->unused_cells, cell);
622 sec_write_guards (other);
627 /* Add to the unused list if not already there */
629 sec_insert_cell_ring (&block->unused_cells, cell);
638 memcpy_with_vbits (void *dest,
646 if (RUNNING_ON_VALGRIND) {
647 vbits = malloc (length);
649 vbits_setup = VALGRIND_GET_VBITS (src, vbits, length);
650 VALGRIND_MAKE_MEM_DEFINED (src, length);
654 memcpy (dest, src, length);
657 if (vbits_setup == 1) {
658 VALGRIND_SET_VBITS (dest, vbits, length);
659 VALGRIND_SET_VBITS (src, vbits, length);
666 sec_realloc (Block *block,
677 /* Standard realloc behavior, should have been handled elsewhere */
678 ASSERT (memory != NULL);
680 ASSERT (tag != NULL);
682 /* Dig out where the meta should be */
687 VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
690 ASSERT (sec_is_valid_word (block, word));
691 ASSERT (pool_valid (*word));
694 /* Validate that it's actually for real */
695 sec_check_guards (cell);
696 ASSERT (cell->requested > 0);
697 ASSERT (cell->tag != NULL);
699 /* The amount of valid data */
700 valid = cell->requested;
702 /* How many words we actually want */
703 n_words = sec_size_to_words (length) + 2;
705 /* Less memory is required than is in the cell */
706 if (n_words <= cell->n_words) {
708 /* TODO: No shrinking behavior yet */
709 cell->requested = length;
710 alloc = sec_cell_to_memory (cell);
713 * Even though we may be reusing the same cell, that doesn't
714 * mean that the allocation is shrinking. It could have shrunk
715 * and is now expanding back some.
718 sec_clear_undefined (alloc, length, valid);
723 /* Need braaaaaiiiiiinsss... */
724 while (cell->n_words < n_words) {
726 /* See if we have a neighbor who can give us some memory */
727 other = sec_neighbor_after (block, cell);
728 if (!other || other->requested != 0)
731 /* Eat the whole neighbor if not too big */
732 if (n_words - cell->n_words + WASTE >= other->n_words) {
733 cell->n_words += other->n_words;
734 sec_write_guards (cell);
735 sec_remove_cell_ring (&block->unused_cells, other);
738 /* Steal from the neighbor */
740 other->words += n_words - cell->n_words;
741 other->n_words -= n_words - cell->n_words;
742 sec_write_guards (other);
743 cell->n_words = n_words;
744 sec_write_guards (cell);
748 if (cell->n_words >= n_words) {
749 cell->requested = length;
751 alloc = sec_cell_to_memory (cell);
752 sec_clear_undefined (alloc, valid, length);
756 /* That didn't work, try alloc/free */
757 alloc = sec_alloc (block, tag, length);
759 memcpy_with_vbits (alloc, memory, valid);
760 sec_free (block, memory);
768 sec_allocated (Block *block, void *memory)
780 VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
783 /* Lookup the meta for this memory block (using guard pointer) */
784 ASSERT (sec_is_valid_word (block, word));
785 ASSERT (pool_valid (*word));
788 sec_check_guards (cell);
789 ASSERT (cell->requested > 0);
790 ASSERT (cell->tag != NULL);
793 VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
796 return cell->requested;
800 sec_validate (Block *block)
806 if (RUNNING_ON_VALGRIND)
811 last = word + block->n_words;
814 ASSERT (word < last);
816 ASSERT (sec_is_valid_word (block, word));
817 ASSERT (pool_valid (*word));
820 /* Validate that it's actually for real */
821 sec_check_guards (cell);
823 /* Is it an allocated block? */
824 if (cell->requested > 0) {
825 ASSERT (cell->tag != NULL);
826 ASSERT (cell->next != NULL);
827 ASSERT (cell->prev != NULL);
828 ASSERT (cell->next->prev == cell);
829 ASSERT (cell->prev->next == cell);
830 ASSERT (cell->requested <= (cell->n_words - 2) * sizeof (word_t));
832 /* An unused block */
834 ASSERT (cell->tag == NULL);
835 ASSERT (cell->next != NULL);
836 ASSERT (cell->prev != NULL);
837 ASSERT (cell->next->prev == cell);
838 ASSERT (cell->prev->next == cell);
841 word += cell->n_words;
847 /* -----------------------------------------------------------------------------
852 sec_acquire_pages (size_t *sz,
853 const char *during_tag)
856 unsigned long pgsize;
862 /* Make sure sz is a multiple of the page size */
863 pgsize = getpagesize ();
864 *sz = (*sz + pgsize -1) & ~(pgsize - 1);
866 #if defined(HAVE_MLOCK)
867 pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
868 if (pages == MAP_FAILED) {
869 if (show_warning && egg_secure_warnings)
870 fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n",
871 (unsigned long)*sz, during_tag, strerror (errno));
876 if (mlock (pages, *sz) < 0) {
877 if (show_warning && egg_secure_warnings && errno != EPERM) {
878 fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n",
879 (unsigned long)*sz, during_tag, strerror (errno));
886 DEBUG_ALLOC ("gkr-secure-memory: new block ", *sz);
892 if (show_warning && egg_secure_warnings)
893 fprintf (stderr, "your system does not support private memory");
901 sec_release_pages (void *pages, size_t sz)
904 ASSERT (sz % getpagesize () == 0);
906 #if defined(HAVE_MLOCK)
907 if (munlock (pages, sz) < 0 && egg_secure_warnings)
908 fprintf (stderr, "couldn't unlock private memory: %s\n", strerror (errno));
910 if (munmap (pages, sz) < 0 && egg_secure_warnings)
911 fprintf (stderr, "couldn't unmap private anonymous memory: %s\n", strerror (errno));
913 DEBUG_ALLOC ("gkr-secure-memory: freed block ", sz);
920 /* -----------------------------------------------------------------------------
921 * MANAGE DIFFERENT BLOCKS
924 static Block *all_blocks = NULL;
927 sec_block_create (size_t size,
928 const char *during_tag)
935 /* We can force all all memory to be malloced */
936 if (getenv ("SECMEM_FORCE_FALLBACK"))
939 block = pool_alloc ();
943 cell = pool_alloc ();
949 /* The size above is a minimum, we're free to go bigger */
950 if (size < DEFAULT_BLOCK_SIZE)
951 size = DEFAULT_BLOCK_SIZE;
953 block->words = sec_acquire_pages (&size, during_tag);
954 block->n_words = size / sizeof (word_t);
962 VALGRIND_MAKE_MEM_DEFINED (block->words, size);
965 /* The first cell to allocate from */
966 cell->words = block->words;
967 cell->n_words = block->n_words;
969 sec_write_guards (cell);
970 sec_insert_cell_ring (&block->unused_cells, cell);
972 block->next = all_blocks;
979 sec_block_destroy (Block *block)
985 ASSERT (block->words);
986 ASSERT (block->n_used == 0);
988 /* Remove from the list */
989 for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) {
996 /* Must have been found */
997 ASSERT (bl == block);
998 ASSERT (block->used_cells == NULL);
1000 /* Release all the meta data cells */
1001 while (block->unused_cells) {
1002 cell = block->unused_cells;
1003 sec_remove_cell_ring (&block->unused_cells, cell);
1007 /* Release all pages of secure memory */
1008 sec_release_pages (block->words, block->n_words * sizeof (word_t));
1013 /* ------------------------------------------------------------------------
1014 * PUBLIC FUNCTIONALITY
1018 egg_secure_alloc_full (const char *tag,
1023 void *memory = NULL;
1028 if (length > 0xFFFFFFFF / 2) {
1029 if (egg_secure_warnings)
1030 fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n",
1031 (unsigned long)length);
1035 /* Can't allocate zero bytes */
1041 for (block = all_blocks; block; block = block->next) {
1042 memory = sec_alloc (block, tag, length);
1047 /* None of the current blocks have space, allocate new */
1049 block = sec_block_create (length, tag);
1051 memory = sec_alloc (block, tag, length);
1054 #ifdef WITH_VALGRIND
1056 VALGRIND_MALLOCLIKE_BLOCK (memory, length, sizeof (void*), 1);
1061 if (!memory && (flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback != NULL) {
1062 memory = EGG_SECURE_GLOBALS.fallback (NULL, length);
1063 if (memory) /* Our returned memory is always zeroed */
1064 memset (memory, 0, length);
1074 egg_secure_realloc_full (const char *tag,
1079 Block *block = NULL;
1080 size_t previous = 0;
1087 if (length > 0xFFFFFFFF / 2) {
1088 if (egg_secure_warnings)
1089 fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n",
1090 (unsigned long)length);
1095 return egg_secure_alloc_full (tag, length, flags);
1097 egg_secure_free_full (memory, flags);
1103 /* Find out where it belongs to */
1104 for (block = all_blocks; block; block = block->next) {
1105 if (sec_is_valid_word (block, memory)) {
1106 previous = sec_allocated (block, memory);
1108 #ifdef WITH_VALGRIND
1109 /* Let valgrind think we are unallocating so that it'll validate */
1110 VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t));
1113 alloc = sec_realloc (block, tag, memory, length);
1115 #ifdef WITH_VALGRIND
1116 /* Now tell valgrind about either the new block or old one */
1117 VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory,
1118 alloc ? length : previous,
1119 sizeof (word_t), 1);
1125 /* If it didn't work we may need to allocate a new block */
1126 if (block && !alloc)
1129 if (block && block->n_used == 0)
1130 sec_block_destroy (block);
1135 if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) {
1137 * In this case we can't zero the returned memory,
1138 * because we don't know what the block size was.
1140 return EGG_SECURE_GLOBALS.fallback (memory, length);
1142 if (egg_secure_warnings)
1143 fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n",
1144 (unsigned long)memory);
1145 ASSERT (0 && "memory does does not belong to secure memory pool");
1151 alloc = egg_secure_alloc_full (tag, length, flags);
1153 memcpy_with_vbits (alloc, memory, previous);
1154 egg_secure_free_full (memory, flags);
1165 egg_secure_free (void *memory)
1167 egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK);
1171 egg_secure_free_full (void *memory, int flags)
1173 Block *block = NULL;
1180 /* Find out where it belongs to */
1181 for (block = all_blocks; block; block = block->next) {
1182 if (sec_is_valid_word (block, memory))
1186 #ifdef WITH_VALGRIND
1187 /* We like valgrind's warnings, so give it a first whack at checking for errors */
1188 if (block != NULL || !(flags & EGG_SECURE_USE_FALLBACK))
1189 VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t));
1192 if (block != NULL) {
1193 sec_free (block, memory);
1194 if (block->n_used == 0)
1195 sec_block_destroy (block);
1201 if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) {
1202 EGG_SECURE_GLOBALS.fallback (memory, 0);
1204 if (egg_secure_warnings)
1205 fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n",
1206 (unsigned long)memory);
1207 ASSERT (0 && "memory does does not belong to secure memory pool");
1213 egg_secure_check (const void *memory)
1215 Block *block = NULL;
1219 /* Find out where it belongs to */
1220 for (block = all_blocks; block; block = block->next) {
1221 if (sec_is_valid_word (block, (word_t*)memory))
1227 return block == NULL ? 0 : 1;
1231 egg_secure_validate (void)
1233 Block *block = NULL;
1237 for (block = all_blocks; block; block = block->next)
1238 sec_validate (block);
1244 static egg_secure_rec *
1245 records_for_ring (Cell *cell_ring,
1246 egg_secure_rec *records,
1247 unsigned int *count,
1248 unsigned int *total)
1250 egg_secure_rec *new_rec;
1251 unsigned int allocated = *count;
1256 if (*count >= allocated) {
1257 new_rec = realloc (records, sizeof (egg_secure_rec) * (allocated + 32));
1258 if (new_rec == NULL) {
1269 records[*count].request_length = cell->requested;
1270 records[*count].block_length = cell->n_words * sizeof (word_t);
1271 records[*count].tag = cell->tag;
1273 (*total) += cell->n_words;
1276 } while (cell != NULL && cell != cell_ring);
1282 egg_secure_records (unsigned int *count)
1284 egg_secure_rec *records = NULL;
1285 Block *block = NULL;
1292 for (block = all_blocks; block != NULL; block = block->next) {
1295 records = records_for_ring (block->unused_cells, records, count, &total);
1296 if (records == NULL)
1298 records = records_for_ring (block->used_cells, records, count, &total);
1299 if (records == NULL)
1302 /* Make sure this actualy accounts for all memory */
1303 ASSERT (total == block->n_words);
1312 egg_secure_strdup_full (const char *tag,
1322 len = strlen (str) + 1;
1323 res = (char *)egg_secure_alloc_full (tag, len, options);
1329 egg_secure_strndup_full (const char *tag,
1341 end = memchr (str, '\0', length);
1343 length = (end - str);
1345 res = (char *)egg_secure_alloc_full (tag, len, options);
1346 memcpy (res, str, len);
1351 egg_secure_clear (void *p, size_t length)
1358 vp = (volatile char*)p;
1367 egg_secure_strclear (char *str)
1371 egg_secure_clear ((unsigned char*)str, strlen (str));
1375 egg_secure_strfree (char *str)
1378 * If we're using unpageable 'secure' memory, then the free call
1379 * should zero out the memory, but because on certain platforms
1380 * we may be using normal memory, zero it out here just in case.
1383 egg_secure_strclear (str);
1384 egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK);