LCOV - code coverage report
Current view: top level - egg - egg-secure-memory.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 84.5 % 561 474
Test Date: 2024-12-15 20:37:51 Functions: 95.0 % 40 38

            Line data    Source code
       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
       3              : 
       4              :    Copyright (C) 2007 Stefan Walter
       5              : 
       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.
      10              : 
      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.
      15              : 
      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/>.
      19              : 
      20              :    Author: Stef Walter <stef@memberwebs.com>
      21              : */
      22              : 
      23              : /*
      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.
      27              :  */
      28              : 
      29              : #include "config.h"
      30              : 
      31              : #include "egg-secure-memory.h"
      32              : 
      33              : #include <sys/types.h>
      34              : #include <sys/mman.h>
      35              : #include <stddef.h>
      36              : #include <string.h>
      37              : #include <stdio.h>
      38              : #include <stdlib.h>
      39              : #include <errno.h>
      40              : #include <unistd.h>
      41              : #include <assert.h>
      42              : 
      43              : #ifdef WITH_VALGRIND
      44              : #include <valgrind/valgrind.h>
      45              : #include <valgrind/memcheck.h>
      46              : #endif
      47              : 
      48              : #define DEBUG_SECURE_MEMORY 0
      49              : 
      50              : #if DEBUG_SECURE_MEMORY
      51              : #define DEBUG_ALLOC(msg, n)     fprintf(stderr, "%s %lu bytes\n", msg, n);
      52              : #else
      53              : #define DEBUG_ALLOC(msg, n)
      54              : #endif
      55              : 
      56              : #define DEFAULT_BLOCK_SIZE 16384
      57              : 
      58              : /* Use our own assert to guarantee no glib allocations */
      59              : #ifndef ASSERT
      60              : #ifdef G_DISABLE_ASSERT
      61              : #define ASSERT(x)
      62              : #else
      63              : #define ASSERT(x) assert(x)
      64              : #endif
      65              : #endif
      66              : 
      67              : #define DO_LOCK() \
      68              :         EGG_SECURE_GLOBALS.lock ();
      69              : 
      70              : #define DO_UNLOCK() \
      71              :         EGG_SECURE_GLOBALS.unlock ();
      72              : 
      73              : static int show_warning = 1;
      74              : int egg_secure_warnings = 1;
      75              : 
      76              : /*
      77              :  * We allocate all memory in units of sizeof(void*). This
      78              :  * is our definition of 'word'.
      79              :  */
      80              : typedef void* word_t;
      81              : 
      82              : /* The amount of extra words we can allocate */
      83              : #define WASTE   4
      84              : 
      85              : /*
      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 ().
      89              :  */
      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 */
      97              : } Cell;
      98              : 
      99              : /*
     100              :  * A block of secure memory. This structure is the header in that block.
     101              :  */
     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 */
     109              : } Block;
     110              : 
     111              : /* -----------------------------------------------------------------------------
     112              :  * UNUSED STACK
     113              :  */
     114              : 
     115              : static inline void
     116       150654 : unused_push (void **stack, void *ptr)
     117              : {
     118       150654 :         ASSERT (ptr);
     119       150654 :         ASSERT (stack);
     120       150654 :         *((void**)ptr) = *stack;
     121       150654 :         *stack = ptr;
     122       150654 : }
     123              : 
     124              : static inline void*
     125        80353 : unused_pop (void **stack)
     126              : {
     127              :         void *ptr;
     128        80353 :         ASSERT (stack);
     129        80353 :         ptr = *stack;
     130        80353 :         *stack = *(void**)ptr;
     131        80353 :         return ptr;
     132              : 
     133              : }
     134              : 
     135              : static inline void*
     136       191804 : unused_peek (void **stack)
     137              : {
     138       191804 :         ASSERT (stack);
     139       191804 :         return *stack;
     140              : }
     141              : 
     142              : /* -----------------------------------------------------------------------------
     143              :  * POOL META DATA ALLOCATION
     144              :  *
     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.
     148              :  */
     149              : 
     150              : /* Pool allocates this data type */
     151              : typedef union _Item {
     152              :                 Cell cell;
     153              :                 Block block;
     154              : } Item;
     155              : 
     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 */
     163              : } Pool;
     164              : 
     165              : static void *
     166        80353 : pool_alloc (void)
     167              : {
     168              :         Pool *pool;
     169              :         void *pages, *item;
     170              :         size_t len, i;
     171              : 
     172        80353 :         if (!EGG_SECURE_GLOBALS.pool_version ||
     173        80353 :             strcmp (EGG_SECURE_GLOBALS.pool_version, EGG_SECURE_POOL_VER_STR) != 0) {
     174            0 :                 if (show_warning && egg_secure_warnings)
     175            0 :                         fprintf (stderr, "the secure memory pool version does not match the code '%s' != '%s'\n",
     176            0 :                                  EGG_SECURE_GLOBALS.pool_version ? EGG_SECURE_GLOBALS.pool_version : "(null)",
     177              :                                  EGG_SECURE_POOL_VER_STR);
     178            0 :                 show_warning = 0;
     179            0 :                 return NULL;
     180              :         }
     181              : 
     182              :         /* A pool with an available item */
     183       111872 :         for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
     184       111451 :                 if (unused_peek (&pool->unused))
     185        79932 :                         break;
     186              :         }
     187              : 
     188              :         /* Create a new pool */
     189        80353 :         if (pool == NULL) {
     190          421 :                 len = getpagesize () * 2;
     191          421 :                 pages = mmap (0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     192          421 :                 if (pages == MAP_FAILED)
     193            0 :                         return NULL;
     194              : 
     195              :                 /* Fill in the block header, and inlude in block list */
     196          421 :                 pool = pages;
     197          421 :                 pool->next = EGG_SECURE_GLOBALS.pool_data;
     198          421 :                 EGG_SECURE_GLOBALS.pool_data = pool;
     199          421 :                 pool->length = len;
     200          421 :                 pool->used = 0;
     201          421 :                 pool->unused = NULL;
     202              : 
     203              :                 /* Fill block with unused items */
     204          421 :                 pool->n_items = (len - sizeof (Pool)) / sizeof (Item);
     205        71149 :                 for (i = 0; i < pool->n_items; ++i)
     206        70728 :                         unused_push (&pool->unused, pool->items + i);
     207              : 
     208              : #ifdef WITH_VALGRIND
     209              :                 VALGRIND_CREATE_MEMPOOL(pool, 0, 0);
     210              : #endif
     211              :         }
     212              : 
     213        80353 :         ++pool->used;
     214        80353 :         ASSERT (unused_peek (&pool->unused));
     215        80353 :         item = unused_pop (&pool->unused);
     216              : 
     217              : #ifdef WITH_VALGRIND
     218              :         VALGRIND_MEMPOOL_ALLOC (pool, item, sizeof (Item));
     219              : #endif
     220              : 
     221        80353 :         return memset (item, 0, sizeof (Item));
     222              : }
     223              : 
     224              : static void
     225        80347 : pool_free (void* item)
     226              : {
     227              :         Pool *pool, **at;
     228              :         char *ptr, *beg, *end;
     229              : 
     230        80347 :         ptr = item;
     231              : 
     232              :         /* Find which block this one belongs to */
     233        80347 :         for (at = (Pool **)&EGG_SECURE_GLOBALS.pool_data, pool = *at;
     234       117202 :              pool != NULL; at = &pool->next, pool = *at) {
     235       117202 :                 beg = (char*)pool->items;
     236       117202 :                 end = (char*)pool + pool->length - sizeof (Item);
     237       117202 :                 if (ptr >= beg && ptr <= end) {
     238        80347 :                         ASSERT ((ptr - beg) % sizeof (Item) == 0);
     239        80347 :                         break;
     240              :                 }
     241              :         }
     242              : 
     243              :         /* Otherwise invalid meta */
     244        80347 :         ASSERT (at);
     245        80347 :         ASSERT (pool);
     246        80347 :         ASSERT (pool->used > 0);
     247              : 
     248              :         /* No more meta cells used in this block, remove from list, destroy */
     249        80347 :         if (pool->used == 1) {
     250          421 :                 *at = pool->next;
     251              : 
     252              : #ifdef WITH_VALGRIND
     253              :                 VALGRIND_DESTROY_MEMPOOL (pool);
     254              : #endif
     255              : 
     256          421 :                 munmap (pool, pool->length);
     257          421 :                 return;
     258              :         }
     259              : 
     260              : #ifdef WITH_VALGRIND
     261              :         VALGRIND_MEMPOOL_FREE (pool, item);
     262              :         VALGRIND_MAKE_MEM_UNDEFINED (item, sizeof (Item));
     263              : #endif
     264              : 
     265        79926 :         --pool->used;
     266        79926 :         memset (item, 0xCD, sizeof (Item));
     267        79926 :         unused_push (&pool->unused, item);
     268              : }
     269              : 
     270              : #ifndef G_DISABLE_ASSERT
     271              : 
     272              : static int
     273     19715221 : pool_valid (void* item)
     274              : {
     275              :         Pool *pool;
     276              :         char *ptr, *beg, *end;
     277              : 
     278     19715221 :         ptr = item;
     279              : 
     280              :         /* Find which block this one belongs to */
     281     33775427 :         for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
     282     33775427 :                 beg = (char*)pool->items;
     283     33775427 :                 end = (char*)pool + pool->length - sizeof (Item);
     284     33775427 :                 if (ptr >= beg && ptr <= end)
     285     19715221 :                         return (pool->used && (ptr - beg) % sizeof (Item) == 0);
     286              :         }
     287              : 
     288            0 :         return 0;
     289              : }
     290              : 
     291              : #endif /* G_DISABLE_ASSERT */
     292              : 
     293              : /* -----------------------------------------------------------------------------
     294              :  * SEC ALLOCATION
     295              :  *
     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.
     299              :  */
     300              : 
     301              : static inline size_t
     302      1892320 : sec_size_to_words (size_t length)
     303              : {
     304      1892320 :         return (length % sizeof (void*) ? 1 : 0) + (length / sizeof (void*));
     305              : }
     306              : 
     307              : static inline void
     308       154264 : sec_write_guards (Cell *cell)
     309              : {
     310              : #ifdef WITH_VALGRIND
     311              :         VALGRIND_MAKE_MEM_UNDEFINED (cell->words, sizeof (word_t));
     312              :         VALGRIND_MAKE_MEM_UNDEFINED (cell->words + cell->n_words - 1, sizeof (word_t));
     313              : #endif
     314              : 
     315       154264 :         ((void**)cell->words)[0] = (void*)cell;
     316       154264 :         ((void**)cell->words)[cell->n_words - 1] = (void*)cell;
     317              : 
     318              : #ifdef WITH_VALGRIND
     319              :         VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t));
     320              :         VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t));
     321              : #endif
     322       154264 : }
     323              : 
     324              : static inline void
     325     19868502 : sec_check_guards (Cell *cell)
     326              : {
     327              : #ifdef WITH_VALGRIND
     328              :         VALGRIND_MAKE_MEM_DEFINED (cell->words, sizeof (word_t));
     329              :         VALGRIND_MAKE_MEM_DEFINED (cell->words + cell->n_words - 1, sizeof (word_t));
     330              : #endif
     331              : 
     332     19868502 :         ASSERT(((void**)cell->words)[0] == (void*)cell);
     333     19868502 :         ASSERT(((void**)cell->words)[cell->n_words - 1] == (void*)cell);
     334              : 
     335              : #ifdef WITH_VALGRIND
     336              :         VALGRIND_MAKE_MEM_NOACCESS (cell->words, sizeof (word_t));
     337              :         VALGRIND_MAKE_MEM_NOACCESS (cell->words + cell->n_words - 1, sizeof (word_t));
     338              : #endif
     339     19868502 : }
     340              : 
     341              : static void
     342        73382 : sec_insert_cell_ring (Cell **ring, Cell *cell)
     343              : {
     344        73382 :         ASSERT (ring);
     345        73382 :         ASSERT (cell);
     346        73382 :         ASSERT (cell != *ring);
     347        73382 :         ASSERT (cell->next == NULL);
     348        73382 :         ASSERT (cell->prev == NULL);
     349              : 
     350              :         /* Insert back into the mix of available memory */
     351        73382 :         if (*ring) {
     352        32046 :                 cell->next = (*ring)->next;
     353        32046 :                 cell->prev = *ring;
     354        32046 :                 cell->next->prev = cell;
     355        32046 :                 cell->prev->next = cell;
     356              :         } else {
     357        41336 :                 cell->next = cell;
     358        41336 :                 cell->prev = cell;
     359              :         }
     360              : 
     361        73382 :         *ring = cell;
     362        73382 :         ASSERT (cell->next->prev == cell);
     363        73382 :         ASSERT (cell->prev->next == cell);
     364        73382 : }
     365              : 
     366              : static void
     367        73377 : sec_remove_cell_ring (Cell **ring, Cell *cell)
     368              : {
     369        73377 :         ASSERT (ring);
     370        73377 :         ASSERT (*ring);
     371        73377 :         ASSERT (cell->next);
     372        73377 :         ASSERT (cell->prev);
     373              : 
     374        73377 :         ASSERT (cell->next->prev == cell);
     375        73377 :         ASSERT (cell->prev->next == cell);
     376              : 
     377        73377 :         if (cell == *ring) {
     378              :                 /* The last meta? */
     379        57757 :                 if (cell->next == cell) {
     380        41334 :                         ASSERT (cell->prev == cell);
     381        41334 :                         *ring = NULL;
     382              : 
     383              :                 /* Just pointing to this meta */
     384              :                 } else {
     385        16423 :                         ASSERT (cell->prev != cell);
     386        16423 :                         *ring = cell->next;
     387              :                 }
     388              :         }
     389              : 
     390        73377 :         cell->next->prev = cell->prev;
     391        73377 :         cell->prev->next = cell->next;
     392        73377 :         cell->next = cell->prev = NULL;
     393              : 
     394        73377 :         ASSERT (*ring != cell);
     395        73377 : }
     396              : 
     397              : static inline void*
     398        67733 : sec_cell_to_memory (Cell *cell)
     399              : {
     400        67733 :         return cell->words + 1;
     401              : }
     402              : 
     403              : static inline int
     404     22694261 : sec_is_valid_word (Block *block, word_t *word)
     405              : {
     406     22694261 :         return (word >= block->words && word < block->words + block->n_words);
     407              : }
     408              : 
     409              : static inline void
     410        20879 : sec_clear_undefined (void *memory,
     411              :                      size_t from,
     412              :                      size_t to)
     413              : {
     414        20879 :         char *ptr = memory;
     415        20879 :         ASSERT (from <= to);
     416              : #ifdef WITH_VALGRIND
     417              :         VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
     418              : #endif
     419        20879 :         memset (ptr + from, 0, to - from);
     420              : #ifdef WITH_VALGRIND
     421              :         VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
     422              : #endif
     423        20879 : }
     424              : static inline void
     425        43044 : sec_clear_noaccess (void *memory, size_t from, size_t to)
     426              : {
     427        43044 :         char *ptr = memory;
     428        43044 :         ASSERT (from <= to);
     429              : #ifdef WITH_VALGRIND
     430              :         VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
     431              : #endif
     432        43044 :         memset (ptr + from, 0, to - from);
     433              : #ifdef WITH_VALGRIND
     434              :         VALGRIND_MAKE_MEM_NOACCESS (ptr + from, to - from);
     435              : #endif
     436        43044 : }
     437              : 
     438              : static Cell*
     439        43044 : sec_neighbor_before (Block *block, Cell *cell)
     440              : {
     441              :         word_t *word;
     442              : 
     443        43044 :         ASSERT (cell);
     444        43044 :         ASSERT (block);
     445              : 
     446        43044 :         word = cell->words - 1;
     447        43044 :         if (!sec_is_valid_word (block, word))
     448        26602 :                 return NULL;
     449              : 
     450              : #ifdef WITH_VALGRIND
     451              :         VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
     452              : #endif
     453              : 
     454        16442 :         cell = *word;
     455        16442 :         sec_check_guards (cell);
     456              : 
     457              : #ifdef WITH_VALGRIND
     458              :         VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
     459              : #endif
     460              : 
     461        16442 :         return cell;
     462              : }
     463              : 
     464              : static Cell*
     465        62058 : sec_neighbor_after (Block *block, Cell *cell)
     466              : {
     467              :         word_t *word;
     468              : 
     469        62058 :         ASSERT (cell);
     470        62058 :         ASSERT (block);
     471              : 
     472        62058 :         word = cell->words + cell->n_words;
     473        62058 :         if (!sec_is_valid_word (block, word))
     474        11309 :                 return NULL;
     475              : 
     476              : #ifdef WITH_VALGRIND
     477              :         VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
     478              : #endif
     479              : 
     480        50749 :         cell = *word;
     481        50749 :         sec_check_guards (cell);
     482              : 
     483              : #ifdef WITH_VALGRIND
     484              :         VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
     485              : #endif
     486              : 
     487        50749 :         return cell;
     488              : }
     489              : 
     490              : static void*
     491      1888798 : sec_alloc (Block *block,
     492              :            const char *tag,
     493              :            size_t length)
     494              : {
     495              :         Cell *cell, *other;
     496              :         size_t n_words;
     497              :         void *memory;
     498              : 
     499      1888798 :         ASSERT (block);
     500      1888798 :         ASSERT (length);
     501      1888798 :         ASSERT (tag);
     502              : 
     503      1888798 :         if (!block->unused_cells)
     504        29739 :                 return NULL;
     505              : 
     506              :         /*
     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.
     510              :          *
     511              :          * We allocate memory in units of sizeof (void*)
     512              :          */
     513              : 
     514      1859059 :         n_words = sec_size_to_words (length) + 2;
     515              : 
     516              :         /* Look for a cell of at least our required size */
     517      1859059 :         cell = block->unused_cells;
     518      2152057 :         while (cell->n_words < n_words) {
     519      2109011 :                 cell = cell->next;
     520      2109011 :                 if (cell == block->unused_cells) {
     521      1816013 :                         cell = NULL;
     522      1816013 :                         break;
     523              :                 }
     524              :         }
     525              : 
     526      1859059 :         if (!cell)
     527      1816013 :                 return NULL;
     528              : 
     529        43046 :         ASSERT (cell->tag == NULL);
     530        43046 :         ASSERT (cell->requested == 0);
     531        43046 :         ASSERT (cell->prev);
     532        43046 :         ASSERT (cell->words);
     533        43046 :         sec_check_guards (cell);
     534              : 
     535              :         /* Steal from the cell if it's too long */
     536        43046 :         if (cell->n_words > n_words + WASTE) {
     537        42319 :                 other = pool_alloc ();
     538        42319 :                 if (!other)
     539            0 :                         return NULL;
     540        42319 :                 other->n_words = n_words;
     541        42319 :                 other->words = cell->words;
     542        42319 :                 cell->n_words -= n_words;
     543        42319 :                 cell->words += n_words;
     544              : 
     545        42319 :                 sec_write_guards (other);
     546        42319 :                 sec_write_guards (cell);
     547              : 
     548        42319 :                 cell = other;
     549              :         }
     550              : 
     551        43046 :         if (cell->next)
     552          727 :                 sec_remove_cell_ring (&block->unused_cells, cell);
     553              : 
     554        43046 :         ++block->n_used;
     555        43046 :         cell->tag = tag;
     556        43046 :         cell->requested = length;
     557        43046 :         sec_insert_cell_ring (&block->used_cells, cell);
     558        43046 :         memory = sec_cell_to_memory (cell);
     559              : 
     560              : #ifdef WITH_VALGRIND
     561              :         VALGRIND_MAKE_MEM_UNDEFINED (memory, length);
     562              : #endif
     563              : 
     564        43046 :         return memset (memory, 0, length);
     565              : }
     566              : 
     567              : static void*
     568        43044 : sec_free (Block *block, void *memory)
     569              : {
     570              :         Cell *cell, *other;
     571              :         word_t *word;
     572              : 
     573        43044 :         ASSERT (block);
     574        43044 :         ASSERT (memory);
     575              : 
     576        43044 :         word = memory;
     577        43044 :         --word;
     578              : 
     579              : #ifdef WITH_VALGRIND
     580              :         VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
     581              : #endif
     582              : 
     583              :         /* Lookup the meta for this memory block (using guard pointer) */
     584        43044 :         ASSERT (sec_is_valid_word (block, word));
     585        43044 :         ASSERT (pool_valid (*word));
     586        43044 :         cell = *word;
     587              : 
     588              : #ifdef WITH_VALGRIND
     589              :         VALGRIND_MAKE_MEM_DEFINED (cell->words, cell->n_words * sizeof (word_t));
     590              : #endif
     591              : 
     592        43044 :         sec_check_guards (cell);
     593        43044 :         sec_clear_noaccess (memory, 0, cell->requested);
     594              : 
     595        43044 :         sec_check_guards (cell);
     596        43044 :         ASSERT (cell->requested > 0);
     597        43044 :         ASSERT (cell->tag != NULL);
     598              : 
     599              :         /* Remove from the used cell ring */
     600        43044 :         sec_remove_cell_ring (&block->used_cells, cell);
     601              : 
     602              :         /* Find previous unallocated neighbor, and merge if possible */
     603        43044 :         other = sec_neighbor_before (block, cell);
     604        43044 :         if (other && other->requested == 0) {
     605         7560 :                 ASSERT (other->tag == NULL);
     606         7560 :                 ASSERT (other->next && other->prev);
     607         7560 :                 other->n_words += cell->n_words;
     608         7560 :                 sec_write_guards (other);
     609         7560 :                 pool_free (cell);
     610         7560 :                 cell = other;
     611              :         }
     612              : 
     613              :         /* Find next unallocated neighbor, and merge if possible */
     614        43044 :         other = sec_neighbor_after (block, cell);
     615        43044 :         if (other && other->requested == 0) {
     616        28462 :                 ASSERT (other->tag == NULL);
     617        28462 :                 ASSERT (other->next && other->prev);
     618        28462 :                 other->n_words += cell->n_words;
     619        28462 :                 other->words = cell->words;
     620        28462 :                 if (cell->next)
     621         4297 :                         sec_remove_cell_ring (&block->unused_cells, cell);
     622        28462 :                 sec_write_guards (other);
     623        28462 :                 pool_free (cell);
     624        28462 :                 cell = other;
     625              :         }
     626              : 
     627              :         /* Add to the unused list if not already there */
     628        43044 :         if (!cell->next)
     629        11319 :                 sec_insert_cell_ring (&block->unused_cells, cell);
     630              : 
     631        43044 :         cell->tag = NULL;
     632        43044 :         cell->requested = 0;
     633        43044 :         --block->n_used;
     634        43044 :         return NULL;
     635              : }
     636              : 
     637              : static void
     638         8574 : memcpy_with_vbits (void *dest,
     639              :                    void *src,
     640              :                    size_t length)
     641              : {
     642              : #ifdef WITH_VALGRIND
     643              :         int vbits_setup = 0;
     644              :         void *vbits = NULL;
     645              : 
     646              :         if (RUNNING_ON_VALGRIND) {
     647              :                 vbits = malloc (length);
     648              :                 if (vbits != NULL)
     649              :                         vbits_setup = VALGRIND_GET_VBITS (src, vbits, length);
     650              :                 VALGRIND_MAKE_MEM_DEFINED (src, length);
     651              :         }
     652              : #endif
     653              : 
     654         8574 :         memcpy (dest, src, length);
     655              : 
     656              : #ifdef WITH_VALGRIND
     657              :         if (vbits_setup == 1) {
     658              :                 (void)VALGRIND_SET_VBITS (dest, vbits, length);
     659              :                 (void)VALGRIND_SET_VBITS (src, vbits, length);
     660              :         }
     661              :         free (vbits);
     662              : #endif
     663         8574 : }
     664              : 
     665              : static void*
     666        33261 : sec_realloc (Block *block,
     667              :              const char *tag,
     668              :              void *memory,
     669              :              size_t length)
     670              : {
     671              :         Cell *cell, *other;
     672              :         word_t *word;
     673              :         size_t n_words;
     674              :         size_t valid;
     675              :         void *alloc;
     676              : 
     677              :         /* Standard realloc behavior, should have been handled elsewhere */
     678        33261 :         ASSERT (memory != NULL);
     679        33261 :         ASSERT (length > 0);
     680        33261 :         ASSERT (tag != NULL);
     681              : 
     682              :         /* Dig out where the meta should be */
     683        33261 :         word = memory;
     684        33261 :         --word;
     685              : 
     686              : #ifdef WITH_VALGRIND
     687              :         VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
     688              : #endif
     689              : 
     690        33261 :         ASSERT (sec_is_valid_word (block, word));
     691        33261 :         ASSERT (pool_valid (*word));
     692        33261 :         cell = *word;
     693              : 
     694              :         /* Validate that it's actually for real */
     695        33261 :         sec_check_guards (cell);
     696        33261 :         ASSERT (cell->requested > 0);
     697        33261 :         ASSERT (cell->tag != NULL);
     698              : 
     699              :         /* The amount of valid data */
     700        33261 :         valid = cell->requested;
     701              : 
     702              :         /* How many words we actually want */
     703        33261 :         n_words = sec_size_to_words (length) + 2;
     704              : 
     705              :         /* Less memory is required than is in the cell */
     706        33261 :         if (n_words <= cell->n_words) {
     707              : 
     708              :                 /* TODO: No shrinking behavior yet */
     709        20470 :                 cell->requested = length;
     710        20470 :                 alloc = sec_cell_to_memory (cell);
     711              : 
     712              :                 /*
     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.
     716              :                  */
     717        20470 :                 if (length < valid)
     718        16662 :                         sec_clear_undefined (alloc, length, valid);
     719              : 
     720        20470 :                 return alloc;
     721              :         }
     722              : 
     723              :         /* Need braaaaaiiiiiinsss... */
     724        23231 :         while (cell->n_words < n_words) {
     725              : 
     726              :                 /* See if we have a neighbor who can give us some memory */
     727        19014 :                 other = sec_neighbor_after (block, cell);
     728        19014 :                 if (!other || other->requested != 0)
     729              :                         break;
     730              : 
     731              :                 /* Eat the whole neighbor if not too big */
     732        10440 :                 if (n_words - cell->n_words + WASTE >= other->n_words) {
     733         6293 :                         cell->n_words += other->n_words;
     734         6293 :                         sec_write_guards (cell);
     735         6293 :                         sec_remove_cell_ring (&block->unused_cells, other);
     736         6293 :                         pool_free (other);
     737              : 
     738              :                 /* Steal from the neighbor */
     739              :                 } else {
     740         4147 :                         other->words += n_words - cell->n_words;
     741         4147 :                         other->n_words -= n_words - cell->n_words;
     742         4147 :                         sec_write_guards (other);
     743         4147 :                         cell->n_words = n_words;
     744         4147 :                         sec_write_guards (cell);
     745              :                 }
     746              :         }
     747              : 
     748        12791 :         if (cell->n_words >= n_words) {
     749         4217 :                 cell->requested = length;
     750         4217 :                 cell->tag = tag;
     751         4217 :                 alloc = sec_cell_to_memory (cell);
     752         4217 :                 sec_clear_undefined (alloc, valid, length);
     753         4217 :                 return alloc;
     754              :         }
     755              : 
     756              :         /* That didn't work, try alloc/free */
     757         8574 :         alloc = sec_alloc (block, tag, length);
     758         8574 :         if (alloc) {
     759          276 :                 memcpy_with_vbits (alloc, memory, valid);
     760          276 :                 sec_free (block, memory);
     761              :         }
     762              : 
     763         8574 :         return alloc;
     764              : }
     765              : 
     766              : 
     767              : static size_t
     768        33261 : sec_allocated (Block *block, void *memory)
     769              : {
     770              :         Cell *cell;
     771              :         word_t *word;
     772              : 
     773        33261 :         ASSERT (block);
     774        33261 :         ASSERT (memory);
     775              : 
     776        33261 :         word = memory;
     777        33261 :         --word;
     778              : 
     779              : #ifdef WITH_VALGRIND
     780              :         VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
     781              : #endif
     782              : 
     783              :         /* Lookup the meta for this memory block (using guard pointer) */
     784        33261 :         ASSERT (sec_is_valid_word (block, word));
     785        33261 :         ASSERT (pool_valid (*word));
     786        33261 :         cell = *word;
     787              : 
     788        33261 :         sec_check_guards (cell);
     789        33261 :         ASSERT (cell->requested > 0);
     790        33261 :         ASSERT (cell->tag != NULL);
     791              : 
     792              : #ifdef WITH_VALGRIND
     793              :         VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
     794              : #endif
     795              : 
     796        33261 :         return cell->requested;
     797              : }
     798              : 
     799              : static void
     800      7873195 : sec_validate (Block *block)
     801              : {
     802              :         Cell *cell;
     803              :         word_t *word, *last;
     804              : 
     805              : #ifdef WITH_VALGRIND
     806              :         if (RUNNING_ON_VALGRIND)
     807              :                 return;
     808              : #endif
     809              : 
     810      7873195 :         word = block->words;
     811      7873195 :         last = word + block->n_words;
     812              : 
     813              :         for (;;) {
     814     19605655 :                 ASSERT (word < last);
     815              : 
     816     19605655 :                 ASSERT (sec_is_valid_word (block, word));
     817     19605655 :                 ASSERT (pool_valid (*word));
     818     19605655 :                 cell = *word;
     819              : 
     820              :                 /* Validate that it's actually for real */
     821     19605655 :                 sec_check_guards (cell);
     822              : 
     823              :                 /* Is it an allocated block? */
     824     19605655 :                 if (cell->requested > 0) {
     825     10486547 :                         ASSERT (cell->tag != NULL);
     826     10486547 :                         ASSERT (cell->next != NULL);
     827     10486547 :                         ASSERT (cell->prev != NULL);
     828     10486547 :                         ASSERT (cell->next->prev == cell);
     829     10486547 :                         ASSERT (cell->prev->next == cell);
     830     10486547 :                         ASSERT (cell->requested <= (cell->n_words - 2) * sizeof (word_t));
     831              : 
     832              :                 /* An unused block */
     833              :                 } else {
     834      9119108 :                         ASSERT (cell->tag == NULL);
     835      9119108 :                         ASSERT (cell->next != NULL);
     836      9119108 :                         ASSERT (cell->prev != NULL);
     837      9119108 :                         ASSERT (cell->next->prev == cell);
     838      9119108 :                         ASSERT (cell->prev->next == cell);
     839              :                 }
     840              : 
     841     19605655 :                 word += cell->n_words;
     842     19605655 :                 if (word == last)
     843      7873195 :                         break;
     844              :         }
     845      7873195 : }
     846              : 
     847              : /* -----------------------------------------------------------------------------
     848              :  * LOCKED MEMORY
     849              :  */
     850              : 
     851              : static void*
     852        19017 : sec_acquire_pages (size_t *sz,
     853              :                    const char *during_tag)
     854              : {
     855              :         void *pages;
     856              :         unsigned long pgsize;
     857              : 
     858        19017 :         ASSERT (sz);
     859        19017 :         ASSERT (*sz);
     860        19017 :         ASSERT (during_tag);
     861              : 
     862              :         /* Make sure sz is a multiple of the page size */
     863        19017 :         pgsize = getpagesize ();
     864        19017 :         *sz = (*sz + pgsize -1) & ~(pgsize - 1);
     865              : 
     866              : #if defined(HAVE_MLOCK)
     867        19017 :         pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     868        19017 :         if (pages == MAP_FAILED) {
     869            0 :                 if (show_warning && egg_secure_warnings)
     870            0 :                         fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n",
     871            0 :                                  (unsigned long)*sz, during_tag, strerror (errno));
     872            0 :                 show_warning = 0;
     873            0 :                 return NULL;
     874              :         }
     875              : 
     876        19017 :         if (mlock (pages, *sz) < 0) {
     877            0 :                 if (show_warning && egg_secure_warnings && errno != EPERM) {
     878            0 :                         fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n",
     879            0 :                                  (unsigned long)*sz, during_tag, strerror (errno));
     880            0 :                         show_warning = 0;
     881              :                 }
     882            0 :                 munmap (pages, *sz);
     883            0 :                 return NULL;
     884              :         }
     885              : 
     886              :         DEBUG_ALLOC ("gkr-secure-memory: new block ", *sz);
     887              : 
     888              : #if defined(MADV_DONTDUMP)
     889        19017 :         if (madvise (pages, *sz, MADV_DONTDUMP) < 0) {
     890            0 :                 if (show_warning && egg_secure_warnings) {
     891              :                         /*
     892              :                          * Not fatal - this was added in Linux 3.4 and older
     893              :                          * kernels will legitimately fail this at runtime
     894              :                          */
     895            0 :                         fprintf (stderr, "couldn't MADV_DONTDUMP %lu bytes of memory (%s): %s\n",
     896            0 :                                  (unsigned long)*sz, during_tag, strerror (errno));
     897              :                 }
     898              :         }
     899              : #endif
     900              : 
     901        19017 :         show_warning = 1;
     902        19017 :         return pages;
     903              : 
     904              : #else
     905              :         if (show_warning && egg_secure_warnings)
     906              :                 fprintf (stderr, "your system does not support private memory");
     907              :         show_warning = 0;
     908              :         return NULL;
     909              : #endif
     910              : 
     911              : }
     912              : 
     913              : static void
     914        19016 : sec_release_pages (void *pages, size_t sz)
     915              : {
     916        19016 :         ASSERT (pages);
     917        19016 :         ASSERT (sz % getpagesize () == 0);
     918              : 
     919              : #if defined(HAVE_MLOCK)
     920        19016 :         if (munlock (pages, sz) < 0 && egg_secure_warnings)
     921            0 :                 fprintf (stderr, "couldn't unlock private memory: %s\n", strerror (errno));
     922              : 
     923        19016 :         if (munmap (pages, sz) < 0 && egg_secure_warnings)
     924            0 :                 fprintf (stderr, "couldn't unmap private anonymous memory: %s\n", strerror (errno));
     925              : 
     926              :         DEBUG_ALLOC ("gkr-secure-memory: freed block ", sz);
     927              : 
     928              : #else
     929              :         ASSERT (FALSE);
     930              : #endif
     931        19016 : }
     932              : 
     933              : /* -----------------------------------------------------------------------------
     934              :  * MANAGE DIFFERENT BLOCKS
     935              :  */
     936              : 
     937              : static Block *all_blocks = NULL;
     938              : 
     939              : static Block*
     940        19017 : sec_block_create (size_t size,
     941              :                   const char *during_tag)
     942              : {
     943              :         Block *block;
     944              :         Cell *cell;
     945              : 
     946        19017 :         ASSERT (during_tag);
     947              : 
     948              :         /* We can force all all memory to be malloced */
     949        19017 :         if (getenv ("SECMEM_FORCE_FALLBACK"))
     950            0 :                 return NULL;
     951              : 
     952        19017 :         block = pool_alloc ();
     953        19017 :         if (!block)
     954            0 :                 return NULL;
     955              : 
     956        19017 :         cell = pool_alloc ();
     957        19017 :         if (!cell) {
     958            0 :                 pool_free (block);
     959            0 :                 return NULL;
     960              :         }
     961              : 
     962              :         /* The size above is a minimum, we're free to go bigger */
     963        19017 :         if (size < DEFAULT_BLOCK_SIZE)
     964        19017 :                 size = DEFAULT_BLOCK_SIZE;
     965              : 
     966        19017 :         block->words = sec_acquire_pages (&size, during_tag);
     967        19017 :         block->n_words = size / sizeof (word_t);
     968        19017 :         if (!block->words) {
     969            0 :                 pool_free (block);
     970            0 :                 pool_free (cell);
     971            0 :                 return NULL;
     972              :         }
     973              : 
     974              : #ifdef WITH_VALGRIND
     975              :         VALGRIND_MAKE_MEM_DEFINED (block->words, size);
     976              : #endif
     977              : 
     978              :         /* The first cell to allocate from */
     979        19017 :         cell->words = block->words;
     980        19017 :         cell->n_words = block->n_words;
     981        19017 :         cell->requested = 0;
     982        19017 :         sec_write_guards (cell);
     983        19017 :         sec_insert_cell_ring (&block->unused_cells, cell);
     984              : 
     985        19017 :         block->next = all_blocks;
     986        19017 :         all_blocks = block;
     987              : 
     988        19017 :         return block;
     989              : }
     990              : 
     991              : static void
     992        19016 : sec_block_destroy (Block *block)
     993              : {
     994              :         Block *bl, **at;
     995              :         Cell *cell;
     996              : 
     997        19016 :         ASSERT (block);
     998        19016 :         ASSERT (block->words);
     999        19016 :         ASSERT (block->n_used == 0);
    1000              : 
    1001              :         /* Remove from the list */
    1002       792187 :         for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) {
    1003       792187 :                 if (bl == block) {
    1004        19016 :                         *at = block->next;
    1005        19016 :                         break;
    1006              :                 }
    1007              :         }
    1008              : 
    1009              :         /* Must have been found */
    1010        19016 :         ASSERT (bl == block);
    1011        19016 :         ASSERT (block->used_cells == NULL);
    1012              : 
    1013              :         /* Release all the meta data cells */
    1014        38032 :         while (block->unused_cells) {
    1015        19016 :                 cell = block->unused_cells;
    1016        19016 :                 sec_remove_cell_ring (&block->unused_cells, cell);
    1017        19016 :                 pool_free (cell);
    1018              :         }
    1019              : 
    1020              :         /* Release all pages of secure memory */
    1021        19016 :         sec_release_pages (block->words, block->n_words * sizeof (word_t));
    1022              : 
    1023        19016 :         pool_free (block);
    1024        19016 : }
    1025              : 
    1026              : /* ------------------------------------------------------------------------
    1027              :  * PUBLIC FUNCTIONALITY
    1028              :  */
    1029              : 
    1030              : void*
    1031        42828 : egg_secure_alloc_full (const char *tag,
    1032              :                        size_t length,
    1033              :                        int flags)
    1034              : {
    1035              :         Block *block;
    1036        42828 :         void *memory = NULL;
    1037              : 
    1038        42828 :         if (tag == NULL)
    1039            0 :                 tag = "?";
    1040              : 
    1041        42828 :         if (length > 0xFFFFFFFF / 2) {
    1042            0 :                 if (egg_secure_warnings)
    1043            0 :                         fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n",
    1044              :                                  (unsigned long)length);
    1045            0 :                 return NULL;
    1046              :         }
    1047              : 
    1048              :         /* Can't allocate zero bytes */
    1049        42828 :         if (length == 0)
    1050            0 :                 return NULL;
    1051              : 
    1052        42828 :         DO_LOCK ();
    1053              : 
    1054      1880224 :                 for (block = all_blocks; block; block = block->next) {
    1055      1861207 :                         memory = sec_alloc (block, tag, length);
    1056      1861207 :                         if (memory)
    1057        23811 :                                 break;
    1058              :                 }
    1059              : 
    1060              :                 /* None of the current blocks have space, allocate new */
    1061        42828 :                 if (!memory) {
    1062        19017 :                         block = sec_block_create (length, tag);
    1063        19017 :                         if (block)
    1064        19017 :                                 memory = sec_alloc (block, tag, length);
    1065              :                 }
    1066              : 
    1067              : #ifdef WITH_VALGRIND
    1068              :                 if (memory != NULL)
    1069              :                         VALGRIND_MALLOCLIKE_BLOCK (memory, length, sizeof (void*), 1);
    1070              : #endif
    1071              : 
    1072        42828 :         DO_UNLOCK ();
    1073              : 
    1074        42828 :         if (!memory && (flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback != NULL) {
    1075           58 :                 memory = EGG_SECURE_GLOBALS.fallback (NULL, length);
    1076           58 :                 if (memory) /* Our returned memory is always zeroed */
    1077           58 :                         memset (memory, 0, length);
    1078              :         }
    1079              : 
    1080        42828 :         if (!memory)
    1081            0 :                 errno = ENOMEM;
    1082              : 
    1083        42828 :         return memory;
    1084              : }
    1085              : 
    1086              : void*
    1087        33868 : egg_secure_realloc_full (const char *tag,
    1088              :                          void *memory,
    1089              :                          size_t length,
    1090              :                          int flags)
    1091              : {
    1092        33868 :         Block *block = NULL;
    1093        33868 :         size_t previous = 0;
    1094        33868 :         int donew = 0;
    1095        33868 :         void *alloc = NULL;
    1096              : 
    1097        33868 :         if (tag == NULL)
    1098            0 :                 tag = "?";
    1099              : 
    1100        33868 :         if (length > 0xFFFFFFFF / 2) {
    1101            0 :                 if (egg_secure_warnings)
    1102            0 :                         fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n",
    1103              :                                  (unsigned long)length);
    1104            0 :                 return NULL;
    1105              :         }
    1106              : 
    1107        33868 :         if (memory == NULL)
    1108          186 :                 return egg_secure_alloc_full (tag, length, flags);
    1109        33682 :         if (!length) {
    1110          162 :                 egg_secure_free_full (memory, flags);
    1111          162 :                 return NULL;
    1112              :         }
    1113              : 
    1114        33520 :         DO_LOCK ();
    1115              : 
    1116              :                 /* Find out where it belongs to */
    1117      1266117 :                 for (block = all_blocks; block; block = block->next) {
    1118      1265858 :                         if (sec_is_valid_word (block, memory)) {
    1119        33261 :                                 previous = sec_allocated (block, memory);
    1120              : 
    1121              : #ifdef WITH_VALGRIND
    1122              :                                 /* Let valgrind think we are unallocating so that it'll validate */
    1123              :                                 VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t));
    1124              : #endif
    1125              : 
    1126        33261 :                                 alloc = sec_realloc (block, tag, memory, length);
    1127              : 
    1128              : #ifdef WITH_VALGRIND
    1129              :                                 /* Now tell valgrind about either the new block or old one */
    1130              :                                 VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory,
    1131              :                                                            alloc ? length : previous,
    1132              :                                                            sizeof (word_t), 1);
    1133              : #endif
    1134        33261 :                                 break;
    1135              :                         }
    1136              :                 }
    1137              : 
    1138              :                 /* If it didn't work we may need to allocate a new block */
    1139        33520 :                 if (block && !alloc)
    1140         8298 :                         donew = 1;
    1141              : 
    1142        33520 :                 if (block && block->n_used == 0)
    1143            0 :                         sec_block_destroy (block);
    1144              : 
    1145        33520 :         DO_UNLOCK ();
    1146              : 
    1147        33520 :         if (!block) {
    1148          259 :                 if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) {
    1149              :                         /*
    1150              :                          * In this case we can't zero the returned memory,
    1151              :                          * because we don't know what the block size was.
    1152              :                          */
    1153          259 :                         return EGG_SECURE_GLOBALS.fallback (memory, length);
    1154              :                 } else {
    1155            0 :                         if (egg_secure_warnings)
    1156            0 :                                 fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n",
    1157              :                                          (unsigned long)memory);
    1158            0 :                         ASSERT (0 && "memory does does not belong to secure memory pool");
    1159              :                         return NULL;
    1160              :                 }
    1161              :         }
    1162              : 
    1163        33261 :         if (donew) {
    1164         8298 :                 alloc = egg_secure_alloc_full (tag, length, flags);
    1165         8298 :                 if (alloc) {
    1166         8298 :                         memcpy_with_vbits (alloc, memory, previous);
    1167         8298 :                         egg_secure_free_full (memory, flags);
    1168              :                 }
    1169              :         }
    1170              : 
    1171        33261 :         if (!alloc)
    1172            0 :                 errno = ENOMEM;
    1173              : 
    1174        33261 :         return alloc;
    1175              : }
    1176              : 
    1177              : void
    1178        91849 : egg_secure_free (void *memory)
    1179              : {
    1180        91849 :         egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK);
    1181        91849 : }
    1182              : 
    1183              : void
    1184       100349 : egg_secure_free_full (void *memory, int flags)
    1185              : {
    1186       100349 :         Block *block = NULL;
    1187              : 
    1188       100349 :         if (memory == NULL)
    1189          204 :                 return;
    1190              : 
    1191       100145 :         DO_LOCK ();
    1192              : 
    1193              :                 /* Find out where it belongs to */
    1194      1665124 :                 for (block = all_blocks; block; block = block->next) {
    1195      1607747 :                         if (sec_is_valid_word (block, memory))
    1196        42768 :                                 break;
    1197              :                 }
    1198              : 
    1199              : #ifdef WITH_VALGRIND
    1200              :                 /* We like valgrind's warnings, so give it a first whack at checking for errors */
    1201              :                 if (block != NULL || !(flags & EGG_SECURE_USE_FALLBACK))
    1202              :                         VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t));
    1203              : #endif
    1204              : 
    1205       100145 :                 if (block != NULL) {
    1206        42768 :                         sec_free (block, memory);
    1207        42768 :                         if (block->n_used == 0)
    1208        19016 :                                 sec_block_destroy (block);
    1209              :                 }
    1210              : 
    1211       100145 :         DO_UNLOCK ();
    1212              : 
    1213       100145 :         if (!block) {
    1214        57377 :                 if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) {
    1215        57377 :                         EGG_SECURE_GLOBALS.fallback (memory, 0);
    1216              :                 } else {
    1217            0 :                         if (egg_secure_warnings)
    1218            0 :                                 fprintf (stderr, "memory does not belong to secure memory pool: 0x%08lx\n",
    1219              :                                          (unsigned long)memory);
    1220            0 :                         ASSERT (0 && "memory does does not belong to secure memory pool");
    1221              :                 }
    1222              :         }
    1223              : }
    1224              : 
    1225              : int
    1226         2005 : egg_secure_check (const void *memory)
    1227              : {
    1228         2005 :         Block *block = NULL;
    1229              : 
    1230         2005 :         DO_LOCK ();
    1231              : 
    1232              :                 /* Find out where it belongs to */
    1233         2279 :                 for (block = all_blocks; block; block = block->next) {
    1234          333 :                         if (sec_is_valid_word (block, (word_t*)memory))
    1235           59 :                                 break;
    1236              :                 }
    1237              : 
    1238         2005 :         DO_UNLOCK ();
    1239              : 
    1240         2005 :         return block == NULL ? 0 : 1;
    1241              : }
    1242              : 
    1243              : void
    1244       100174 : egg_secure_validate (void)
    1245              : {
    1246       100174 :         Block *block = NULL;
    1247              : 
    1248       100174 :         DO_LOCK ();
    1249              : 
    1250      7973369 :                 for (block = all_blocks; block; block = block->next)
    1251      7873195 :                         sec_validate (block);
    1252              : 
    1253       100174 :         DO_UNLOCK ();
    1254       100174 : }
    1255              : 
    1256              : 
    1257              : static egg_secure_rec *
    1258            0 : records_for_ring (Cell *cell_ring,
    1259              :                   egg_secure_rec *records,
    1260              :                   unsigned int *count,
    1261              :                   unsigned int *total)
    1262              : {
    1263              :         egg_secure_rec *new_rec;
    1264            0 :         unsigned int allocated = *count;
    1265              :         Cell *cell;
    1266              : 
    1267            0 :         cell = cell_ring;
    1268              :         do {
    1269            0 :                 if (*count >= allocated) {
    1270            0 :                         new_rec = realloc (records, sizeof (egg_secure_rec) * (allocated + 32));
    1271            0 :                         if (new_rec == NULL) {
    1272            0 :                                 *count = 0;
    1273            0 :                                 free (records);
    1274            0 :                                 return NULL;
    1275              :                         } else {
    1276            0 :                                 records = new_rec;
    1277            0 :                                 allocated += 32;
    1278              :                         }
    1279              :                 }
    1280              : 
    1281            0 :                 if (cell != NULL) {
    1282            0 :                         records[*count].request_length = cell->requested;
    1283            0 :                         records[*count].block_length = cell->n_words * sizeof (word_t);
    1284            0 :                         records[*count].tag = cell->tag;
    1285            0 :                         (*count)++;
    1286            0 :                         (*total) += cell->n_words;
    1287            0 :                         cell = cell->next;
    1288              :                 }
    1289            0 :         } while (cell != NULL && cell != cell_ring);
    1290              : 
    1291            0 :         return records;
    1292              : }
    1293              : 
    1294              : egg_secure_rec *
    1295            0 : egg_secure_records (unsigned int *count)
    1296              : {
    1297            0 :         egg_secure_rec *records = NULL;
    1298            0 :         Block *block = NULL;
    1299              :         unsigned int total;
    1300              : 
    1301            0 :         *count = 0;
    1302              : 
    1303            0 :         DO_LOCK ();
    1304              : 
    1305            0 :                 for (block = all_blocks; block != NULL; block = block->next) {
    1306            0 :                         total = 0;
    1307              : 
    1308            0 :                         records = records_for_ring (block->unused_cells, records, count, &total);
    1309            0 :                         if (records == NULL)
    1310            0 :                                 break;
    1311            0 :                         records = records_for_ring (block->used_cells, records, count, &total);
    1312            0 :                         if (records == NULL)
    1313            0 :                                 break;
    1314              : 
    1315              :                         /* Make sure this actually accounts for all memory */
    1316            0 :                         ASSERT (total == block->n_words);
    1317              :                 }
    1318              : 
    1319            0 :         DO_UNLOCK ();
    1320              : 
    1321            0 :         return records;
    1322              : }
    1323              : 
    1324              : char*
    1325           64 : egg_secure_strdup_full (const char *tag,
    1326              :                         const char *str,
    1327              :                         int options)
    1328              : {
    1329              :         size_t len;
    1330              :         char *res;
    1331              : 
    1332           64 :         if (!str)
    1333            0 :                 return NULL;
    1334              : 
    1335           64 :         len = strlen (str) + 1;
    1336           64 :         res = (char *)egg_secure_alloc_full (tag, len, options);
    1337           64 :         strcpy (res, str);
    1338           64 :         return res;
    1339              : }
    1340              : 
    1341              : char *
    1342            3 : egg_secure_strndup_full (const char *tag,
    1343              :                          const char *str,
    1344              :                          size_t length,
    1345              :                          int options)
    1346              : {
    1347              :         size_t len;
    1348              :         char *res;
    1349              :         const char *end;
    1350              : 
    1351            3 :         if (!str)
    1352            0 :                 return NULL;
    1353              : 
    1354            3 :         end = memchr (str, '\0', length);
    1355            3 :         if (end != NULL)
    1356            1 :                 length = (end - str);
    1357            3 :         len = length + 1;
    1358            3 :         res = (char *)egg_secure_alloc_full (tag, len, options);
    1359            3 :         memcpy (res, str, len);
    1360            3 :         res[length] = '\0';
    1361            3 :         return res;
    1362              : }
    1363              : 
    1364              : void
    1365          404 : egg_secure_clear (void *p, size_t length)
    1366              : {
    1367              :         volatile char *vp;
    1368              : 
    1369          404 :         if (p == NULL)
    1370          183 :                 return;
    1371              : 
    1372          221 :         vp = (volatile char*)p;
    1373         2401 :         while (length) {
    1374         2180 :                 *vp = 0xAA;
    1375         2180 :                 vp++;
    1376         2180 :                 length--;
    1377              :         }
    1378              : }
    1379              : 
    1380              : void
    1381           33 : egg_secure_strclear (char *str)
    1382              : {
    1383           33 :         if (!str)
    1384           13 :                 return;
    1385           20 :         egg_secure_clear ((unsigned char*)str, strlen (str));
    1386              : }
    1387              : 
    1388              : void
    1389           32 : egg_secure_strfree (char *str)
    1390              : {
    1391              :         /*
    1392              :          * If we're using unpageable 'secure' memory, then the free call
    1393              :          * should zero out the memory, but because on certain platforms
    1394              :          * we may be using normal memory, zero it out here just in case.
    1395              :          */
    1396              : 
    1397           32 :         egg_secure_strclear (str);
    1398           32 :         egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK);
    1399           32 : }
        

Generated by: LCOV version 2.0-1