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