/* The amount of extra words we can allocate */ #define WASTE 4
/* *Trackallocatedmemoryorafreeblock.Thisstructureisnotstored *inthesecurememoryarea.Itisallocatedfromapoolofother *memory.Seemeta_pool_xxx().
*/ typedefstruct _Cell {
word_t *words; /* Pointer to secure memory */
size_t n_words; /* Amount of secure memory in words */
size_t requested; /* Amount actually requested by app, in bytes, 0 if unused */ constchar *tag; /* Tag which describes the allocation */ struct _Cell *next; /* Next in memory ring */ struct _Cell *prev; /* Previous in memory ring */
} Cell;
/* *Ablockofsecurememory.Thisstructureistheheaderinthatblock.
*/ typedefstruct _Block {
word_t *words; /* Actual memory hangs off here */
size_t n_words; /* Number of words in block */
size_t n_used; /* Number of used allocations */ struct _Cell* used_cells; /* Ring of used allocations */ struct _Cell* unused_cells; /* Ring of unused allocations */ struct _Block *next; /* Next block in list */
} Block;
/* Pool allocates this data type */ typedefunion _Item {
Cell cell;
Block block;
} Item;
typedefstruct _Pool { struct _Pool *next; /* Next pool in list */
size_t length; /* Length in bytes of the pool */
size_t used; /* Number of cells used in pool */ void *unused; /* Unused stack of unused stuff */
size_t n_items; /* Total number of items in pool */
Item items[1]; /* Actual items hang off here */
} Pool;
staticvoid *
pool_alloc (void)
{ if (!check_pool_version ()) { if (show_warning && gtk_secure_warnings)
fprintf (stderr, "the secure memory pool version does not match the code '%s' != '%s'\n",
GTK_SECURE_GLOBALS.pool_version ? GTK_SECURE_GLOBALS.pool_version : "(null)",
GTK_SECURE_POOL_VER_STR);
show_warning = 0; return NULL;
}
#ifdefined(HAVE_MMAP) && defined(HAVE_GETPAGESIZE) /* A pool with an available item */
Pool *pool = NULL;
for (pool = GTK_SECURE_GLOBALS.pool_data; pool != NULL; pool = pool->next) { if (unused_peek (&pool->unused)) break;
}
void *item = NULL;
/* Create a new pool */ if (pool == NULL) {
size_t len = getpagesize () * 2; void *pages = mmap (0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pages == MAP_FAILED) return NULL;
/* Fill in the block header, and include in block list */
pool = pages;
pool->next = GTK_SECURE_GLOBALS.pool_data;
GTK_SECURE_GLOBALS.pool_data = pool;
pool->length = len;
pool->used = 0;
pool->unused = NULL;
/* Fill block with unused items */
pool->n_items = (len - sizeof (Pool)) / sizeof (Item); for (size_t i = 0; i < pool->n_items; ++i)
unused_push (&pool->unused, pool->items + i);
/* Find which block this one belongs to */ for (at = (Pool **)>K_SECURE_GLOBALS.pool_data, pool = *at;
pool != NULL; at = &pool->next, pool = *at) {
beg = (char*)pool->items;
end = (char*)pool + pool->length - sizeof (Item); if (ptr >= beg && ptr <= end) {
g_assert ((ptr - beg) % sizeof (Item) == 0); break;
}
}
/* Find which block this one belongs to */ for (pool = GTK_SECURE_GLOBALS.pool_data; pool; pool = pool->next) {
beg = (char*)pool->items;
end = (char*)pool + pool->length - sizeof (Item); if (ptr >= beg && ptr <= end) return (pool->used && (ptr - beg) % sizeof (Item) == 0);
}
/* Look for a cell of at least our required size */
cell = block->unused_cells; while (cell->n_words < n_words) {
cell = cell->next; if (cell == block->unused_cells) {
cell = NULL; break;
}
}
/* Steal from the cell if it's too long */ if (cell->n_words > n_words + WASTE) {
other = pool_alloc (); if (!other) return NULL;
other->n_words = n_words;
other->words = cell->words;
cell->n_words -= n_words;
cell->words += n_words;
/* Need braaaaaiiiiiinsss... */ while (cell->n_words < n_words) {
/* See if we have a neighbor who can give us some memory */
other = sec_neighbor_after (block, cell); if (!other || other->requested != 0) break;
/* Eat the whole neighbor if not too big */ if (n_words - cell->n_words + WASTE >= other->n_words) {
cell->n_words += other->n_words;
sec_write_guards (cell);
sec_remove_cell_ring (&block->unused_cells, other);
pool_free (other);
#ifdefined(HAVE_MLOCK) && defined(HAVE_MMAP) && defined(HAVE_GETPAGESIZE) /* Make sure sz is a multiple of the page size */ unsignedlong pgsize = getpagesize ();
#elifdefined G_OS_WIN32 /* Make sure sz is a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE in wincrypt.h */
*sz = (*sz + CRYPTPROTECTMEMORY_BLOCK_SIZE - 1) & ~(CRYPTPROTECTMEMORY_BLOCK_SIZE - 1);
void *data = (void *) LocalAlloc (LPTR, *sz);
if (data == NULL) { if (show_warning && gtk_secure_warnings)
fprintf (stderr, "couldn't allocate %lu bytes of memory (%s): %#010lX\n",
(unsignedlong)*sz, during_tag, GetLastError ());
show_warning = 0; return NULL;
}
if (!CryptProtectMemory (data, *sz, CRYPTPROTECTMEMORY_SAME_PROCESS)) { if (show_warning && gtk_secure_warnings)
fprintf (stderr, "couldn't encrypt %lu bytes of memory (%s): %#010lX\n",
(unsignedlong)*sz, during_tag, GetLastError ());
show_warning = 0; return NULL;
}
DEBUG_ALLOC ("gtk-secure-memory: new block ", *sz);
show_warning = 1; return data;
#else if (show_warning && gtk_secure_warnings)
fprintf (stderr, "your system does not support private memory");
show_warning = 0; return NULL; #endif
/* Remove from the list */ for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) { if (bl == block) {
*at = block->next; break;
}
}
/* Must have been found */
g_assert (bl == block);
g_assert (block->used_cells == NULL);
/* Release all the meta data cells */ while (block->unused_cells) {
cell = block->unused_cells;
sec_remove_cell_ring (&block->unused_cells, cell);
pool_free (cell);
}
/* Release all pages of secure memory */
sec_release_pages (block->words, block->n_words * sizeof (word_t));
if (length > 0xFFFFFFFF / 2) { if (gtk_secure_warnings)
fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n",
(unsignedlong)length); return NULL;
}
/* Can't allocate zero bytes */ if (length == 0) return NULL;
DO_LOCK ();
for (block = all_blocks; block; block = block->next) {
memory = sec_alloc (block, tag, length); if (memory) break;
}
/* None of the current blocks have space, allocate new */ if (!memory) {
block = sec_block_create (length, tag); if (block)
memory = sec_alloc (block, tag, length);
}
if (length > 0xFFFFFFFF / 2) { if (gtk_secure_warnings)
fprintf (stderr, "tried to allocate an excessive amount of memory: %lu\n",
(unsignedlong)length); return NULL;
}
if (memory == NULL) return gtk_secure_alloc_full (tag, length, flags); if (!length) {
gtk_secure_free_full (memory, flags); return NULL;
}
DO_LOCK ();
/* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, memory)) {
previous = sec_allocated (block, memory);
#ifdef WITH_VALGRIND /* Let valgrind think we are unallocating so that it'll validate */
VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t)); #endif
alloc = sec_realloc (block, tag, memory, length);
#ifdef WITH_VALGRIND /* Now tell valgrind about either the new block or old one */
VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory,
alloc ? length : previous, sizeof (word_t), 1); #endif break;
}
}
/* If it didn't work we may need to allocate a new block */ if (block && !alloc)
donew = 1;
if (block && block->n_used == 0)
sec_block_destroy (block);
DO_UNLOCK ();
if (!block) { if ((flags & GTK_SECURE_USE_FALLBACK) && GTK_SECURE_GLOBALS.fallback_alloc) { /* *Inthiscasewecan'tzerothereturnedmemory, *becausewedon'tknowwhattheblocksizewas.
*/ return GTK_SECURE_GLOBALS.fallback_alloc (memory, length);
} else { if (gtk_secure_warnings)
fprintf (stderr, "memory does not belong to secure memory pool: 0x%08" G_GUINTPTR_FORMAT "x\n",
(guintptr) memory);
g_assert (0 && "memory does does not belong to secure memory pool"); return NULL;
}
}
/* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, memory)) break;
}
#ifdef WITH_VALGRIND /* We like valgrind's warnings, so give it a first whack at checking for errors */ if (block != NULL || !(flags & GTK_SECURE_USE_FALLBACK))
VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t)); #endif
if (block != NULL) {
sec_free (block, memory); if (block->n_used == 0)
sec_block_destroy (block);
}
DO_UNLOCK ();
if (!block) { if ((flags & GTK_SECURE_USE_FALLBACK) && GTK_SECURE_GLOBALS.fallback_free) {
GTK_SECURE_GLOBALS.fallback_free (memory);
} else { if (gtk_secure_warnings)
fprintf (stderr, "memory does not belong to secure memory pool: 0x%08" G_GUINTPTR_FORMAT "x\n",
(guintptr) memory);
g_assert (0 && "memory does does not belong to secure memory pool");
}
}
}
int
gtk_secure_check (constvoid *memory)
{
Block *block = NULL;
DO_LOCK ();
/* Find out where it belongs to */ for (block = all_blocks; block; block = block->next) { if (sec_is_valid_word (block, (word_t*)memory)) break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.