diff options
author | Stef Walter <stef@memberwebs.com> | 2010-10-14 19:38:39 +0000 |
---|---|---|
committer | Stef Walter <stefw@collabora.co.uk> | 2011-09-10 13:30:24 +0200 |
commit | 3f60c65cc0f535362ad6eb77ec08e63c235110e2 (patch) | |
tree | ac0dac8545144b6502979892597103b322877042 | |
parent | 73b1ef9914933d6748c9295d7ba3e7410c1633dc (diff) | |
download | gnome-keyring-3f60c65cc0f535362ad6eb77ec08e63c235110e2.tar.gz |
Secure memory tagging
* Tag all secure memory with strings, and print out diagnostic
report of what's in use, upon request.
31 files changed, 342 insertions, 137 deletions
diff --git a/daemon/control/gkd-control-client.c b/daemon/control/gkd-control-client.c index a52dc0fa..70b80065 100644 --- a/daemon/control/gkd-control-client.c +++ b/daemon/control/gkd-control-client.c @@ -36,6 +36,8 @@ #include <sys/un.h> #include <sys/stat.h> +EGG_SECURE_DECLARE (control_client); + static int control_connect (const gchar *path) { diff --git a/daemon/control/gkd-control-server.c b/daemon/control/gkd-control-server.c index 6e062970..4e4db3ec 100644 --- a/daemon/control/gkd-control-server.c +++ b/daemon/control/gkd-control-server.c @@ -47,6 +47,8 @@ typedef struct _ControlData { gsize position; } ControlData; +EGG_SECURE_DECLARE (control_server); + /* ----------------------------------------------------------------------------------- * CONTROL SERVER */ diff --git a/daemon/dbus/gkd-secret-unlock.c b/daemon/dbus/gkd-secret-unlock.c index ff233e1e..0c466e79 100644 --- a/daemon/dbus/gkd-secret-unlock.c +++ b/daemon/dbus/gkd-secret-unlock.c @@ -83,6 +83,8 @@ G_DEFINE_TYPE_WITH_CODE (GkdSecretUnlock, gkd_secret_unlock, G_TYPE_OBJECT, static guint unique_prompt_number = 0; static GQueue unlock_prompt_queue = G_QUEUE_INIT; +EGG_SECURE_DECLARE (secret_unlock); + /* ----------------------------------------------------------------------------- * INTERNAL */ diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c index b60507d7..0fe17bc6 100644 --- a/daemon/gkd-main.c +++ b/daemon/gkd-main.c @@ -78,6 +78,8 @@ typedef int socklen_t; #define GKD_COMP_SSH "ssh" #define GKD_COMP_GPG "gpg" +EGG_SECURE_DECLARE (daemon_main); + /* ----------------------------------------------------------------------------- * COMMAND LINE */ @@ -322,6 +324,58 @@ prepare_logging () g_set_printerr_handler (printerr_handler); } +#ifdef WITH_TESTABLE + +static void +dump_diagnostics (void) +{ + egg_secure_rec *records; + egg_secure_rec *rec; + unsigned int count, i; + GHashTable *table; + GHashTableIter iter; + gsize request = 0; + gsize block = 0; + + g_printerr ("------------------- Secure Memory --------------------\n"); + g_printerr (" Tag Used Space\n"); + g_printerr ("------------------------------------------------------\n"); + + records = egg_secure_records (&count); + table = g_hash_table_new (g_str_hash, g_str_equal); + for (i = 0; i < count; i++) { + if (!records[i].tag) + records[i].tag = "<unused>"; + rec = g_hash_table_lookup (table, records[i].tag); + if (rec == NULL) + g_hash_table_insert (table, (gchar *)records[i].tag, &records[i]); + else { + rec->block_length += records[i].block_length; + rec->request_length += records[i].request_length; + } + block += records[i].block_length; + request += records[i].request_length; + } + + g_hash_table_iter_init (&iter, table); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&rec)) + g_printerr (" %-20s %12lu %16lu\n", rec->tag, + (unsigned long)rec->request_length, + (unsigned long)rec->block_length); + + if (count > 0) + g_printerr ("------------------------------------------------------\n"); + + g_printerr (" %-20s %12lu %16lu\n", "Total", + (unsigned long)request, (unsigned long)block); + g_printerr ("------------------------------------------------------\n"); + + g_hash_table_destroy (table); + free (records); +} + +#endif /* WITH_TESTABLE */ + /* ----------------------------------------------------------------------------- * SIGNALS */ @@ -343,6 +397,11 @@ signal_thread (gpointer user_data) } switch (sig) { + case SIGUSR1: +#ifdef WITH_TESTABLE + dump_diagnostics (); +#endif /* WITH_TESTABLE */ + break; case SIGPIPE: /* Ignore */ break; @@ -378,6 +437,7 @@ setup_signal_handling (GMainLoop *loop) sigaddset (&signal_set, SIGPIPE); sigaddset (&signal_set, SIGHUP); sigaddset (&signal_set, SIGTERM); + sigaddset (&signal_set, SIGUSR1); pthread_sigmask (SIG_BLOCK, &signal_set, NULL); res = pthread_create (&sig_thread, NULL, signal_thread, loop); diff --git a/daemon/gpg-agent/gkd-gpg-agent-ops.c b/daemon/gpg-agent/gkd-gpg-agent-ops.c index 97cb9462..58aeb8f3 100644 --- a/daemon/gpg-agent/gkd-gpg-agent-ops.c +++ b/daemon/gpg-agent/gkd-gpg-agent-ops.c @@ -44,6 +44,8 @@ #define COLLECTION "session" #define N_COLLECTION 7 +EGG_SECURE_DECLARE (gpg_agent_ops); + /* ---------------------------------------------------------------------------------- * PASSWORD STUFF */ diff --git a/daemon/ssh-agent/gkd-ssh-agent-ops.c b/daemon/ssh-agent/gkd-ssh-agent-ops.c index 691ebe07..a87e28e0 100644 --- a/daemon/ssh-agent/gkd-ssh-agent-ops.c +++ b/daemon/ssh-agent/gkd-ssh-agent-ops.c @@ -39,11 +39,12 @@ #include <string.h> #include <stdio.h> - #define V1_LABEL "SSH1 RSA Key" typedef gboolean (*ObjectForeachFunc) (GckObject *object, gpointer user_data); +EGG_SECURE_DECLARE (ssh_agent_ops); + /* ---------------------------------------------------------------------------- */ diff --git a/daemon/ssh-agent/gkd-ssh-agent.c b/daemon/ssh-agent/gkd-ssh-agent.c index 649d6814..2f836311 100644 --- a/daemon/ssh-agent/gkd-ssh-agent.c +++ b/daemon/ssh-agent/gkd-ssh-agent.c @@ -47,6 +47,8 @@ typedef int socklen_t; /* The loaded PKCS#11 modules */ static GList *pkcs11_modules = NULL; +EGG_SECURE_DECLARE (ssh_agent); + static gboolean read_all (int fd, guchar *buf, int len) { diff --git a/egg/egg-dh.c b/egg/egg-dh.c index bed524e8..85dec77c 100644 --- a/egg/egg-dh.c +++ b/egg/egg-dh.c @@ -27,6 +27,8 @@ /* Enabling this is a complete security compromise */ #define DEBUG_DH_SECRET 0 +EGG_SECURE_DECLARE (dh); + typedef struct _DHGroup { const gchar *name; guint bits; diff --git a/egg/egg-entry-buffer.c b/egg/egg-entry-buffer.c index afb4093b..cac1f2d3 100644 --- a/egg/egg-entry-buffer.c +++ b/egg/egg-entry-buffer.c @@ -28,6 +28,8 @@ #include <string.h> +EGG_SECURE_DECLARE (entry_buffer); + /* Initial size of buffer, in bytes */ #define MIN_SIZE 16 diff --git a/egg/egg-libgcrypt.c b/egg/egg-libgcrypt.c index 8e1eb70c..e5b3f558 100644 --- a/egg/egg-libgcrypt.c +++ b/egg/egg-libgcrypt.c @@ -28,6 +28,8 @@ #include <gcrypt.h> +EGG_SECURE_DECLARE (libgcrypt); + static void log_handler (gpointer unused, int unknown, const gchar *msg, va_list va) { diff --git a/egg/egg-openssl.c b/egg/egg-openssl.c index 63d92ab5..45daccb2 100644 --- a/egg/egg-openssl.c +++ b/egg/egg-openssl.c @@ -56,6 +56,8 @@ #define PEM_PREF_END "-----END " #define PEM_PREF_END_L 9 +EGG_SECURE_DECLARE (openssl); + static void parse_header_lines (const gchar *hbeg, const gchar *hend, GHashTable **result) { diff --git a/egg/egg-secure-memory.c b/egg/egg-secure-memory.c index facc9fe0..ab63d45f 100644 --- a/egg/egg-secure-memory.c +++ b/egg/egg-secure-memory.c @@ -97,20 +97,22 @@ typedef void* word_t; typedef struct _Cell { word_t *words; /* Pointer to secure memory */ size_t n_words; /* Amount of secure memory in words */ - size_t allocated; /* Amount actually requested by app, in bytes, 0 if unused */ - struct _Cell *next; /* Next in unused memory ring, or NULL if used */ - struct _Cell *prev; /* Previous in unused memory ring, or NULL if used */ + size_t requested; /* Amount actually requested by app, in bytes, 0 if unused */ + const char *tag; /* Tag which describes the allocation */ + struct _Cell *next; /* Next in memory ring */ + struct _Cell *prev; /* Previous in memory ring */ } Cell; /* * A block of secure memory. This structure is the header in that block. */ typedef struct _Block { - word_t *words; /* Actual memory hangs off here */ - size_t n_words; /* Number of words in block */ - size_t used; /* Number of used allocations */ - struct _Cell* unused; /* Ring of unused allocations */ - struct _Block *next; /* Next block in list */ + word_t *words; /* Actual memory hangs off here */ + size_t n_words; /* Number of words in block */ + size_t n_used; /* Number of used allocations */ + struct _Cell* used_cells; /* Ring of used allocations */ + struct _Cell* unused_cells; /* Ring of unused allocations */ + struct _Block *next; /* Next block in list */ } Block; /* ----------------------------------------------------------------------------- @@ -463,7 +465,9 @@ sec_neighbor_after (Block *block, Cell *cell) } static void* -sec_alloc (Block *block, size_t length) +sec_alloc (Block *block, + const char *tag, + size_t length) { Cell *cell, *other; size_t n_words; @@ -471,8 +475,9 @@ sec_alloc (Block *block, size_t length) ASSERT (block); ASSERT (length); + ASSERT (tag); - if (!block->unused) + if (!block->unused_cells) return NULL; /* @@ -486,10 +491,10 @@ sec_alloc (Block *block, size_t length) n_words = sec_size_to_words (length) + 2; /* Look for a cell of at least our required size */ - cell = block->unused; + cell = block->unused_cells; while (cell->n_words < n_words) { cell = cell->next; - if (cell == block->unused) { + if (cell == block->unused_cells) { cell = NULL; break; } @@ -497,8 +502,9 @@ sec_alloc (Block *block, size_t length) if (!cell) return NULL; - - ASSERT (cell->allocated == 0); + + ASSERT (cell->tag == NULL); + ASSERT (cell->requested == 0); ASSERT (cell->prev); ASSERT (cell->words); sec_check_guards (cell); @@ -520,10 +526,12 @@ sec_alloc (Block *block, size_t length) } if (cell->next) - sec_remove_cell_ring (&block->unused, cell); - - ++block->used; - cell->allocated = length; + sec_remove_cell_ring (&block->unused_cells, cell); + + ++block->n_used; + cell->tag = tag; + cell->requested = length; + sec_insert_cell_ring (&block->used_cells, cell); memory = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND @@ -559,16 +567,19 @@ sec_free (Block *block, void *memory) #endif sec_check_guards (cell); - sec_clear_memory (memory, 0, cell->allocated); + sec_clear_memory (memory, 0, cell->requested); sec_check_guards (cell); - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - ASSERT (cell->allocated > 0); + ASSERT (cell->requested > 0); + ASSERT (cell->tag != NULL); + + /* 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->allocated == 0) { + if (other && other->requested == 0) { + ASSERT (other->tag == NULL); ASSERT (other->next && other->prev); other->n_words += cell->n_words; sec_write_guards (other); @@ -578,12 +589,13 @@ sec_free (Block *block, void *memory) /* Find next unallocated neighbor, and merge if possible */ other = sec_neighbor_after (block, cell); - if (other && other->allocated == 0) { + 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, cell); + sec_remove_cell_ring (&block->unused_cells, cell); sec_write_guards (other); pool_free (cell); cell = other; @@ -591,25 +603,30 @@ sec_free (Block *block, void *memory) /* Add to the unused list if not already there */ if (!cell->next) - sec_insert_cell_ring (&block->unused, cell); - - cell->allocated = 0; - --block->used; + sec_insert_cell_ring (&block->unused_cells, cell); + + cell->tag = NULL; + cell->requested = 0; + --block->n_used; return NULL; } static void* -sec_realloc (Block *block, void *memory, size_t length) +sec_realloc (Block *block, + const char *tag, + void *memory, + size_t length) { Cell *cell, *other; word_t *word; size_t n_words; size_t valid; void *alloc; - + /* Standard realloc behavior, should have been handled elsewhere */ ASSERT (memory != NULL); ASSERT (length > 0); + ASSERT (tag != NULL); /* Dig out where the meta should be */ word = memory; @@ -625,13 +642,12 @@ sec_realloc (Block *block, void *memory, size_t length) /* Validate that it's actually for real */ sec_check_guards (cell); - ASSERT (cell->allocated > 0); - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - + ASSERT (cell->requested > 0); + ASSERT (cell->tag != NULL); + /* The amount of valid data */ - valid = cell->allocated; - + valid = cell->requested; + /* How many words we actually want */ n_words = sec_size_to_words (length) + 2; @@ -639,7 +655,7 @@ sec_realloc (Block *block, void *memory, size_t length) if (n_words <= cell->n_words) { /* TODO: No shrinking behavior yet */ - cell->allocated = length; + cell->requested = length; alloc = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND @@ -662,14 +678,14 @@ sec_realloc (Block *block, void *memory, size_t length) /* See if we have a neighbor who can give us some memory */ other = sec_neighbor_after (block, cell); - if (!other || other->allocated != 0) + 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; sec_write_guards (cell); - sec_remove_cell_ring (&block->unused, other); + sec_remove_cell_ring (&block->unused_cells, other); pool_free (other); /* Steal from the neighbor */ @@ -683,18 +699,19 @@ sec_realloc (Block *block, void *memory, size_t length) } if (cell->n_words >= n_words) { - cell->allocated = length; + cell->requested = length; + cell->tag = tag; alloc = sec_cell_to_memory (cell); - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (alloc, length); #endif return sec_clear_memory (alloc, valid, length); } - + /* That didn't work, try alloc/free */ - alloc = sec_alloc (block, length); + alloc = sec_alloc (block, tag, length); if (alloc) { memcpy (alloc, memory, valid); sec_free (block, memory); @@ -726,15 +743,14 @@ sec_allocated (Block *block, void *memory) cell = *word; sec_check_guards (cell); - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - ASSERT (cell->allocated > 0); - + ASSERT (cell->requested > 0); + ASSERT (cell->tag != NULL); + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t)); #endif - - return cell->allocated; + + return cell->requested; } static void @@ -757,15 +773,19 @@ sec_validate (Block *block) sec_check_guards (cell); /* Is it an allocated block? */ - if (cell->allocated > 0) { - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - ASSERT (cell->allocated <= (cell->n_words - 2) * sizeof (word_t)); + if (cell->requested > 0) { + ASSERT (cell->tag != NULL); + ASSERT (cell->next != NULL); + ASSERT (cell->prev != NULL); + 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->next); - ASSERT (cell->prev); + ASSERT (cell->tag == NULL); + ASSERT (cell->next != NULL); + ASSERT (cell->prev != NULL); ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); } @@ -781,13 +801,15 @@ sec_validate (Block *block) */ static void* -sec_acquire_pages (size_t *sz) +sec_acquire_pages (size_t *sz, + const char *during_tag) { void *pages; unsigned long pgsize; ASSERT (sz); ASSERT (*sz); + ASSERT (during_tag); /* Make sure sz is a multiple of the page size */ pgsize = getpagesize (); @@ -797,16 +819,16 @@ sec_acquire_pages (size_t *sz) pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pages == MAP_FAILED) { if (lock_warning && egg_secure_warnings) - fprintf (stderr, "couldn't map %lu bytes of private memory: %s\n", - (unsigned long)*sz, strerror (errno)); + fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n", + (unsigned long)*sz, during_tag, strerror (errno)); lock_warning = 0; return NULL; } if (mlock (pages, *sz) < 0) { if (lock_warning && egg_secure_warnings && errno != EPERM) { - fprintf (stderr, "couldn't lock %lu bytes of private memory: %s\n", - (unsigned long)*sz, strerror (errno)); + fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n", + (unsigned long)*sz, during_tag, strerror (errno)); lock_warning = 0; } munmap (pages, *sz); @@ -854,11 +876,14 @@ sec_release_pages (void *pages, size_t sz) static Block *all_blocks = NULL; static Block* -sec_block_create (size_t size) +sec_block_create (size_t size, + const char *during_tag) { Block *block; Cell *cell; + ASSERT (during_tag); + #if FORCE_FALLBACK_MEMORY /* We can force all all memory to be malloced */ return NULL; @@ -878,7 +903,7 @@ sec_block_create (size_t size) if (size < DEFAULT_BLOCK_SIZE) size = DEFAULT_BLOCK_SIZE; - block->words = sec_acquire_pages (&size); + block->words = sec_acquire_pages (&size, during_tag); block->n_words = size / sizeof (word_t); if (!block->words) { pool_free (block); @@ -893,10 +918,10 @@ sec_block_create (size_t size) /* The first cell to allocate from */ cell->words = block->words; cell->n_words = block->n_words; - cell->allocated = 0; + cell->requested = 0; sec_write_guards (cell); - sec_insert_cell_ring (&block->unused, cell); - + sec_insert_cell_ring (&block->unused_cells, cell); + block->next = all_blocks; all_blocks = block; @@ -911,7 +936,7 @@ sec_block_destroy (Block *block) ASSERT (block); ASSERT (block->words); - ASSERT (block->used == 0); + ASSERT (block->n_used == 0); /* Remove from the list */ for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) { @@ -923,11 +948,12 @@ sec_block_destroy (Block *block) /* Must have been found */ ASSERT (bl == block); + ASSERT (block->used_cells == NULL); /* Release all the meta data cells */ - while (block->unused) { - cell = block->unused; - sec_remove_cell_ring (&block->unused, cell); + while (block->unused_cells) { + cell = block->unused_cells; + sec_remove_cell_ring (&block->unused_cells, cell); pool_free (cell); } @@ -942,17 +968,16 @@ sec_block_destroy (Block *block) */ void* -egg_secure_alloc (size_t length) -{ - return egg_secure_alloc_full (length, GKR_SECURE_USE_FALLBACK); -} - -void* -egg_secure_alloc_full (size_t length, int flags) +egg_secure_alloc_full (const char *tag, + size_t length, + int flags) { Block *block; void *memory = NULL; - + + if (tag == NULL) + tag = "?"; + if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", @@ -967,16 +992,16 @@ egg_secure_alloc_full (size_t length, int flags) DO_LOCK (); for (block = all_blocks; block; block = block->next) { - memory = sec_alloc (block, length); + memory = sec_alloc (block, tag, length); if (memory) break; } /* None of the current blocks have space, allocate new */ if (!memory) { - block = sec_block_create (length); + block = sec_block_create (length, tag); if (block) - memory = sec_alloc (block, length); + memory = sec_alloc (block, tag, length); } #ifdef WITH_VALGRIND @@ -985,8 +1010,8 @@ egg_secure_alloc_full (size_t length, int flags) #endif DO_UNLOCK (); - - if (!memory && (flags & GKR_SECURE_USE_FALLBACK)) { + + if (!memory && (flags & EGG_SECURE_USE_FALLBACK)) { memory = egg_memory_fallback (NULL, length); if (memory) /* Our returned memory is always zeroed */ memset (memory, 0, length); @@ -999,19 +1024,19 @@ egg_secure_alloc_full (size_t length, int flags) } void* -egg_secure_realloc (void *memory, size_t length) -{ - return egg_secure_realloc_full (memory, length, GKR_SECURE_USE_FALLBACK); -} - -void* -egg_secure_realloc_full (void *memory, size_t length, int flags) +egg_secure_realloc_full (const char *tag, + void *memory, + size_t length, + int flags) { Block *block = NULL; size_t previous = 0; int donew = 0; void *alloc = NULL; - + + if (tag == NULL) + tag = "?"; + if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", @@ -1020,7 +1045,7 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) } if (memory == NULL) - return egg_secure_alloc_full (length, flags); + return egg_secure_alloc_full (tag, length, flags); if (!length) { egg_secure_free_full (memory, flags); return NULL; @@ -1038,8 +1063,8 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t)); #endif - alloc = sec_realloc (block, memory, length); - + alloc = sec_realloc (block, tag, memory, length); + #ifdef WITH_VALGRIND /* Now tell valgrind about either the new block or old one */ VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory, @@ -1054,13 +1079,13 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) if (block && !alloc) donew = 1; - if (block && block->used == 0) + if (block && block->n_used == 0) sec_block_destroy (block); DO_UNLOCK (); if (!block) { - if ((flags & GKR_SECURE_USE_FALLBACK)) { + if ((flags & EGG_SECURE_USE_FALLBACK)) { /* * In this case we can't zero the returned memory, * because we don't know what the block size was. @@ -1074,9 +1099,9 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) return NULL; } } - + if (donew) { - alloc = egg_secure_alloc_full (length, flags); + alloc = egg_secure_alloc_full (tag, length, flags); if (alloc) { memcpy (alloc, memory, previous); egg_secure_free_full (memory, flags); @@ -1092,7 +1117,7 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) void egg_secure_free (void *memory) { - egg_secure_free_full (memory, GKR_SECURE_USE_FALLBACK); + egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK); } void @@ -1119,14 +1144,14 @@ egg_secure_free_full (void *memory, int flags) if (block != NULL) { sec_free (block, memory); - if (block->used == 0) + if (block->n_used == 0) sec_block_destroy (block); } DO_UNLOCK (); if (!block) { - if ((flags & GKR_SECURE_USE_FALLBACK)) { + if ((flags & EGG_SECURE_USE_FALLBACK)) { egg_memory_fallback (memory, 0); } else { if (egg_secure_warnings) @@ -1168,35 +1193,87 @@ egg_secure_validate (void) DO_UNLOCK (); } -void -egg_secure_dump_blocks (void) + +static egg_secure_rec * +records_for_ring (Cell *cell_ring, + egg_secure_rec *records, + unsigned int *count, + unsigned int *total) { + egg_secure_rec *new_rec; + unsigned int allocated = *count; + Cell *cell; + + cell = cell_ring; + do { + if (*count >= allocated) { + new_rec = realloc (records, sizeof (egg_secure_rec) * (allocated + 32)); + if (new_rec == NULL) { + *count = 0; + free (records); + return NULL; + } else { + records = new_rec; + allocated += 32; + } + } + + if (cell != NULL) { + records[*count].request_length = cell->requested; + records[*count].block_length = cell->n_words * sizeof (word_t); + records[*count].tag = cell->tag; + (*count)++; + (*total) += cell->n_words; + cell = cell->next; + } + } while (cell != NULL && cell != cell_ring); + + return records; +} + +egg_secure_rec * +egg_secure_records (unsigned int *count) +{ + egg_secure_rec *records = NULL; Block *block = NULL; + unsigned int total; + + *count = 0; DO_LOCK (); - - /* Find out where it belongs to */ - for (block = all_blocks; block; block = block->next) { - fprintf (stderr, "----------------------------------------------------\n"); - fprintf (stderr, " BLOCK at: 0x%08lx len: %lu\n", (unsigned long)block, - (unsigned long)block->n_words * sizeof (word_t)); - fprintf (stderr, "\n"); + + for (block = all_blocks; block != NULL; block = block->next) { + total = 0; + + records = records_for_ring (block->unused_cells, records, count, &total); + if (records == NULL) + break; + records = records_for_ring (block->used_cells, records, count, &total); + if (records == NULL) + break; + + /* Make sure this actualy accounts for all memory */ + ASSERT (total == block->n_words); } - + DO_UNLOCK (); + + return records; } char* -egg_secure_strdup (const char *str) +egg_secure_strdup_full (const char *tag, + const char *str, + int options) { size_t len; char *res; - + if (!str) return NULL; - + len = strlen (str) + 1; - res = (char*)egg_secure_alloc (len); + res = (char *)egg_secure_alloc_full (tag, len, options); strcpy (res, str); return res; } @@ -1235,5 +1312,5 @@ egg_secure_strfree (char *str) */ egg_secure_strclear (str); - egg_secure_free_full (str, GKR_SECURE_USE_FALLBACK); + egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK); } diff --git a/egg/egg-secure-memory.h b/egg/egg-secure-memory.h index 85ce1f69..682811d9 100644 --- a/egg/egg-secure-memory.h +++ b/egg/egg-secure-memory.h @@ -70,15 +70,22 @@ extern void* egg_memory_fallback (void *p, size_t length); * Allocations return NULL on failure. */ -#define GKR_SECURE_USE_FALLBACK 0x0001 +#define EGG_SECURE_USE_FALLBACK 0x0001 -void* egg_secure_alloc (size_t length); +#define EGG_SECURE_DECLARE(tag) \ + static inline void* egg_secure_alloc (size_t length) { \ + return egg_secure_alloc_full (G_STRINGIFY (tag), length, EGG_SECURE_USE_FALLBACK); \ + } \ + static inline void* egg_secure_realloc (void *p, size_t length) { \ + return egg_secure_realloc_full (G_STRINGIFY (tag), p, length, EGG_SECURE_USE_FALLBACK); \ + } \ + static inline void* egg_secure_strdup (const char *str) { \ + return egg_secure_strdup_full (G_STRINGIFY (tag), str, EGG_SECURE_USE_FALLBACK); \ + } -void* egg_secure_alloc_full (size_t length, int flags); +void* egg_secure_alloc_full (const char *tag, size_t length, int options); -void* egg_secure_realloc (void *p, size_t length); - -void* egg_secure_realloc_full (void *p, size_t length, int fallback); +void* egg_secure_realloc_full (const char *tag, void *p, size_t length, int options); void egg_secure_free (void* p); @@ -90,12 +97,18 @@ int egg_secure_check (const void* p); void egg_secure_validate (void); -void egg_secure_dump_blocks (void); - -char* egg_secure_strdup (const char *str); +char* egg_secure_strdup_full (const char *tag, const char *str, int options); void egg_secure_strclear (char *str); void egg_secure_strfree (char *str); +typedef struct { + const char *tag; + size_t request_length; + size_t block_length; +} egg_secure_rec; + +egg_secure_rec * egg_secure_records (unsigned int *count); + #endif /* EGG_SECURE_MEMORY_H */ diff --git a/egg/egg-symkey.c b/egg/egg-symkey.c index a69100f4..04d6a915 100644 --- a/egg/egg-symkey.c +++ b/egg/egg-symkey.c @@ -26,6 +26,8 @@ #include "egg-secure-memory.h" #include "egg-symkey.h" +EGG_SECURE_DECLARE (symkey); + /* ----------------------------------------------------------------------------- * QUARKS */ diff --git a/egg/tests/test-secmem.c b/egg/tests/test-secmem.c index b5ee4651..20beec93 100644 --- a/egg/tests/test-secmem.c +++ b/egg/tests/test-secmem.c @@ -37,7 +37,9 @@ EGG_SECURE_GLIB_DEFINITIONS (); /* 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) * @@ -69,7 +71,7 @@ test_alloc_free (void) gpointer p; gboolean ret; - p = egg_secure_alloc_full (512, 0); + p = egg_secure_alloc_full ("tests", 512, 0); g_assert (p != NULL); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, 512)); @@ -87,12 +89,12 @@ test_realloc_across (void) gpointer p, p2; /* Tiny allocation */ - p = egg_secure_realloc_full (NULL, 1088, 0); + p = egg_secure_realloc_full ("tests", NULL, 1088, 0); 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 */ - p2 = egg_secure_realloc_full (p, 16200, 0); + /* 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)); } @@ -103,13 +105,13 @@ test_alloc_two (void) gpointer p, p2; gboolean ret; - p2 = egg_secure_alloc_full (4, 0); + p2 = egg_secure_alloc_full ("tests", 4, 0); g_assert (p2 != NULL); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p2, 4)); memset (p2, 0x67, 4); - p = egg_secure_alloc_full (16200, 0); + p = egg_secure_alloc_full ("tests", 16200, 0); g_assert (p != NULL); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, 16200)); @@ -131,19 +133,19 @@ test_realloc (void) len = strlen (str) + 1; - p = egg_secure_realloc_full (NULL, len, 0); + p = egg_secure_realloc_full ("tests", NULL, len, 0); g_assert (p != NULL); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (p, len)); strcpy ((gchar*)p, str); - p2 = egg_secure_realloc_full (p, 512, 0); + p2 = egg_secure_realloc_full ("tests", p, 512, 0); g_assert (p2 != NULL); g_assert_cmpint (G_MAXSIZE, ==, find_non_zero (((gchar*)p2) + len, 512 - len)); g_assert (strcmp (p2, str) == 0); - p = egg_secure_realloc_full (p2, 0, 0); + p = egg_secure_realloc_full ("tests", p2, 0, 0); g_assert (p == NULL); } @@ -220,7 +222,7 @@ test_clear (void) { gpointer p; - p = egg_secure_alloc_full (188, 0); + p = egg_secure_alloc_full ("tests", 188, 0); g_assert (p != NULL); memset (p, 0x89, 188); g_assert (memchr (p, 0x89, 188) == p); diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c index e4585b7b..ade1ae9e 100644 --- a/gcr/gcr-parser.c +++ b/gcr/gcr-parser.c @@ -164,6 +164,8 @@ static const ParserFormat parser_normal[]; static const ParserFormat parser_formats[]; static ParserFormat* parser_format_lookup (gint format_id); +EGG_SECURE_DECLARE (parser); + /* ----------------------------------------------------------------------------- * QUARK DEFINITIONS */ diff --git a/pkcs11/gkm/gkm-aes-key.c b/pkcs11/gkm/gkm-aes-key.c index 71f9e088..d80d15d8 100644 --- a/pkcs11/gkm/gkm-aes-key.c +++ b/pkcs11/gkm/gkm-aes-key.c @@ -47,6 +47,8 @@ static const CK_MECHANISM_TYPE GKM_AES_MECHANISMS[] = { CKM_G_HKDF_SHA256_DERIVE }; +EGG_SECURE_DECLARE (aes_key); + /* ----------------------------------------------------------------------------- * INTERNAL */ diff --git a/pkcs11/gkm/gkm-aes-mechanism.c b/pkcs11/gkm/gkm-aes-mechanism.c index 9742450c..898aa410 100644 --- a/pkcs11/gkm/gkm-aes-mechanism.c +++ b/pkcs11/gkm/gkm-aes-mechanism.c @@ -31,6 +31,8 @@ #include "egg/egg-padding.h" #include "egg/egg-secure-memory.h" +EGG_SECURE_DECLARE (aes_mechanism); + static CK_RV retrieve_length (GkmSession *session, GkmObject *wrapped, gsize *length) { diff --git a/pkcs11/gkm/gkm-data-der.c b/pkcs11/gkm/gkm-data-der.c index 8e606518..06372022 100644 --- a/pkcs11/gkm/gkm-data-der.c +++ b/pkcs11/gkm/gkm-data-der.c @@ -36,6 +36,8 @@ #include <glib.h> #include <gcrypt.h> +EGG_SECURE_DECLARE (data_der); + /* ----------------------------------------------------------------------------- * QUARKS */ diff --git a/pkcs11/gkm/gkm-dh-mechanism.c b/pkcs11/gkm/gkm-dh-mechanism.c index 446defbd..3f80be15 100644 --- a/pkcs11/gkm/gkm-dh-mechanism.c +++ b/pkcs11/gkm/gkm-dh-mechanism.c @@ -32,6 +32,8 @@ #include "egg/egg-libgcrypt.h" #include "egg/egg-secure-memory.h" +EGG_SECURE_DECLARE (dh_mechanism); + static GkmObject* create_dh_object (GkmSession *session, GkmTransaction *transaction, CK_OBJECT_CLASS klass, CK_ATTRIBUTE_PTR value, CK_ATTRIBUTE_PTR prime, CK_ATTRIBUTE_PTR base, diff --git a/pkcs11/gkm/gkm-generic-key.c b/pkcs11/gkm/gkm-generic-key.c index 834f152b..6ea5fdba 100644 --- a/pkcs11/gkm/gkm-generic-key.c +++ b/pkcs11/gkm/gkm-generic-key.c @@ -46,6 +46,8 @@ static const CK_MECHANISM_TYPE GKM_GENERIC_MECHANISMS[] = { CKM_G_HKDF_SHA256_DERIVE }; +EGG_SECURE_DECLARE (generic_key); + /* ----------------------------------------------------------------------------- * INTERNAL */ diff --git a/pkcs11/gkm/gkm-hkdf-mechanism.c b/pkcs11/gkm/gkm-hkdf-mechanism.c index bbca94f3..be37d1c8 100644 --- a/pkcs11/gkm/gkm-hkdf-mechanism.c +++ b/pkcs11/gkm/gkm-hkdf-mechanism.c @@ -32,6 +32,8 @@ #include "egg/egg-libgcrypt.h" #include "egg/egg-secure-memory.h" +EGG_SECURE_DECLARE (hkdf_mechanism); + CK_RV gkm_hkdf_mechanism_derive (GkmSession *session, const char *algo, CK_MECHANISM_PTR mech, GkmObject *base, diff --git a/pkcs11/gkm/gkm-null-mechanism.c b/pkcs11/gkm/gkm-null-mechanism.c index d1016bf9..b08360c1 100644 --- a/pkcs11/gkm/gkm-null-mechanism.c +++ b/pkcs11/gkm/gkm-null-mechanism.c @@ -30,6 +30,8 @@ #include "egg/egg-libgcrypt.h" #include "egg/egg-secure-memory.h" +EGG_SECURE_DECLARE (null_mechanism); + static CK_RV retrieve_length (GkmSession *session, GkmObject *wrapped, gsize *length) { diff --git a/pkcs11/gkm/gkm-secret.c b/pkcs11/gkm/gkm-secret.c index ca9a36e9..0951a55e 100644 --- a/pkcs11/gkm/gkm-secret.c +++ b/pkcs11/gkm/gkm-secret.c @@ -35,6 +35,8 @@ struct _GkmSecret { G_DEFINE_TYPE (GkmSecret, gkm_secret, G_TYPE_OBJECT); +EGG_SECURE_DECLARE (secret); + /* ----------------------------------------------------------------------------- * OBJECT */ diff --git a/pkcs11/gnome2-store/gkm-gnome2-file.c b/pkcs11/gnome2-store/gkm-gnome2-file.c index 4dafd5d1..f933b769 100644 --- a/pkcs11/gnome2-store/gkm-gnome2-file.c +++ b/pkcs11/gnome2-store/gkm-gnome2-file.c @@ -90,6 +90,8 @@ typedef GkmDataResult (*BlockFunc) (guint block, EggBuffer *buffer, GkmSecret *l #define UNUSED_VALUE GUINT_TO_POINTER (1) +EGG_SECURE_DECLARE (data_file); + /* ----------------------------------------------------------------------------- * HELPERS */ diff --git a/pkcs11/secret-store/gkm-secret-binary.c b/pkcs11/secret-store/gkm-secret-binary.c index 29cd9cdc..9468c862 100644 --- a/pkcs11/secret-store/gkm-secret-binary.c +++ b/pkcs11/secret-store/gkm-secret-binary.c @@ -52,6 +52,8 @@ #include <string.h> #include <unistd.h> +EGG_SECURE_DECLARE (secret_binary); + /* ----------------------------------------------------------------------------- * DECLARATIONS */ diff --git a/pkcs11/wrap-layer/gkm-wrap-login.c b/pkcs11/wrap-layer/gkm-wrap-login.c index d17b7ff2..5b563c54 100644 --- a/pkcs11/wrap-layer/gkm-wrap-login.c +++ b/pkcs11/wrap-layer/gkm-wrap-login.c @@ -39,6 +39,8 @@ /* Holds failed unlock password, accessed atomically */ static gpointer unlock_failure = NULL; +EGG_SECURE_DECLARE (wrap_login); + void gkm_wrap_layer_mark_login_unlock_success (void) { diff --git a/ui/gku-prompt-tool.c b/ui/gku-prompt-tool.c index c719b23a..e8bf93a3 100644 --- a/ui/gku-prompt-tool.c +++ b/ui/gku-prompt-tool.c @@ -67,6 +67,8 @@ static gsize n_the_key = 0; * @short_description: Displays a propmt for 3rd party programs (ssh, gnupg) **/ +EGG_SECURE_DECLARE (prompt_tool); + /* ------------------------------------------------------------------------------ */ /** diff --git a/ui/gku-prompt-util.c b/ui/gku-prompt-util.c index 2d163599..27aa1f2a 100644 --- a/ui/gku-prompt-util.c +++ b/ui/gku-prompt-util.c @@ -29,6 +29,8 @@ #include "egg/egg-padding.h" #include "egg/egg-secure-memory.h" +EGG_SECURE_DECLARE (prompt); + void gku_prompt_util_encode_mpi (GKeyFile *key_file, const gchar *section, const gchar *field, gcry_mpi_t mpi) diff --git a/ui/gku-prompt.c b/ui/gku-prompt.c index abcb82f6..dc1a6109 100644 --- a/ui/gku-prompt.c +++ b/ui/gku-prompt.c @@ -96,6 +96,8 @@ const struct { const gchar *section; const gchar *name; } SOFT_RESET[] = { { "details", "expanded" }, }; +EGG_SECURE_DECLARE (prompt); + /* ----------------------------------------------------------------------------- * INTERNAL */ diff --git a/ui/tests/test-util.c b/ui/tests/test-util.c index 0cb92121..65e471da 100644 --- a/ui/tests/test-util.c +++ b/ui/tests/test-util.c @@ -35,6 +35,8 @@ EGG_SECURE_GLIB_DEFINITIONS (); +EGG_SECURE_DECLARE (test_util); + typedef struct { GKeyFile *key_file; } Test; |