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 : }
|