From 7cea18071bd33d70834cc05b8bcdcaee05194270 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sat, 27 Oct 2012 11:58:13 +0200 Subject: [PATCH] Bring over a new version of the secure memory code from gcr * This allows libraries to share the pool if they have the same version of the secure memory code. --- egg/egg-secure-memory.c | 451 +++++++++++++++++++------------------ egg/egg-secure-memory.h | 114 +++++----- egg/tests/test-dh.c | 2 +- egg/tests/test-hkdf.c | 2 +- egg/tests/test-secmem.c | 20 +- libsecret/secret-service.c | 2 +- 6 files changed, 301 insertions(+), 290 deletions(-) diff --git a/egg/egg-secure-memory.c b/egg/egg-secure-memory.c index 490f10c..9e605ff 100644 --- a/egg/egg-secure-memory.c +++ b/egg/egg-secure-memory.c @@ -1,29 +1,29 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-secure-memory.h - library for allocating memory that is non-pageable - * - * Copyright (C) 2007 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Author: Stef Walter - */ + + Copyright (C) 2007 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter +*/ /* - * IMPORTANT: This is pure vanila standard C, no glib. We need this - * because certain consumers of this protocol need to be built + * IMPORTANT: This is pure vanila standard C, no glib. We need this + * because certain consumers of this protocol need to be built * without linking in any special libraries. ie: the PKCS#11 module. */ @@ -48,8 +48,8 @@ #define DEBUG_SECURE_MEMORY 0 -#if DEBUG_SECURE_MEMORY -#define DEBUG_ALLOC(msg, n) fprintf(stderr, "%s %lu bytes\n", msg, n); +#if DEBUG_SECURE_MEMORY +#define DEBUG_ALLOC(msg, n) fprintf(stderr, "%s %lu bytes\n", msg, n); #else #define DEBUG_ALLOC(msg, n) #endif @@ -59,33 +59,33 @@ /* Use our own assert to guarantee no glib allocations */ #ifndef ASSERT #ifdef G_DISABLE_ASSERT -#define ASSERT(x) -#else +#define ASSERT(x) +#else #define ASSERT(x) assert(x) #endif #endif #define DO_LOCK() \ - egg_memory_lock (); - -#define DO_UNLOCK() \ - egg_memory_unlock (); + EGG_SECURE_GLOBALS.lock (); -static int lock_warning = 1; +#define DO_UNLOCK() \ + EGG_SECURE_GLOBALS.unlock (); + +static int show_warning = 1; int egg_secure_warnings = 1; -/* - * We allocate all memory in units of sizeof(void*). This +/* + * We allocate all memory in units of sizeof(void*). This * is our definition of 'word'. */ typedef void* word_t; -/* The amount of extra words we can allocate */ +/* The amount of extra words we can allocate */ #define WASTE 4 -/* - * Track allocated memory or a free block. This structure is not stored - * in the secure memory area. It is allocated from a pool of other +/* + * Track allocated memory or a free block. This structure is not stored + * in the secure memory area. It is allocated from a pool of other * memory. See meta_pool_xxx (). */ typedef struct _Cell { @@ -97,7 +97,7 @@ typedef struct _Cell { struct _Cell *prev; /* Previous in memory ring */ } Cell; -/* +/* * A block of secure memory. This structure is the header in that block. */ typedef struct _Block { @@ -130,20 +130,20 @@ unused_pop (void **stack) ptr = *stack; *stack = *(void**)ptr; return ptr; - + } static inline void* unused_peek (void **stack) { ASSERT (stack); - return *stack; + return *stack; } /* ----------------------------------------------------------------------------- * POOL META DATA ALLOCATION - * - * A pool for memory meta data. We allocate fixed size blocks. There are actually + * + * A pool for memory meta data. We allocate fixed size blocks. There are actually * two different structures stored in this pool: Cell and Block. Cell is allocated * way more often, and is bigger so we just allocate that size for both. */ @@ -163,21 +163,29 @@ typedef struct _Pool { Item items[1]; /* Actual items hang off here */ } Pool; -static Pool *all_pools = NULL; - -static void* +static void * pool_alloc (void) { Pool *pool; void *pages, *item; size_t len, i; - + + if (!EGG_SECURE_GLOBALS.pool_version || + strcmp (EGG_SECURE_GLOBALS.pool_version, EGG_SECURE_POOL_VER_STR) != 0) { + if (show_warning && egg_secure_warnings) + fprintf (stderr, "the secure memory pool version does not match the code '%s' != '%s'\n", + EGG_SECURE_GLOBALS.pool_version ? EGG_SECURE_GLOBALS.pool_version : "(null)", + EGG_SECURE_POOL_VER_STR); + show_warning = 0; + return NULL; + } + /* A pool with an available item */ - for (pool = all_pools; pool; pool = pool->next) { + for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) { if (unused_peek (&pool->unused)) break; } - + /* Create a new pool */ if (pool == NULL) { len = getpagesize () * 2; @@ -187,8 +195,8 @@ pool_alloc (void) /* Fill in the block header, and inlude in block list */ pool = pages; - pool->next = all_pools; - all_pools = pool; + pool->next = EGG_SECURE_GLOBALS.pool_data; + EGG_SECURE_GLOBALS.pool_data = pool; pool->length = len; pool->used = 0; pool->unused = NULL; @@ -197,7 +205,7 @@ pool_alloc (void) pool->n_items = (len - sizeof (Pool)) / sizeof (Item); for (i = 0; i < pool->n_items; ++i) unused_push (&pool->unused, pool->items + i); - + #ifdef WITH_VALGRIND VALGRIND_CREATE_MEMPOOL(pool, 0, 0); #endif @@ -219,11 +227,12 @@ pool_free (void* item) { Pool *pool, **at; char *ptr, *beg, *end; - + ptr = item; - + /* Find which block this one belongs to */ - for (at = &all_pools, pool = *at; pool; at = &pool->next, pool = *at) { + for (at = (Pool **)&EGG_SECURE_GLOBALS.pool_data, pool = *at; + pool != NULL; at = &pool->next, pool = *at) { beg = (char*)pool->items; end = (char*)pool + pool->length - sizeof (Item); if (ptr >= beg && ptr <= end) { @@ -266,17 +275,17 @@ pool_valid (void* item) { Pool *pool; char *ptr, *beg, *end; - + ptr = item; - + /* Find which block this one belongs to */ - for (pool = all_pools; pool; pool = pool->next) { + for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) { beg = (char*)pool->items; end = (char*)pool + pool->length - sizeof (Item); - if (ptr >= beg && ptr <= end) + if (ptr >= beg && ptr <= end) return (pool->used && (ptr - beg) % sizeof (Item) == 0); } - + return 0; } @@ -284,9 +293,9 @@ pool_valid (void* item) /* ----------------------------------------------------------------------------- * SEC ALLOCATION - * + * * Each memory cell begins and ends with a pointer to its metadata. These are also - * used as guards or red zones. Since they're treated as redzones by valgrind we + * used as guards or red zones. Since they're treated as redzones by valgrind we * have to jump through a few hoops before reading and/or writing them. */ @@ -306,11 +315,11 @@ sec_write_guards (Cell *cell) ((void**)cell->words)[0] = (void*)cell; ((void**)cell->words)[cell->n_words - 1] = (void*)cell; - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t)); VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t)); -#endif +#endif } static inline void @@ -318,16 +327,16 @@ sec_check_guards (Cell *cell) { #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (cell->words, sizeof (word_t)); - VALGRIND_MAKE_MEM_DEFINED (cell->words + cell->n_words - 1, sizeof (word_t)); -#endif - + VALGRIND_MAKE_MEM_DEFINED (cell->words + cell->n_words - 1, sizeof (word_t)); +#endif + ASSERT(((void**)cell->words)[0] == (void*)cell); ASSERT(((void**)cell->words)[cell->n_words - 1] == (void*)cell); - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t)); VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t)); -#endif +#endif } static void @@ -338,9 +347,9 @@ sec_insert_cell_ring (Cell **ring, Cell *cell) ASSERT (cell != *ring); ASSERT (cell->next == NULL); ASSERT (cell->prev == NULL); - - /* Insert back into the mix of available memory */ - if (*ring) { + + /* Insert back into the mix of available memory */ + if (*ring) { cell->next = (*ring)->next; cell->prev = *ring; cell->next->prev = cell; @@ -349,7 +358,7 @@ sec_insert_cell_ring (Cell **ring, Cell *cell) cell->next = cell; cell->prev = cell; } - + *ring = cell; ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); @@ -382,7 +391,7 @@ sec_remove_cell_ring (Cell **ring, Cell *cell) cell->next->prev = cell->prev; cell->prev->next = cell->next; cell->next = cell->prev = NULL; - + ASSERT (*ring != cell); } @@ -431,10 +440,10 @@ static Cell* sec_neighbor_before (Block *block, Cell *cell) { word_t *word; - + ASSERT (cell); ASSERT (block); - + word = cell->words - 1; if (!sec_is_valid_word (block, word)) return NULL; @@ -442,7 +451,7 @@ sec_neighbor_before (Block *block, Cell *cell) #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif - + cell = *word; sec_check_guards (cell); @@ -453,14 +462,14 @@ sec_neighbor_before (Block *block, Cell *cell) return cell; } -static Cell* +static Cell* sec_neighbor_after (Block *block, Cell *cell) { word_t *word; - + ASSERT (cell); ASSERT (block); - + word = cell->words + cell->n_words; if (!sec_is_valid_word (block, word)) return NULL; @@ -471,7 +480,7 @@ sec_neighbor_after (Block *block, Cell *cell) cell = *word; sec_check_guards (cell); - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t)); #endif @@ -487,7 +496,7 @@ sec_alloc (Block *block, Cell *cell, *other; size_t n_words; void *memory; - + ASSERT (block); ASSERT (length); ASSERT (tag); @@ -495,16 +504,16 @@ sec_alloc (Block *block, if (!block->unused_cells) return NULL; - /* - * Each memory allocation is aligned to a pointer size, and + /* + * Each memory allocation is aligned to a pointer size, and * then, sandwidched between two pointers to its meta data. * These pointers also act as guards. * - * We allocate memory in units of sizeof (void*) + * We allocate memory in units of sizeof (void*) */ - + n_words = sec_size_to_words (length) + 2; - + /* Look for a cell of at least our required size */ cell = block->unused_cells; while (cell->n_words < n_words) { @@ -514,7 +523,7 @@ sec_alloc (Block *block, break; } } - + if (!cell) return NULL; @@ -523,7 +532,7 @@ sec_alloc (Block *block, ASSERT (cell->prev); ASSERT (cell->words); sec_check_guards (cell); - + /* Steal from the cell if it's too long */ if (cell->n_words > n_words + WASTE) { other = pool_alloc (); @@ -533,13 +542,13 @@ sec_alloc (Block *block, other->words = cell->words; cell->n_words -= n_words; cell->words += n_words; - + sec_write_guards (other); sec_write_guards (cell); - + cell = other; } - + if (cell->next) sec_remove_cell_ring (&block->unused_cells, cell); @@ -548,11 +557,11 @@ sec_alloc (Block *block, cell->requested = length; sec_insert_cell_ring (&block->used_cells, cell); memory = sec_cell_to_memory (cell); - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED (memory, length); #endif - + return memset (memory, 0, length); } @@ -561,13 +570,13 @@ sec_free (Block *block, void *memory) { Cell *cell, *other; word_t *word; - + ASSERT (block); ASSERT (memory); - + word = memory; --word; - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif @@ -591,39 +600,39 @@ sec_free (Block *block, void *memory) /* Remove from the used cell ring */ sec_remove_cell_ring (&block->used_cells, cell); - /* Find previous unallocated neighbor, and merge if possible */ - other = sec_neighbor_before (block, cell); - if (other && other->requested == 0) { - ASSERT (other->tag == NULL); - ASSERT (other->next && other->prev); - other->n_words += cell->n_words; - sec_write_guards (other); - pool_free (cell); - cell = other; - } - - /* Find next unallocated neighbor, and merge if possible */ - other = sec_neighbor_after (block, cell); - if (other && other->requested == 0) { - ASSERT (other->tag == NULL); - ASSERT (other->next && other->prev); - other->n_words += cell->n_words; - other->words = cell->words; - if (cell->next) - sec_remove_cell_ring (&block->unused_cells, cell); - sec_write_guards (other); - pool_free (cell); - cell = other; - } + /* Find previous unallocated neighbor, and merge if possible */ + other = sec_neighbor_before (block, cell); + if (other && other->requested == 0) { + ASSERT (other->tag == NULL); + ASSERT (other->next && other->prev); + other->n_words += cell->n_words; + sec_write_guards (other); + pool_free (cell); + cell = other; + } - /* Add to the unused list if not already there */ - if (!cell->next) - sec_insert_cell_ring (&block->unused_cells, cell); + /* Find next unallocated neighbor, and merge if possible */ + other = sec_neighbor_after (block, cell); + if (other && other->requested == 0) { + ASSERT (other->tag == NULL); + ASSERT (other->next && other->prev); + other->n_words += cell->n_words; + other->words = cell->words; + if (cell->next) + sec_remove_cell_ring (&block->unused_cells, cell); + sec_write_guards (other); + pool_free (cell); + cell = other; + } - cell->tag = NULL; - cell->requested = 0; - --block->n_used; - return NULL; + /* Add to the unused list if not already there */ + if (!cell->next) + sec_insert_cell_ring (&block->unused_cells, cell); + + cell->tag = NULL; + cell->requested = 0; + --block->n_used; + return NULL; } static void @@ -674,7 +683,7 @@ sec_realloc (Block *block, /* Dig out where the meta should be */ word = memory; --word; - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif @@ -682,7 +691,7 @@ sec_realloc (Block *block, ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; - + /* Validate that it's actually for real */ sec_check_guards (cell); ASSERT (cell->requested > 0); @@ -701,17 +710,17 @@ sec_realloc (Block *block, cell->requested = length; alloc = sec_cell_to_memory (cell); - /* + /* * Even though we may be reusing the same cell, that doesn't * mean that the allocation is shrinking. It could have shrunk - * and is now expanding back some. - */ + * and is now expanding back some. + */ if (length < valid) sec_clear_undefined (alloc, length, valid); return alloc; } - + /* Need braaaaaiiiiiinsss... */ while (cell->n_words < n_words) { @@ -719,7 +728,7 @@ sec_realloc (Block *block, other = sec_neighbor_after (block, cell); if (!other || other->requested != 0) break; - + /* Eat the whole neighbor if not too big */ if (n_words - cell->n_words + WASTE >= other->n_words) { cell->n_words += other->n_words; @@ -736,7 +745,7 @@ sec_realloc (Block *block, sec_write_guards (cell); } } - + if (cell->n_words >= n_words) { cell->requested = length; cell->tag = tag; @@ -751,7 +760,7 @@ sec_realloc (Block *block, memcpy_with_vbits (alloc, memory, valid); sec_free (block, memory); } - + return alloc; } @@ -761,7 +770,7 @@ sec_allocated (Block *block, void *memory) { Cell *cell; word_t *word; - + ASSERT (block); ASSERT (memory); @@ -771,12 +780,12 @@ sec_allocated (Block *block, void *memory) #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif - + /* Lookup the meta for this memory block (using guard pointer) */ ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; - + sec_check_guards (cell); ASSERT (cell->requested > 0); ASSERT (cell->tag != NULL); @@ -808,10 +817,10 @@ sec_validate (Block *block) ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; - + /* Validate that it's actually for real */ sec_check_guards (cell); - + /* Is it an allocated block? */ if (cell->requested > 0) { ASSERT (cell->tag != NULL); @@ -820,7 +829,7 @@ sec_validate (Block *block) ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); ASSERT (cell->requested <= (cell->n_words - 2) * sizeof (word_t)); - + /* An unused block */ } else { ASSERT (cell->tag == NULL); @@ -829,7 +838,7 @@ sec_validate (Block *block) ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); } - + word += cell->n_words; if (word == last) break; @@ -846,7 +855,7 @@ sec_acquire_pages (size_t *sz, { void *pages; unsigned long pgsize; - + ASSERT (sz); ASSERT (*sz); ASSERT (during_tag); @@ -854,56 +863,56 @@ sec_acquire_pages (size_t *sz, /* Make sure sz is a multiple of the page size */ pgsize = getpagesize (); *sz = (*sz + pgsize -1) & ~(pgsize - 1); - + #if defined(HAVE_MLOCK) pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pages == MAP_FAILED) { - if (lock_warning && egg_secure_warnings) + if (show_warning && egg_secure_warnings) fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n", (unsigned long)*sz, during_tag, strerror (errno)); - lock_warning = 0; + show_warning = 0; return NULL; } - + if (mlock (pages, *sz) < 0) { - if (lock_warning && egg_secure_warnings && errno != EPERM) { + if (show_warning && egg_secure_warnings && errno != EPERM) { fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n", (unsigned long)*sz, during_tag, strerror (errno)); - lock_warning = 0; + show_warning = 0; } munmap (pages, *sz); return NULL; } - + DEBUG_ALLOC ("gkr-secure-memory: new block ", *sz); - - lock_warning = 1; + + show_warning = 1; return pages; - + #else - if (lock_warning && egg_secure_warnings) + if (show_warning && egg_secure_warnings) fprintf (stderr, "your system does not support private memory"); - lock_warning = 0; + show_warning = 0; return NULL; #endif } -static void +static void sec_release_pages (void *pages, size_t sz) { ASSERT (pages); ASSERT (sz % getpagesize () == 0); - + #if defined(HAVE_MLOCK) if (munlock (pages, sz) < 0 && egg_secure_warnings) fprintf (stderr, "couldn't unlock private memory: %s\n", strerror (errno)); - + if (munmap (pages, sz) < 0 && egg_secure_warnings) fprintf (stderr, "couldn't unmap private anonymous memory: %s\n", strerror (errno)); - + DEBUG_ALLOC ("gkr-secure-memory: freed block ", sz); - + #else ASSERT (FALSE); #endif @@ -915,7 +924,7 @@ sec_release_pages (void *pages, size_t sz) static Block *all_blocks = NULL; -static Block* +static Block* sec_block_create (size_t size, const char *during_tag) { @@ -941,7 +950,7 @@ sec_block_create (size_t size, /* The size above is a minimum, we're free to go bigger */ if (size < DEFAULT_BLOCK_SIZE) size = DEFAULT_BLOCK_SIZE; - + block->words = sec_acquire_pages (&size, during_tag); block->n_words = size / sizeof (word_t); if (!block->words) { @@ -949,11 +958,11 @@ sec_block_create (size_t size, pool_free (cell); return NULL; } - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (block->words, size); #endif - + /* The first cell to allocate from */ cell->words = block->words; cell->n_words = block->n_words; @@ -963,7 +972,7 @@ sec_block_create (size_t size, block->next = all_blocks; all_blocks = block; - + return block; } @@ -976,7 +985,7 @@ sec_block_destroy (Block *block) ASSERT (block); ASSERT (block->words); ASSERT (block->n_used == 0); - + /* Remove from the list */ for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) { if (bl == block) { @@ -984,7 +993,7 @@ sec_block_destroy (Block *block) break; } } - + /* Must have been found */ ASSERT (bl == block); ASSERT (block->used_cells == NULL); @@ -995,7 +1004,7 @@ sec_block_destroy (Block *block) sec_remove_cell_ring (&block->unused_cells, cell); pool_free (cell); } - + /* Release all pages of secure memory */ sec_release_pages (block->words, block->n_words * sizeof (word_t)); @@ -1019,46 +1028,46 @@ egg_secure_alloc_full (const char *tag, if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) - fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", - (unsigned long)length); + fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", + (unsigned long)length); return NULL; } /* Can't allocate zero bytes */ if (length == 0) return NULL; - + DO_LOCK (); - + for (block = all_blocks; block; block = block->next) { memory = sec_alloc (block, tag, length); if (memory) - break; + break; } - + /* None of the current blocks have space, allocate new */ if (!memory) { block = sec_block_create (length, tag); if (block) memory = sec_alloc (block, tag, length); } - + #ifdef WITH_VALGRIND if (memory != NULL) VALGRIND_MALLOCLIKE_BLOCK (memory, length, sizeof (void*), 1); #endif - + DO_UNLOCK (); - if (!memory && (flags & EGG_SECURE_USE_FALLBACK)) { - memory = egg_memory_fallback (NULL, length); + if (!memory && (flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback != NULL) { + memory = EGG_SECURE_GLOBALS.fallback (NULL, length); if (memory) /* Our returned memory is always zeroed */ memset (memory, 0, length); } - + if (!memory) errno = ENOMEM; - + return memory; } @@ -1078,20 +1087,20 @@ egg_secure_realloc_full (const char *tag, if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) - fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", + fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", (unsigned long)length); return NULL; } - + if (memory == NULL) return egg_secure_alloc_full (tag, length, flags); if (!length) { egg_secure_free_full (memory, flags); return NULL; } - + DO_LOCK (); - + /* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, memory)) { @@ -1106,10 +1115,10 @@ egg_secure_realloc_full (const char *tag, #ifdef WITH_VALGRIND /* Now tell valgrind about either the new block or old one */ - VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory, - alloc ? length : previous, + VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory, + alloc ? length : previous, sizeof (word_t), 1); -#endif +#endif break; } } @@ -1120,21 +1129,21 @@ egg_secure_realloc_full (const char *tag, if (block && block->n_used == 0) sec_block_destroy (block); - - DO_UNLOCK (); - + + DO_UNLOCK (); + if (!block) { - if ((flags & EGG_SECURE_USE_FALLBACK)) { - /* - * In this case we can't zero the returned memory, + if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) { + /* + * In this case we can't zero the returned memory, * because we don't know what the block size was. */ - return egg_memory_fallback (memory, length); + return EGG_SECURE_GLOBALS.fallback (memory, length); } else { if (egg_secure_warnings) - fprintf (stderr, "memory does not belong to gnome-keyring: 0x%08lx\n", + fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n", (unsigned long)memory); - ASSERT (0 && "memory does does not belong to gnome-keyring"); + ASSERT (0 && "memory does does not belong to secure memory pool"); return NULL; } } @@ -1146,7 +1155,7 @@ egg_secure_realloc_full (const char *tag, egg_secure_free_full (memory, flags); } } - + if (!alloc) errno = ENOMEM; @@ -1163,12 +1172,12 @@ void egg_secure_free_full (void *memory, int flags) { Block *block = NULL; - + if (memory == NULL) return; - + DO_LOCK (); - + /* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, memory)) @@ -1186,49 +1195,49 @@ egg_secure_free_full (void *memory, int flags) if (block->n_used == 0) sec_block_destroy (block); } - + DO_UNLOCK (); - + if (!block) { - if ((flags & EGG_SECURE_USE_FALLBACK)) { - egg_memory_fallback (memory, 0); + if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) { + EGG_SECURE_GLOBALS.fallback (memory, 0); } else { if (egg_secure_warnings) - fprintf (stderr, "memory does not belong to gnome-keyring: 0x%08lx\n", + fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n", (unsigned long)memory); - ASSERT (0 && "memory does does not belong to gnome-keyring"); + ASSERT (0 && "memory does does not belong to secure memory pool"); } } -} +} -int +int egg_secure_check (const void *memory) { Block *block = NULL; DO_LOCK (); - + /* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, (word_t*)memory)) break; } - + DO_UNLOCK (); - + return block == NULL ? 0 : 1; -} +} void egg_secure_validate (void) { Block *block = NULL; - + DO_LOCK (); - + for (block = all_blocks; block; block = block->next) sec_validate (block); - + DO_UNLOCK (); } @@ -1311,7 +1320,7 @@ egg_secure_strdup_full (const char *tag, if (!str) return NULL; - len = strlen (str) + 1; + len = strlen (str) + 1; res = (char *)egg_secure_alloc_full (tag, len, options); strcpy (res, str); return res; @@ -1343,10 +1352,10 @@ void egg_secure_clear (void *p, size_t length) { volatile char *vp; - + if (p == NULL) return; - + vp = (volatile char*)p; while (length) { *vp = 0xAA; @@ -1368,10 +1377,10 @@ egg_secure_strfree (char *str) { /* * If we're using unpageable 'secure' memory, then the free call - * should zero out the memory, but because on certain platforms + * should zero out the memory, but because on certain platforms * we may be using normal memory, zero it out here just in case. */ - + egg_secure_strclear (str); egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK); } diff --git a/egg/egg-secure-memory.h b/egg/egg-secure-memory.h index 1bfa82e..969dbd7 100644 --- a/egg/egg-secure-memory.h +++ b/egg/egg-secure-memory.h @@ -1,25 +1,25 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-secure-memory.h - library for allocating memory that is non-pageable - * - * Copyright (C) 2007 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Author: Stef Walter - */ + + Copyright (C) 2007 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter +*/ #ifndef EGG_SECURE_MEMORY_H #define EGG_SECURE_MEMORY_H @@ -27,49 +27,51 @@ #include /* ------------------------------------------------------------------- - * Low Level Secure Memory - * - * IMPORTANT: This is pure vanila standard C, no glib. We need this - * because certain consumers of this protocol need to be built + * Low Level Secure Memory + * + * IMPORTANT: This is pure vanila standard C, no glib. We need this + * because certain consumers of this protocol need to be built * without linking in any special libraries. ie: the PKCS#11 module. - * + * * Thread locking - * + * * In order to use these functions in a module the following functions - * must be defined somewhere, and provide appropriate locking for + * must be defined somewhere, and provide appropriate locking for * secure memory between threads: */ - -extern void egg_memory_lock (void); -extern void egg_memory_unlock (void); +typedef struct { + void (* lock) (void); + void (* unlock) (void); + void * (* fallback) (void *pointer, + size_t length); + void * pool_data; + const char * pool_version; +} egg_secure_glob; + +#define EGG_SECURE_POOL_VER_STR "1.0" +#define EGG_SECURE_GLOBALS SECMEM_pool_data_v1_0 + +#define EGG_SECURE_DEFINE_GLOBALS(lock, unlock, fallback) \ + egg_secure_glob EGG_SECURE_GLOBALS = { \ + lock, unlock, fallback, NULL, EGG_SECURE_POOL_VER_STR }; + +#define EGG_SECURE_DEFINE_GLIB_GLOBALS() \ + static GStaticMutex memory_mutex = G_STATIC_MUTEX_INIT; \ + static void egg_memory_lock (void) \ + { g_static_mutex_lock (&memory_mutex); } \ + static void egg_memory_unlock (void) \ + { g_static_mutex_unlock (&memory_mutex); } \ + EGG_SECURE_DEFINE_GLOBALS (egg_memory_lock, egg_memory_unlock, g_realloc); + +extern egg_secure_glob EGG_SECURE_GLOBALS; /* - * Allocation Fallbacks - * - * If we cannot allocate secure memory, then this function - * (defined elsewhere) will be called which has a chance to - * allocate other memory abort or do whatever. - * - * Same call semantics as realloc with regard to NULL and zeros - */ -extern void* egg_memory_fallback (void *p, size_t length); - -#define EGG_SECURE_GLIB_DEFINITIONS() \ - static GStaticMutex memory_mutex = G_STATIC_MUTEX_INIT; \ - void egg_memory_lock (void) \ - { g_static_mutex_lock (&memory_mutex); } \ - void egg_memory_unlock (void) \ - { g_static_mutex_unlock (&memory_mutex); } \ - void* egg_memory_fallback (void *p, size_t sz) \ - { return g_realloc (p, sz); } \ - -/* * Main functionality - * + * * Allocations return NULL on failure. - */ - + */ + #define EGG_SECURE_USE_FALLBACK 0x0001 #define EGG_SECURE_DECLARE(tag) \ @@ -90,13 +92,13 @@ void* egg_secure_alloc_full (const char *tag, size_t length, int options); void* egg_secure_realloc_full (const char *tag, void *p, size_t length, int options); -void egg_secure_free (void* p); +void egg_secure_free (void* p); -void egg_secure_free_full (void* p, int fallback); +void egg_secure_free_full (void* p, int fallback); void egg_secure_clear (void *p, size_t length); -int egg_secure_check (const void* p); +int egg_secure_check (const void* p); void egg_secure_validate (void); diff --git a/egg/tests/test-dh.c b/egg/tests/test-dh.c index ba9fcfc..a676f93 100644 --- a/egg/tests/test-dh.c +++ b/egg/tests/test-dh.c @@ -34,7 +34,7 @@ #include #include -EGG_SECURE_GLIB_DEFINITIONS (); +EGG_SECURE_DEFINE_GLIB_GLOBALS (); static void test_perform (void) diff --git a/egg/tests/test-hkdf.c b/egg/tests/test-hkdf.c index 93f16df..de1d196 100644 --- a/egg/tests/test-hkdf.c +++ b/egg/tests/test-hkdf.c @@ -33,7 +33,7 @@ #include -EGG_SECURE_GLIB_DEFINITIONS (); +EGG_SECURE_DEFINE_GLIB_GLOBALS (); static void test_hkdf_test_case_1 (void) diff --git a/egg/tests/test-secmem.c b/egg/tests/test-secmem.c index cee5bd9..e0b6e24 100644 --- a/egg/tests/test-secmem.c +++ b/egg/tests/test-secmem.c @@ -32,14 +32,14 @@ #include -EGG_SECURE_GLIB_DEFINITIONS (); +EGG_SECURE_DEFINE_GLIB_GLOBALS (); /* Declared in egg-secure-memory.c */ extern int egg_secure_warnings; EGG_SECURE_DECLARE (tests); -/* +/* * Each test looks like (on one line): * void unit_test_xxxxx (CuTest* cu) * @@ -93,7 +93,7 @@ test_realloc_across (void) g_assert (p != NULL); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, 1088)); - /* Reallocate to a large one, will have to have changed blocks */ + /* Reallocate to a large one, will have to have changed blocks */ p2 = egg_secure_realloc_full ("tests", p, 16200, 0); g_assert (p2 != NULL); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p2, 16200)); @@ -182,26 +182,25 @@ test_multialloc (void) case 0: /* Allocate some memory */ size = g_random_int_range (1, 16384); data = egg_secure_alloc (size); - g_assert (data); + g_assert (data != NULL); memset (data, 0xCAFEBABE, size); g_ptr_array_add (memory, data); break; case 1: /* Reallocate some memory */ index = g_random_int_range (0, memory->len); data = g_ptr_array_index (memory, index); - g_assert (data); + g_assert (data != NULL); size = g_random_int_range (1, 16384); data = egg_secure_realloc (data, size); - g_assert (data); + g_assert (data != NULL); memset (data, 0xCAFEBABE, size); g_ptr_array_index (memory, index) = data; break; case 2: /* Free some memory */ index = g_random_int_range (0, memory->len); - data = g_ptr_array_index (memory, index); - g_assert (data); + data = g_ptr_array_remove_index_fast (memory, index); + g_assert (data != NULL); egg_secure_free (data); - g_ptr_array_remove_index_fast (memory, index); break; default: g_assert_not_reached (); @@ -214,7 +213,8 @@ test_multialloc (void) } g_assert (memory->len == 0); - g_ptr_array_set_free_func (memory, egg_secure_free); + for (i = 0; i < memory->len; i++) + egg_secure_free (memory->pdata[i]); g_ptr_array_free (memory, TRUE); egg_secure_warnings = 1; diff --git a/libsecret/secret-service.c b/libsecret/secret-service.c index 9234db2..1d45fc4 100644 --- a/libsecret/secret-service.c +++ b/libsecret/secret-service.c @@ -104,7 +104,7 @@ * during a secret_service_get() or secret_service_new() operation. */ -EGG_SECURE_GLIB_DEFINITIONS (); +EGG_SECURE_DEFINE_GLIB_GLOBALS (); GQuark _secret_error_quark = 0;