LCOV - code coverage report
Current view: top level - egg - egg-secure-memory.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 471 561 84.0 %
Date: 2024-02-08 14:44:34 Functions: 38 40 95.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 259 440 58.9 %

           Branch data     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                 :    2024433 : unused_push (void **stack, void *ptr)
     117                 :            : {
     118         [ -  + ]:    2024433 :         ASSERT (ptr);
     119         [ -  + ]:    2024433 :         ASSERT (stack);
     120                 :    2024433 :         *((void**)ptr) = *stack;
     121                 :    2024433 :         *stack = ptr;
     122                 :    2024433 : }
     123                 :            : 
     124                 :            : static inline void*
     125                 :    1981745 : unused_pop (void **stack)
     126                 :            : {
     127                 :            :         void *ptr;
     128         [ -  + ]:    1981745 :         ASSERT (stack);
     129                 :    1981745 :         ptr = *stack;
     130                 :    1981745 :         *stack = *(void**)ptr;
     131                 :    1981745 :         return ptr;
     132                 :            : 
     133                 :            : }
     134                 :            : 
     135                 :            : static inline void*
     136                 :    3994753 : unused_peek (void **stack)
     137                 :            : {
     138         [ -  + ]:    3994753 :         ASSERT (stack);
     139                 :    3994753 :         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                 :    1981745 : pool_alloc (void)
     167                 :            : {
     168                 :            :         Pool *pool;
     169                 :            :         void *pages, *item;
     170                 :            :         size_t len, i;
     171                 :            : 
     172         [ +  - ]:    1981745 :         if (!EGG_SECURE_GLOBALS.pool_version ||
     173         [ -  + ]:    1981745 :             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         [ +  + ]:    2013264 :         for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
     184         [ +  + ]:    2013008 :                 if (unused_peek (&pool->unused))
     185                 :    1981489 :                         break;
     186                 :            :         }
     187                 :            : 
     188                 :            :         /* Create a new pool */
     189         [ +  + ]:    1981745 :         if (pool == NULL) {
     190                 :        256 :                 len = getpagesize () * 2;
     191                 :        256 :                 pages = mmap (0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     192         [ -  + ]:        256 :                 if (pages == MAP_FAILED)
     193                 :          0 :                         return NULL;
     194                 :            : 
     195                 :            :                 /* Fill in the block header, and inlude in block list */
     196                 :        256 :                 pool = pages;
     197                 :        256 :                 pool->next = EGG_SECURE_GLOBALS.pool_data;
     198                 :        256 :                 EGG_SECURE_GLOBALS.pool_data = pool;
     199                 :        256 :                 pool->length = len;
     200                 :        256 :                 pool->used = 0;
     201                 :        256 :                 pool->unused = NULL;
     202                 :            : 
     203                 :            :                 /* Fill block with unused items */
     204                 :        256 :                 pool->n_items = (len - sizeof (Pool)) / sizeof (Item);
     205         [ +  + ]:      43264 :                 for (i = 0; i < pool->n_items; ++i)
     206                 :      43008 :                         unused_push (&pool->unused, pool->items + i);
     207                 :            : 
     208                 :            : #ifdef WITH_VALGRIND
     209                 :            :                 VALGRIND_CREATE_MEMPOOL(pool, 0, 0);
     210                 :            : #endif
     211                 :            :         }
     212                 :            : 
     213                 :    1981745 :         ++pool->used;
     214         [ -  + ]:    1981745 :         ASSERT (unused_peek (&pool->unused));
     215                 :    1981745 :         item = unused_pop (&pool->unused);
     216                 :            : 
     217                 :            : #ifdef WITH_VALGRIND
     218                 :            :         VALGRIND_MEMPOOL_ALLOC (pool, item, sizeof (Item));
     219                 :            : #endif
     220                 :            : 
     221                 :    1981745 :         return memset (item, 0, sizeof (Item));
     222                 :            : }
     223                 :            : 
     224                 :            : static void
     225                 :    1981666 : pool_free (void* item)
     226                 :            : {
     227                 :            :         Pool *pool, **at;
     228                 :            :         char *ptr, *beg, *end;
     229                 :            : 
     230                 :    1981666 :         ptr = item;
     231                 :            : 
     232                 :            :         /* Find which block this one belongs to */
     233                 :    1981666 :         for (at = (Pool **)&EGG_SECURE_GLOBALS.pool_data, pool = *at;
     234         [ +  - ]:    2018521 :              pool != NULL; at = &pool->next, pool = *at) {
     235                 :    2018521 :                 beg = (char*)pool->items;
     236                 :    2018521 :                 end = (char*)pool + pool->length - sizeof (Item);
     237   [ +  +  +  + ]:    2018521 :                 if (ptr >= beg && ptr <= end) {
     238         [ -  + ]:    1981666 :                         ASSERT ((ptr - beg) % sizeof (Item) == 0);
     239                 :    1981666 :                         break;
     240                 :            :                 }
     241                 :            :         }
     242                 :            : 
     243                 :            :         /* Otherwise invalid meta */
     244         [ -  + ]:    1981666 :         ASSERT (at);
     245         [ -  + ]:    1981666 :         ASSERT (pool);
     246         [ -  + ]:    1981666 :         ASSERT (pool->used > 0);
     247                 :            : 
     248                 :            :         /* No more meta cells used in this block, remove from list, destroy */
     249         [ +  + ]:    1981666 :         if (pool->used == 1) {
     250                 :        241 :                 *at = pool->next;
     251                 :            : 
     252                 :            : #ifdef WITH_VALGRIND
     253                 :            :                 VALGRIND_DESTROY_MEMPOOL (pool);
     254                 :            : #endif
     255                 :            : 
     256                 :        241 :                 munmap (pool, pool->length);
     257                 :        241 :                 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                 :    1981425 :         --pool->used;
     266                 :    1981425 :         memset (item, 0xCD, sizeof (Item));
     267                 :    1981425 :         unused_push (&pool->unused, item);
     268                 :            : }
     269                 :            : 
     270                 :            : #ifndef G_DISABLE_ASSERT
     271                 :            : 
     272                 :            : static int
     273                 :   21616924 : pool_valid (void* item)
     274                 :            : {
     275                 :            :         Pool *pool;
     276                 :            :         char *ptr, *beg, *end;
     277                 :            : 
     278                 :   21616924 :         ptr = item;
     279                 :            : 
     280                 :            :         /* Find which block this one belongs to */
     281         [ +  - ]:   35677130 :         for (pool = EGG_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
     282                 :   35677130 :                 beg = (char*)pool->items;
     283                 :   35677130 :                 end = (char*)pool + pool->length - sizeof (Item);
     284   [ +  +  +  + ]:   35677130 :                 if (ptr >= beg && ptr <= end)
     285   [ +  -  +  - ]:   21616924 :                         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                 :    3794055 : sec_size_to_words (size_t length)
     303                 :            : {
     304         [ +  + ]:    3794055 :         return (length % sizeof (void*) ? 1 : 0) + (length / sizeof (void*));
     305                 :            : }
     306                 :            : 
     307                 :            : static inline void
     308                 :    5859320 : 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                 :    5859320 :         ((void**)cell->words)[0] = (void*)cell;
     316                 :    5859320 :         ((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                 :    5859320 : }
     323                 :            : 
     324                 :            : static inline void
     325                 :   29377171 : 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         [ -  + ]:   29377171 :         ASSERT(((void**)cell->words)[0] == (void*)cell);
     333         [ -  + ]:   29377171 :         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                 :   29377171 : }
     340                 :            : 
     341                 :            : static void
     342                 :    1974970 : sec_insert_cell_ring (Cell **ring, Cell *cell)
     343                 :            : {
     344         [ -  + ]:    1974970 :         ASSERT (ring);
     345         [ -  + ]:    1974970 :         ASSERT (cell);
     346         [ -  + ]:    1974970 :         ASSERT (cell != *ring);
     347         [ -  + ]:    1974970 :         ASSERT (cell->next == NULL);
     348         [ -  + ]:    1974970 :         ASSERT (cell->prev == NULL);
     349                 :            : 
     350                 :            :         /* Insert back into the mix of available memory */
     351         [ +  + ]:    1974970 :         if (*ring) {
     352                 :    1933988 :                 cell->next = (*ring)->next;
     353                 :    1933988 :                 cell->prev = *ring;
     354                 :    1933988 :                 cell->next->prev = cell;
     355                 :    1933988 :                 cell->prev->next = cell;
     356                 :            :         } else {
     357                 :      40982 :                 cell->next = cell;
     358                 :      40982 :                 cell->prev = cell;
     359                 :            :         }
     360                 :            : 
     361                 :    1974970 :         *ring = cell;
     362         [ -  + ]:    1974970 :         ASSERT (cell->next->prev == cell);
     363         [ -  + ]:    1974970 :         ASSERT (cell->prev->next == cell);
     364                 :    1974970 : }
     365                 :            : 
     366                 :            : static void
     367                 :    1974906 : sec_remove_cell_ring (Cell **ring, Cell *cell)
     368                 :            : {
     369         [ -  + ]:    1974906 :         ASSERT (ring);
     370         [ -  + ]:    1974906 :         ASSERT (*ring);
     371         [ -  + ]:    1974906 :         ASSERT (cell->next);
     372         [ -  + ]:    1974906 :         ASSERT (cell->prev);
     373                 :            : 
     374         [ -  + ]:    1974906 :         ASSERT (cell->next->prev == cell);
     375         [ -  + ]:    1974906 :         ASSERT (cell->prev->next == cell);
     376                 :            : 
     377         [ +  + ]:    1974906 :         if (cell == *ring) {
     378                 :            :                 /* The last meta? */
     379         [ +  + ]:    1957578 :                 if (cell->next == cell) {
     380         [ -  + ]:      40952 :                         ASSERT (cell->prev == cell);
     381                 :      40952 :                         *ring = NULL;
     382                 :            : 
     383                 :            :                 /* Just pointing to this meta */
     384                 :            :                 } else {
     385         [ -  + ]:    1916626 :                         ASSERT (cell->prev != cell);
     386                 :    1916626 :                         *ring = cell->next;
     387                 :            :                 }
     388                 :            :         }
     389                 :            : 
     390                 :    1974906 :         cell->next->prev = cell->prev;
     391                 :    1974906 :         cell->prev->next = cell->next;
     392                 :    1974906 :         cell->next = cell->prev = NULL;
     393                 :            : 
     394         [ -  + ]:    1974906 :         ASSERT (*ring != cell);
     395                 :    1974906 : }
     396                 :            : 
     397                 :            : static inline void*
     398                 :    1969472 : sec_cell_to_memory (Cell *cell)
     399                 :            : {
     400                 :    1969472 :         return cell->words + 1;
     401                 :            : }
     402                 :            : 
     403                 :            : static inline int
     404                 :   30253565 : sec_is_valid_word (Block *block, word_t *word)
     405                 :            : {
     406   [ +  +  +  + ]:   30253565 :         return (word >= block->words && word < block->words + block->n_words);
     407                 :            : }
     408                 :            : 
     409                 :            : static inline void
     410                 :      20898 : sec_clear_undefined (void *memory,
     411                 :            :                      size_t from,
     412                 :            :                      size_t to)
     413                 :            : {
     414                 :      20898 :         char *ptr = memory;
     415         [ -  + ]:      20898 :         ASSERT (from <= to);
     416                 :            : #ifdef WITH_VALGRIND
     417                 :            :         VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
     418                 :            : #endif
     419                 :      20898 :         memset (ptr + from, 0, to - from);
     420                 :            : #ifdef WITH_VALGRIND
     421                 :            :         VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
     422                 :            : #endif
     423                 :      20898 : }
     424                 :            : static inline void
     425                 :    1944719 : sec_clear_noaccess (void *memory, size_t from, size_t to)
     426                 :            : {
     427                 :    1944719 :         char *ptr = memory;
     428         [ -  + ]:    1944719 :         ASSERT (from <= to);
     429                 :            : #ifdef WITH_VALGRIND
     430                 :            :         VALGRIND_MAKE_MEM_UNDEFINED (ptr + from, to - from);
     431                 :            : #endif
     432                 :    1944719 :         memset (ptr + from, 0, to - from);
     433                 :            : #ifdef WITH_VALGRIND
     434                 :            :         VALGRIND_MAKE_MEM_NOACCESS (ptr + from, to - from);
     435                 :            : #endif
     436                 :    1944719 : }
     437                 :            : 
     438                 :            : static Cell*
     439                 :    1944719 : sec_neighbor_before (Block *block, Cell *cell)
     440                 :            : {
     441                 :            :         word_t *word;
     442                 :            : 
     443         [ -  + ]:    1944719 :         ASSERT (cell);
     444         [ -  + ]:    1944719 :         ASSERT (block);
     445                 :            : 
     446                 :    1944719 :         word = cell->words - 1;
     447         [ +  + ]:    1944719 :         if (!sec_is_valid_word (block, word))
     448                 :      26397 :                 return NULL;
     449                 :            : 
     450                 :            : #ifdef WITH_VALGRIND
     451                 :            :         VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
     452                 :            : #endif
     453                 :            : 
     454                 :    1918322 :         cell = *word;
     455                 :    1918322 :         sec_check_guards (cell);
     456                 :            : 
     457                 :            : #ifdef WITH_VALGRIND
     458                 :            :         VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
     459                 :            : #endif
     460                 :            : 
     461                 :    1918322 :         return cell;
     462                 :            : }
     463                 :            : 
     464                 :            : static Cell*
     465                 :    1963748 : sec_neighbor_after (Block *block, Cell *cell)
     466                 :            : {
     467                 :            :         word_t *word;
     468                 :            : 
     469         [ -  + ]:    1963748 :         ASSERT (cell);
     470         [ -  + ]:    1963748 :         ASSERT (block);
     471                 :            : 
     472                 :    1963748 :         word = cell->words + cell->n_words;
     473         [ +  + ]:    1963748 :         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                 :    1952439 :         cell = *word;
     481                 :    1952439 :         sec_check_guards (cell);
     482                 :            : 
     483                 :            : #ifdef WITH_VALGRIND
     484                 :            :         VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
     485                 :            : #endif
     486                 :            : 
     487                 :    1952439 :         return cell;
     488                 :            : }
     489                 :            : 
     490                 :            : static void*
     491                 :    3790519 : 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         [ -  + ]:    3790519 :         ASSERT (block);
     500         [ -  + ]:    3790519 :         ASSERT (length);
     501         [ -  + ]:    3790519 :         ASSERT (tag);
     502                 :            : 
     503         [ +  + ]:    3790519 :         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                 :    3760780 :         n_words = sec_size_to_words (length) + 2;
     515                 :            : 
     516                 :            :         /* Look for a cell of at least our required size */
     517                 :    3760780 :         cell = block->unused_cells;
     518         [ +  + ]:    4053938 :         while (cell->n_words < n_words) {
     519                 :    2109171 :                 cell = cell->next;
     520         [ +  + ]:    2109171 :                 if (cell == block->unused_cells) {
     521                 :    1816013 :                         cell = NULL;
     522                 :    1816013 :                         break;
     523                 :            :                 }
     524                 :            :         }
     525                 :            : 
     526         [ +  + ]:    3760780 :         if (!cell)
     527                 :    1816013 :                 return NULL;
     528                 :            : 
     529         [ -  + ]:    1944767 :         ASSERT (cell->tag == NULL);
     530         [ -  + ]:    1944767 :         ASSERT (cell->requested == 0);
     531         [ -  + ]:    1944767 :         ASSERT (cell->prev);
     532         [ -  + ]:    1944767 :         ASSERT (cell->words);
     533                 :    1944767 :         sec_check_guards (cell);
     534                 :            : 
     535                 :            :         /* Steal from the cell if it's too long */
     536         [ +  + ]:    1944767 :         if (cell->n_words > n_words + WASTE) {
     537                 :    1944065 :                 other = pool_alloc ();
     538         [ -  + ]:    1944065 :                 if (!other)
     539                 :          0 :                         return NULL;
     540                 :    1944065 :                 other->n_words = n_words;
     541                 :    1944065 :                 other->words = cell->words;
     542                 :    1944065 :                 cell->n_words -= n_words;
     543                 :    1944065 :                 cell->words += n_words;
     544                 :            : 
     545                 :    1944065 :                 sec_write_guards (other);
     546                 :    1944065 :                 sec_write_guards (cell);
     547                 :            : 
     548                 :    1944065 :                 cell = other;
     549                 :            :         }
     550                 :            : 
     551         [ +  + ]:    1944767 :         if (cell->next)
     552                 :        702 :                 sec_remove_cell_ring (&block->unused_cells, cell);
     553                 :            : 
     554                 :    1944767 :         ++block->n_used;
     555                 :    1944767 :         cell->tag = tag;
     556                 :    1944767 :         cell->requested = length;
     557                 :    1944767 :         sec_insert_cell_ring (&block->used_cells, cell);
     558                 :    1944767 :         memory = sec_cell_to_memory (cell);
     559                 :            : 
     560                 :            : #ifdef WITH_VALGRIND
     561                 :            :         VALGRIND_MAKE_MEM_UNDEFINED (memory, length);
     562                 :            : #endif
     563                 :            : 
     564                 :    1944767 :         return memset (memory, 0, length);
     565                 :            : }
     566                 :            : 
     567                 :            : static void*
     568                 :    1944719 : sec_free (Block *block, void *memory)
     569                 :            : {
     570                 :            :         Cell *cell, *other;
     571                 :            :         word_t *word;
     572                 :            : 
     573         [ -  + ]:    1944719 :         ASSERT (block);
     574         [ -  + ]:    1944719 :         ASSERT (memory);
     575                 :            : 
     576                 :    1944719 :         word = memory;
     577                 :    1944719 :         --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         [ -  + ]:    1944719 :         ASSERT (sec_is_valid_word (block, word));
     585         [ -  + ]:    1944719 :         ASSERT (pool_valid (*word));
     586                 :    1944719 :         cell = *word;
     587                 :            : 
     588                 :            : #ifdef WITH_VALGRIND
     589                 :            :         VALGRIND_MAKE_MEM_DEFINED (cell->words, cell->n_words * sizeof (word_t));
     590                 :            : #endif
     591                 :            : 
     592                 :    1944719 :         sec_check_guards (cell);
     593                 :    1944719 :         sec_clear_noaccess (memory, 0, cell->requested);
     594                 :            : 
     595                 :    1944719 :         sec_check_guards (cell);
     596         [ -  + ]:    1944719 :         ASSERT (cell->requested > 0);
     597         [ -  + ]:    1944719 :         ASSERT (cell->tag != NULL);
     598                 :            : 
     599                 :            :         /* Remove from the used cell ring */
     600                 :    1944719 :         sec_remove_cell_ring (&block->used_cells, cell);
     601                 :            : 
     602                 :            :         /* Find previous unallocated neighbor, and merge if possible */
     603                 :    1944719 :         other = sec_neighbor_before (block, cell);
     604   [ +  +  +  + ]:    1944719 :         if (other && other->requested == 0) {
     605         [ -  + ]:       9090 :                 ASSERT (other->tag == NULL);
     606   [ +  -  +  - ]:       9090 :                 ASSERT (other->next && other->prev);
     607                 :       9090 :                 other->n_words += cell->n_words;
     608                 :       9090 :                 sec_write_guards (other);
     609                 :       9090 :                 pool_free (cell);
     610                 :       9090 :                 cell = other;
     611                 :            :         }
     612                 :            : 
     613                 :            :         /* Find next unallocated neighbor, and merge if possible */
     614                 :    1944719 :         other = sec_neighbor_after (block, cell);
     615   [ +  +  +  + ]:    1944719 :         if (other && other->requested == 0) {
     616         [ -  + ]:    1928634 :                 ASSERT (other->tag == NULL);
     617   [ +  -  +  - ]:    1928634 :                 ASSERT (other->next && other->prev);
     618                 :    1928634 :                 other->n_words += cell->n_words;
     619                 :    1928634 :                 other->words = cell->words;
     620         [ +  + ]:    1928634 :                 if (cell->next)
     621                 :       4368 :                         sec_remove_cell_ring (&block->unused_cells, cell);
     622                 :    1928634 :                 sec_write_guards (other);
     623                 :    1928634 :                 pool_free (cell);
     624                 :    1928634 :                 cell = other;
     625                 :            :         }
     626                 :            : 
     627                 :            :         /* Add to the unused list if not already there */
     628         [ +  + ]:    1944719 :         if (!cell->next)
     629                 :      11363 :                 sec_insert_cell_ring (&block->unused_cells, cell);
     630                 :            : 
     631                 :    1944719 :         cell->tag = NULL;
     632                 :    1944719 :         cell->requested = 0;
     633                 :    1944719 :         --block->n_used;
     634                 :    1944719 :         return NULL;
     635                 :            : }
     636                 :            : 
     637                 :            : static void
     638                 :       8570 : 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                 :       8570 :         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                 :       8570 : }
     664                 :            : 
     665                 :            : static void*
     666                 :      33275 : 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         [ -  + ]:      33275 :         ASSERT (memory != NULL);
     679         [ -  + ]:      33275 :         ASSERT (length > 0);
     680         [ -  + ]:      33275 :         ASSERT (tag != NULL);
     681                 :            : 
     682                 :            :         /* Dig out where the meta should be */
     683                 :      33275 :         word = memory;
     684                 :      33275 :         --word;
     685                 :            : 
     686                 :            : #ifdef WITH_VALGRIND
     687                 :            :         VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t));
     688                 :            : #endif
     689                 :            : 
     690         [ -  + ]:      33275 :         ASSERT (sec_is_valid_word (block, word));
     691         [ -  + ]:      33275 :         ASSERT (pool_valid (*word));
     692                 :      33275 :         cell = *word;
     693                 :            : 
     694                 :            :         /* Validate that it's actually for real */
     695                 :      33275 :         sec_check_guards (cell);
     696         [ -  + ]:      33275 :         ASSERT (cell->requested > 0);
     697         [ -  + ]:      33275 :         ASSERT (cell->tag != NULL);
     698                 :            : 
     699                 :            :         /* The amount of valid data */
     700                 :      33275 :         valid = cell->requested;
     701                 :            : 
     702                 :            :         /* How many words we actually want */
     703                 :      33275 :         n_words = sec_size_to_words (length) + 2;
     704                 :            : 
     705                 :            :         /* Less memory is required than is in the cell */
     706         [ +  + ]:      33275 :         if (n_words <= cell->n_words) {
     707                 :            : 
     708                 :            :                 /* TODO: No shrinking behavior yet */
     709                 :      20469 :                 cell->requested = length;
     710                 :      20469 :                 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         [ +  + ]:      20469 :                 if (length < valid)
     718                 :      16662 :                         sec_clear_undefined (alloc, length, valid);
     719                 :            : 
     720                 :      20469 :                 return alloc;
     721                 :            :         }
     722                 :            : 
     723                 :            :         /* Need braaaaaiiiiiinsss... */
     724         [ +  + ]:      23265 :         while (cell->n_words < n_words) {
     725                 :            : 
     726                 :            :                 /* See if we have a neighbor who can give us some memory */
     727                 :      19029 :                 other = sec_neighbor_after (block, cell);
     728   [ +  +  +  + ]:      19029 :                 if (!other || other->requested != 0)
     729                 :            :                         break;
     730                 :            : 
     731                 :            :                 /* Eat the whole neighbor if not too big */
     732         [ +  + ]:      10459 :                 if (n_words - cell->n_words + WASTE >= other->n_words) {
     733                 :       6292 :                         cell->n_words += other->n_words;
     734                 :       6292 :                         sec_write_guards (cell);
     735                 :       6292 :                         sec_remove_cell_ring (&block->unused_cells, other);
     736                 :       6292 :                         pool_free (other);
     737                 :            : 
     738                 :            :                 /* Steal from the neighbor */
     739                 :            :                 } else {
     740                 :       4167 :                         other->words += n_words - cell->n_words;
     741                 :       4167 :                         other->n_words -= n_words - cell->n_words;
     742                 :       4167 :                         sec_write_guards (other);
     743                 :       4167 :                         cell->n_words = n_words;
     744                 :       4167 :                         sec_write_guards (cell);
     745                 :            :                 }
     746                 :            :         }
     747                 :            : 
     748         [ +  + ]:      12806 :         if (cell->n_words >= n_words) {
     749                 :       4236 :                 cell->requested = length;
     750                 :       4236 :                 cell->tag = tag;
     751                 :       4236 :                 alloc = sec_cell_to_memory (cell);
     752                 :       4236 :                 sec_clear_undefined (alloc, valid, length);
     753                 :       4236 :                 return alloc;
     754                 :            :         }
     755                 :            : 
     756                 :            :         /* That didn't work, try alloc/free */
     757                 :       8570 :         alloc = sec_alloc (block, tag, length);
     758         [ +  + ]:       8570 :         if (alloc) {
     759                 :        272 :                 memcpy_with_vbits (alloc, memory, valid);
     760                 :        272 :                 sec_free (block, memory);
     761                 :            :         }
     762                 :            : 
     763                 :       8570 :         return alloc;
     764                 :            : }
     765                 :            : 
     766                 :            : 
     767                 :            : static size_t
     768                 :      33275 : sec_allocated (Block *block, void *memory)
     769                 :            : {
     770                 :            :         Cell *cell;
     771                 :            :         word_t *word;
     772                 :            : 
     773         [ -  + ]:      33275 :         ASSERT (block);
     774         [ -  + ]:      33275 :         ASSERT (memory);
     775                 :            : 
     776                 :      33275 :         word = memory;
     777                 :      33275 :         --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         [ -  + ]:      33275 :         ASSERT (sec_is_valid_word (block, word));
     785         [ -  + ]:      33275 :         ASSERT (pool_valid (*word));
     786                 :      33275 :         cell = *word;
     787                 :            : 
     788                 :      33275 :         sec_check_guards (cell);
     789         [ -  + ]:      33275 :         ASSERT (cell->requested > 0);
     790         [ -  + ]:      33275 :         ASSERT (cell->tag != NULL);
     791                 :            : 
     792                 :            : #ifdef WITH_VALGRIND
     793                 :            :         VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
     794                 :            : #endif
     795                 :            : 
     796                 :      33275 :         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                 :      18840 : sec_acquire_pages (size_t *sz,
     853                 :            :                    const char *during_tag)
     854                 :            : {
     855                 :            :         void *pages;
     856                 :            :         unsigned long pgsize;
     857                 :            : 
     858         [ -  + ]:      18840 :         ASSERT (sz);
     859         [ -  + ]:      18840 :         ASSERT (*sz);
     860         [ -  + ]:      18840 :         ASSERT (during_tag);
     861                 :            : 
     862                 :            :         /* Make sure sz is a multiple of the page size */
     863                 :      18840 :         pgsize = getpagesize ();
     864                 :      18840 :         *sz = (*sz + pgsize -1) & ~(pgsize - 1);
     865                 :            : 
     866                 :            : #if defined(HAVE_MLOCK)
     867                 :      18840 :         pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     868         [ -  + ]:      18840 :         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         [ -  + ]:      18840 :         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         [ -  + ]:      18840 :         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                 :      18840 :         show_warning = 1;
     902                 :      18840 :         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                 :      18825 : sec_release_pages (void *pages, size_t sz)
     915                 :            : {
     916         [ -  + ]:      18825 :         ASSERT (pages);
     917         [ -  + ]:      18825 :         ASSERT (sz % getpagesize () == 0);
     918                 :            : 
     919                 :            : #if defined(HAVE_MLOCK)
     920   [ -  +  -  - ]:      18825 :         if (munlock (pages, sz) < 0 && egg_secure_warnings)
     921                 :          0 :                 fprintf (stderr, "couldn't unlock private memory: %s\n", strerror (errno));
     922                 :            : 
     923   [ -  +  -  - ]:      18825 :         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                 :      18825 : }
     932                 :            : 
     933                 :            : /* -----------------------------------------------------------------------------
     934                 :            :  * MANAGE DIFFERENT BLOCKS
     935                 :            :  */
     936                 :            : 
     937                 :            : static Block *all_blocks = NULL;
     938                 :            : 
     939                 :            : static Block*
     940                 :      18840 : sec_block_create (size_t size,
     941                 :            :                   const char *during_tag)
     942                 :            : {
     943                 :            :         Block *block;
     944                 :            :         Cell *cell;
     945                 :            : 
     946         [ -  + ]:      18840 :         ASSERT (during_tag);
     947                 :            : 
     948                 :            :         /* We can force all all memory to be malloced */
     949         [ -  + ]:      18840 :         if (getenv ("SECMEM_FORCE_FALLBACK"))
     950                 :          0 :                 return NULL;
     951                 :            : 
     952                 :      18840 :         block = pool_alloc ();
     953         [ -  + ]:      18840 :         if (!block)
     954                 :          0 :                 return NULL;
     955                 :            : 
     956                 :      18840 :         cell = pool_alloc ();
     957         [ -  + ]:      18840 :         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         [ +  - ]:      18840 :         if (size < DEFAULT_BLOCK_SIZE)
     964                 :      18840 :                 size = DEFAULT_BLOCK_SIZE;
     965                 :            : 
     966                 :      18840 :         block->words = sec_acquire_pages (&size, during_tag);
     967                 :      18840 :         block->n_words = size / sizeof (word_t);
     968         [ -  + ]:      18840 :         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                 :      18840 :         cell->words = block->words;
     980                 :      18840 :         cell->n_words = block->n_words;
     981                 :      18840 :         cell->requested = 0;
     982                 :      18840 :         sec_write_guards (cell);
     983                 :      18840 :         sec_insert_cell_ring (&block->unused_cells, cell);
     984                 :            : 
     985                 :      18840 :         block->next = all_blocks;
     986                 :      18840 :         all_blocks = block;
     987                 :            : 
     988                 :      18840 :         return block;
     989                 :            : }
     990                 :            : 
     991                 :            : static void
     992                 :      18825 : sec_block_destroy (Block *block)
     993                 :            : {
     994                 :            :         Block *bl, **at;
     995                 :            :         Cell *cell;
     996                 :            : 
     997         [ -  + ]:      18825 :         ASSERT (block);
     998         [ -  + ]:      18825 :         ASSERT (block->words);
     999         [ -  + ]:      18825 :         ASSERT (block->n_used == 0);
    1000                 :            : 
    1001                 :            :         /* Remove from the list */
    1002         [ +  - ]:     791996 :         for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) {
    1003         [ +  + ]:     791996 :                 if (bl == block) {
    1004                 :      18825 :                         *at = block->next;
    1005                 :      18825 :                         break;
    1006                 :            :                 }
    1007                 :            :         }
    1008                 :            : 
    1009                 :            :         /* Must have been found */
    1010         [ -  + ]:      18825 :         ASSERT (bl == block);
    1011         [ -  + ]:      18825 :         ASSERT (block->used_cells == NULL);
    1012                 :            : 
    1013                 :            :         /* Release all the meta data cells */
    1014         [ +  + ]:      37650 :         while (block->unused_cells) {
    1015                 :      18825 :                 cell = block->unused_cells;
    1016                 :      18825 :                 sec_remove_cell_ring (&block->unused_cells, cell);
    1017                 :      18825 :                 pool_free (cell);
    1018                 :            :         }
    1019                 :            : 
    1020                 :            :         /* Release all pages of secure memory */
    1021                 :      18825 :         sec_release_pages (block->words, block->n_words * sizeof (word_t));
    1022                 :            : 
    1023                 :      18825 :         pool_free (block);
    1024                 :      18825 : }
    1025                 :            : 
    1026                 :            : /* ------------------------------------------------------------------------
    1027                 :            :  * PUBLIC FUNCTIONALITY
    1028                 :            :  */
    1029                 :            : 
    1030                 :            : void*
    1031                 :    1944553 : egg_secure_alloc_full (const char *tag,
    1032                 :            :                        size_t length,
    1033                 :            :                        int flags)
    1034                 :            : {
    1035                 :            :         Block *block;
    1036                 :    1944553 :         void *memory = NULL;
    1037                 :            : 
    1038         [ -  + ]:    1944553 :         if (tag == NULL)
    1039                 :          0 :                 tag = "?";
    1040                 :            : 
    1041         [ -  + ]:    1944553 :         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         [ -  + ]:    1944553 :         if (length == 0)
    1050                 :          0 :                 return NULL;
    1051                 :            : 
    1052                 :    1944553 :         DO_LOCK ();
    1053                 :            : 
    1054         [ +  + ]:    3781949 :                 for (block = all_blocks; block; block = block->next) {
    1055                 :    3763109 :                         memory = sec_alloc (block, tag, length);
    1056         [ +  + ]:    3763109 :                         if (memory)
    1057                 :    1925713 :                                 break;
    1058                 :            :                 }
    1059                 :            : 
    1060                 :            :                 /* None of the current blocks have space, allocate new */
    1061         [ +  + ]:    1944553 :                 if (!memory) {
    1062                 :      18840 :                         block = sec_block_create (length, tag);
    1063         [ +  - ]:      18840 :                         if (block)
    1064                 :      18840 :                                 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                 :    1944553 :         DO_UNLOCK ();
    1073                 :            : 
    1074   [ +  +  +  -  :    1944553 :         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         [ -  + ]:    1944553 :         if (!memory)
    1081                 :          0 :                 errno = ENOMEM;
    1082                 :            : 
    1083                 :    1944553 :         return memory;
    1084                 :            : }
    1085                 :            : 
    1086                 :            : void*
    1087                 :      33389 : egg_secure_realloc_full (const char *tag,
    1088                 :            :                          void *memory,
    1089                 :            :                          size_t length,
    1090                 :            :                          int flags)
    1091                 :            : {
    1092                 :      33389 :         Block *block = NULL;
    1093                 :      33389 :         size_t previous = 0;
    1094                 :      33389 :         int donew = 0;
    1095                 :      33389 :         void *alloc = NULL;
    1096                 :            : 
    1097         [ -  + ]:      33389 :         if (tag == NULL)
    1098                 :          0 :                 tag = "?";
    1099                 :            : 
    1100         [ -  + ]:      33389 :         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         [ +  + ]:      33389 :         if (memory == NULL)
    1108                 :          2 :                 return egg_secure_alloc_full (tag, length, flags);
    1109         [ +  + ]:      33387 :         if (!length) {
    1110                 :          1 :                 egg_secure_free_full (memory, flags);
    1111                 :          1 :                 return NULL;
    1112                 :            :         }
    1113                 :            : 
    1114                 :      33386 :         DO_LOCK ();
    1115                 :            : 
    1116                 :            :                 /* Find out where it belongs to */
    1117         [ +  + ]:    1265964 :                 for (block = all_blocks; block; block = block->next) {
    1118         [ +  + ]:    1265853 :                         if (sec_is_valid_word (block, memory)) {
    1119                 :      33275 :                                 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                 :      33275 :                                 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                 :      33275 :                                 break;
    1135                 :            :                         }
    1136                 :            :                 }
    1137                 :            : 
    1138                 :            :                 /* If it didn't work we may need to allocate a new block */
    1139   [ +  +  +  + ]:      33386 :                 if (block && !alloc)
    1140                 :       8298 :                         donew = 1;
    1141                 :            : 
    1142   [ +  +  -  + ]:      33386 :                 if (block && block->n_used == 0)
    1143                 :          0 :                         sec_block_destroy (block);
    1144                 :            : 
    1145                 :      33386 :         DO_UNLOCK ();
    1146                 :            : 
    1147         [ +  + ]:      33386 :         if (!block) {
    1148   [ +  -  +  - ]:        111 :                 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                 :        111 :                         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         [ +  + ]:      33275 :         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         [ -  + ]:      33275 :         if (!alloc)
    1172                 :          0 :                 errno = ENOMEM;
    1173                 :            : 
    1174                 :      33275 :         return alloc;
    1175                 :            : }
    1176                 :            : 
    1177                 :            : void
    1178                 :    1937553 : egg_secure_free (void *memory)
    1179                 :            : {
    1180                 :    1937553 :         egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK);
    1181                 :    1937553 : }
    1182                 :            : 
    1183                 :            : void
    1184                 :    1945867 : egg_secure_free_full (void *memory, int flags)
    1185                 :            : {
    1186                 :    1945867 :         Block *block = NULL;
    1187                 :            : 
    1188         [ +  + ]:    1945867 :         if (memory == NULL)
    1189                 :          4 :                 return;
    1190                 :            : 
    1191                 :    1945863 :         DO_LOCK ();
    1192                 :            : 
    1193                 :            :                 /* Find out where it belongs to */
    1194         [ +  + ]:    3463362 :                 for (block = all_blocks; block; block = block->next) {
    1195         [ +  + ]:    3461946 :                         if (sec_is_valid_word (block, memory))
    1196                 :    1944447 :                                 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         [ +  + ]:    1945863 :                 if (block != NULL) {
    1206                 :    1944447 :                         sec_free (block, memory);
    1207         [ +  + ]:    1944447 :                         if (block->n_used == 0)
    1208                 :      18825 :                                 sec_block_destroy (block);
    1209                 :            :                 }
    1210                 :            : 
    1211                 :    1945863 :         DO_UNLOCK ();
    1212                 :            : 
    1213         [ +  + ]:    1945863 :         if (!block) {
    1214   [ +  -  +  - ]:       1416 :                 if ((flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback) {
    1215                 :       1416 :                         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                 :        453 : egg_secure_check (const void *memory)
    1227                 :            : {
    1228                 :        453 :         Block *block = NULL;
    1229                 :            : 
    1230                 :        453 :         DO_LOCK ();
    1231                 :            : 
    1232                 :            :                 /* Find out where it belongs to */
    1233         [ +  + ]:        699 :                 for (block = all_blocks; block; block = block->next) {
    1234         [ +  + ]:        375 :                         if (sec_is_valid_word (block, (word_t*)memory))
    1235                 :        129 :                                 break;
    1236                 :            :                 }
    1237                 :            : 
    1238                 :        453 :         DO_UNLOCK ();
    1239                 :            : 
    1240                 :        453 :         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                 :          3 : egg_secure_strdup_full (const char *tag,
    1326                 :            :                         const char *str,
    1327                 :            :                         int options)
    1328                 :            : {
    1329                 :            :         size_t len;
    1330                 :            :         char *res;
    1331                 :            : 
    1332         [ -  + ]:          3 :         if (!str)
    1333                 :          0 :                 return NULL;
    1334                 :            : 
    1335                 :          3 :         len = strlen (str) + 1;
    1336                 :          3 :         res = (char *)egg_secure_alloc_full (tag, len, options);
    1337                 :          3 :         strcpy (res, str);
    1338                 :          3 :         return res;
    1339                 :            : }
    1340                 :            : 
    1341                 :            : char *
    1342                 :          2 : 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         [ -  + ]:          2 :         if (!str)
    1352                 :          0 :                 return NULL;
    1353                 :            : 
    1354                 :          2 :         end = memchr (str, '\0', length);
    1355         [ -  + ]:          2 :         if (end != NULL)
    1356                 :          0 :                 length = (end - str);
    1357                 :          2 :         len = length + 1;
    1358                 :          2 :         res = (char *)egg_secure_alloc_full (tag, len, options);
    1359                 :          2 :         memcpy (res, str, len);
    1360                 :          2 :         res[length] = '\0';
    1361                 :          2 :         return res;
    1362                 :            : }
    1363                 :            : 
    1364                 :            : void
    1365                 :         12 : egg_secure_clear (void *p, size_t length)
    1366                 :            : {
    1367                 :            :         volatile char *vp;
    1368                 :            : 
    1369         [ -  + ]:         12 :         if (p == NULL)
    1370                 :          0 :                 return;
    1371                 :            : 
    1372                 :         12 :         vp = (volatile char*)p;
    1373         [ +  + ]:        275 :         while (length) {
    1374                 :        263 :                 *vp = 0xAA;
    1375                 :        263 :                 vp++;
    1376                 :        263 :                 length--;
    1377                 :            :         }
    1378                 :            : }
    1379                 :            : 
    1380                 :            : void
    1381                 :         11 : egg_secure_strclear (char *str)
    1382                 :            : {
    1383         [ -  + ]:         11 :         if (!str)
    1384                 :          0 :                 return;
    1385                 :         11 :         egg_secure_clear ((unsigned char*)str, strlen (str));
    1386                 :            : }
    1387                 :            : 
    1388                 :            : void
    1389                 :         10 : 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                 :         10 :         egg_secure_strclear (str);
    1398                 :         10 :         egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK);
    1399                 :         10 : }

Generated by: LCOV version 1.14