libgcrypt: Import libgcrypt 1.11

We currently use an old version of libgcrypt which results in us having
fewer ciphers and missing on many other improvements.

Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Vladimir Serbinenko authored and Daniel Kiper committed 2025-07-11 23:12:50 +02:00
1 parent a0d4c94ef6
commit 3312af6e07
468 files changed
+210508 -33178

No files matched your search

+416 -211
View File
@@ -1,11 +1,12 @@
/* secmem.c - memory allocation from a secure heap
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
* 2003, 2007 Free Software Foundation, Inc.
* Copyright (C) 2013, 2016 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
@@ -36,7 +37,6 @@
#endif
#endif
#include "ath.h"
#include "g10lib.h"
#include "secmem.h"
@@ -59,35 +59,55 @@ typedef struct memblock
/* This flag specifies that the memory block is in use. */
#define MB_FLAG_ACTIVE (1 << 0)
/* The pool of secure memory. */
static void *pool;
/* An object describing a memory pool. */
typedef struct pooldesc_s
{
/* A link to the next pool. This is used to connect the overflow
* pools. */
struct pooldesc_s * volatile next;
/* Size of POOL in bytes. */
static size_t pool_size;
/* A memory buffer used as allocation pool. */
void *mem;
/* True, if the memory pool is ready for use. May be checked in an
atexit function. */
static volatile int pool_okay;
/* The allocated size of MEM. */
size_t size;
/* True, if the memory pool is mmapped. */
static volatile int pool_is_mmapped;
/* Flag indicating that this memory pool is ready for use. May be
* checked in an atexit function. */
volatile int okay;
/* FIXME? */
/* Flag indicating whether MEM is mmapped. */
volatile int is_mmapped;
/* The number of allocated bytes and the number of used blocks in
* this pool. */
unsigned int cur_alloced, cur_blocks;
} pooldesc_t;
/* The pool of secure memory. This is the head of a linked list with
* the first element being the standard mlock-ed pool and the
* following elements being the overflow pools. */
static pooldesc_t mainpool;
/* A couple of flags with some being set early. */
static int disable_secmem;
static int show_warning;
static int not_locked;
static int no_warning;
static int suspend_warning;
static int no_mlock;
static int no_priv_drop;
static unsigned int auto_expand;
/* Stats. */
static unsigned int cur_alloced, cur_blocks;
/* Lock protecting accesses to the memory pool. */
static ath_mutex_t secmem_lock;
/* Lock protecting accesses to the memory pools. */
GPGRT_LOCK_DEFINE (secmem_lock);
/* Convenient macros. */
#define SECMEM_LOCK ath_mutex_lock (&secmem_lock)
#define SECMEM_UNLOCK ath_mutex_unlock (&secmem_lock)
#define SECMEM_LOCK gpgrt_lock_lock (&secmem_lock)
#define SECMEM_UNLOCK gpgrt_lock_unlock (&secmem_lock)
/* The size of the memblock structure; this does not include the
memory that is available to the user. */
@@ -96,48 +116,77 @@ static ath_mutex_t secmem_lock;
/* Convert an address into the according memory block structure. */
#define ADDR_TO_BLOCK(addr) \
(memblock_t *) ((char *) addr - BLOCK_HEAD_SIZE)
(memblock_t *) (void *) ((char *) addr - BLOCK_HEAD_SIZE)
/* Check whether P points into the pool. */
static int
ptr_into_pool_p (const void *p)
/* Prototypes. */
static void secmem_dump_stats_internal (int extended);
/*
* Functions
*/
/* Memory barrier */
static inline void
memory_barrier(void)
{
#ifdef HAVE_SYNC_SYNCHRONIZE
#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
asm volatile ("":::"memory");
#endif
/* Use GCC / clang intrinsic for memory barrier. */
__sync_synchronize();
#else
/* Slow portable alternative, implement memory barrier by using mutex. */
gpgrt_lock_t tmp;
memset (&tmp, 0, sizeof(tmp));
gpgrt_lock_init (&tmp);
gpgrt_lock_lock (&tmp);
gpgrt_lock_unlock (&tmp);
gpgrt_lock_destroy (&tmp);
#endif
}
/* Check whether P points into POOL. */
static inline int
ptr_into_pool_p (pooldesc_t *pool, const void *p)
{
/* We need to convert pointers to addresses. This is required by
C-99 6.5.8 to avoid undefined behaviour. Using size_t is at
least only implementation defined. See also
C-99 6.5.8 to avoid undefined behaviour. See also
http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
*/
size_t p_addr = (size_t)p;
size_t pool_addr = (size_t)pool;
uintptr_t p_addr = (uintptr_t)p;
uintptr_t pool_addr = (uintptr_t)pool->mem;
return p_addr >= pool_addr && p_addr < pool_addr+pool_size;
return p_addr >= pool_addr && p_addr < pool_addr + pool->size;
}
/* Update the stats. */
static void
stats_update (size_t add, size_t sub)
stats_update (pooldesc_t *pool, size_t add, size_t sub)
{
if (add)
{
cur_alloced += add;
cur_blocks++;
pool->cur_alloced += add;
pool->cur_blocks++;
}
if (sub)
{
cur_alloced -= sub;
cur_blocks--;
pool->cur_alloced -= sub;
pool->cur_blocks--;
}
}
/* Return the block following MB or NULL, if MB is the last block. */
static memblock_t *
mb_get_next (memblock_t *mb)
mb_get_next (pooldesc_t *pool, memblock_t *mb)
{
memblock_t *mb_next;
mb_next = (memblock_t *) ((char *) mb + BLOCK_HEAD_SIZE + mb->size);
mb_next = (memblock_t *) (void *) ((char *) mb + BLOCK_HEAD_SIZE + mb->size);
if (! ptr_into_pool_p (mb_next))
if (! ptr_into_pool_p (pool, mb_next))
mb_next = NULL;
return mb_next;
@@ -146,18 +195,18 @@ mb_get_next (memblock_t *mb)
/* Return the block preceding MB or NULL, if MB is the first
block. */
static memblock_t *
mb_get_prev (memblock_t *mb)
mb_get_prev (pooldesc_t *pool, memblock_t *mb)
{
memblock_t *mb_prev, *mb_next;
if (mb == pool)
if (mb == pool->mem)
mb_prev = NULL;
else
{
mb_prev = (memblock_t *) pool;
mb_prev = (memblock_t *) pool->mem;
while (1)
{
mb_next = mb_get_next (mb_prev);
mb_next = mb_get_next (pool, mb_prev);
if (mb_next == mb)
break;
else
@@ -171,12 +220,12 @@ mb_get_prev (memblock_t *mb)
/* If the preceding block of MB and/or the following block of MB
exist and are not active, merge them to form a bigger block. */
static void
mb_merge (memblock_t *mb)
mb_merge (pooldesc_t *pool, memblock_t *mb)
{
memblock_t *mb_prev, *mb_next;
mb_prev = mb_get_prev (mb);
mb_next = mb_get_next (mb);
mb_prev = mb_get_prev (pool, mb);
mb_next = mb_get_next (pool, mb);
if (mb_prev && (! (mb_prev->flags & MB_FLAG_ACTIVE)))
{
@@ -189,11 +238,11 @@ mb_merge (memblock_t *mb)
/* Return a new block, which can hold SIZE bytes. */
static memblock_t *
mb_get_new (memblock_t *block, size_t size)
mb_get_new (pooldesc_t *pool, memblock_t *block, size_t size)
{
memblock_t *mb, *mb_split;
for (mb = block; ptr_into_pool_p (mb); mb = mb_get_next (mb))
for (mb = block; ptr_into_pool_p (pool, mb); mb = mb_get_next (pool, mb))
if (! (mb->flags & MB_FLAG_ACTIVE) && mb->size >= size)
{
/* Found a free block. */
@@ -203,20 +252,21 @@ mb_get_new (memblock_t *block, size_t size)
{
/* Split block. */
mb_split = (memblock_t *) (((char *) mb) + BLOCK_HEAD_SIZE + size);
mb_split = (memblock_t *) (void *) (((char *) mb) + BLOCK_HEAD_SIZE
+ size);
mb_split->size = mb->size - size - BLOCK_HEAD_SIZE;
mb_split->flags = 0;
mb->size = size;
mb_merge (mb_split);
mb_merge (pool, mb_split);
}
break;
}
if (! ptr_into_pool_p (mb))
if (! ptr_into_pool_p (pool, mb))
{
gpg_err_set_errno (ENOMEM);
mb = NULL;
@@ -233,38 +283,13 @@ print_warn (void)
log_info (_("Warning: using insecure memory!\n"));
}
/* Lock the memory pages into core and drop privileges. */
/* Lock the memory pages of pool P of size N into core and drop
* privileges. */
static void
lock_pool (void *p, size_t n)
lock_pool_pages (void *p, size_t n)
{
#if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
int err;
cap_set_proc (cap_from_text ("cap_ipc_lock+ep"));
err = mlock (p, n);
if (err && errno)
err = errno;
cap_set_proc (cap_from_text ("cap_ipc_lock+p"));
if (err)
{
if (errno != EPERM
#ifdef EAGAIN /* OpenBSD returns this */
&& errno != EAGAIN
#endif
#ifdef ENOSYS /* Some SCOs return this (function not implemented) */
&& errno != ENOSYS
#endif
#ifdef ENOMEM /* Linux might return this. */
&& errno != ENOMEM
#endif
)
log_error ("can't lock memory: %s\n", strerror (err));
show_warning = 1;
not_locked = 1;
}
#elif defined(HAVE_MLOCK)
#if defined(HAVE_MLOCK)
uid_t uid;
int err;
@@ -278,32 +303,33 @@ lock_pool (void *p, size_t n)
if (uid)
{
errno = EPERM;
err = errno;
err = -1;
}
else
{
err = mlock (p, n);
if (err && errno)
err = errno;
err = no_mlock? 0 : mlock (p, n);
}
#else /* !HAVE_BROKEN_MLOCK */
err = mlock (p, n);
if (err && errno)
err = errno;
err = no_mlock? 0 : mlock (p, n);
#endif /* !HAVE_BROKEN_MLOCK */
/* Test whether we are running setuid(0). */
if (uid && ! geteuid ())
{
/* check that we really dropped the privs.
* Note: setuid(0) should always fail */
if (setuid (uid) || getuid () != geteuid () || !setuid (0))
log_fatal ("failed to reset uid: %s\n", strerror (errno));
/* Yes, we are. */
if (!no_priv_drop)
{
/* Check that we really dropped the privs.
* Note: setuid(0) should always fail */
if (setuid (uid) || getuid () != geteuid () || !setuid (0))
log_fatal ("failed to reset uid: %s\n", strerror (errno));
}
}
if (err)
{
if (errno != EPERM
#ifdef EAGAIN /* OpenBSD returns this. */
#ifdef EAGAIN /* BSD and also Linux may return this. */
&& errno != EAGAIN
#endif
#ifdef ENOSYS /* Some SCOs return this (function not implemented). */
@@ -313,7 +339,7 @@ lock_pool (void *p, size_t n)
&& errno != ENOMEM
#endif
)
log_error ("can't lock memory: %s\n", strerror (err));
log_error ("can't lock memory: %s\n", strerror (errno));
show_warning = 1;
not_locked = 1;
}
@@ -330,90 +356,107 @@ lock_pool (void *p, size_t n)
* this whole Windows !@#$% and their user base are inherently insecure. */
(void)p;
(void)n;
#elif defined (__riscos__)
/* No virtual memory on RISC OS, so no pages are swapped to disc,
* besides we don't have mmap, so we don't use it! ;-)
* But don't complain, as explained above. */
(void)p;
(void)n;
#else
(void)p;
(void)n;
log_info ("Please note that you don't have secure memory on this system\n");
if (!no_mlock)
log_info ("Please note that you don't have secure memory on this system\n");
#endif
}
/* Initialize POOL. */
static void
init_pool (size_t n)
init_pool (pooldesc_t *pool, size_t n)
{
size_t pgsize;
long int pgsize_val;
memblock_t *mb;
pool_size = n;
pool->size = n;
if (disable_secmem)
log_bug ("secure memory is disabled");
#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
pgsize_val = sysconf (_SC_PAGESIZE);
#elif defined(HAVE_GETPAGESIZE)
pgsize_val = getpagesize ();
#else
pgsize_val = -1;
#endif
pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val:DEFAULT_PAGE_SIZE;
#if HAVE_MMAP
pool_size = (pool_size + pgsize - 1) & ~(pgsize - 1);
#ifdef MAP_ANONYMOUS
pool = mmap (0, pool_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#else /* map /dev/zero instead */
{
int fd;
size_t pgsize;
long int pgsize_val;
fd = open ("/dev/zero", O_RDWR);
if (fd == -1)
{
log_error ("can't open /dev/zero: %s\n", strerror (errno));
pool = (void *) -1;
}
# if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
pgsize_val = sysconf (_SC_PAGESIZE);
# elif defined(HAVE_GETPAGESIZE)
pgsize_val = getpagesize ();
# else
pgsize_val = -1;
# endif
pgsize = (pgsize_val > 0)? pgsize_val:DEFAULT_PAGE_SIZE;
pool->size = (pool->size + pgsize - 1) & ~(pgsize - 1);
# ifdef MAP_ANONYMOUS
pool->mem = mmap (0, pool->size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
# else /* map /dev/zero instead */
{
int fd;
fd = open ("/dev/zero", O_RDWR);
if (fd == -1)
{
log_error ("can't open /dev/zero: %s\n", strerror (errno));
pool->mem = (void *) -1;
}
else
{
pool->mem = mmap (0, pool->size,
(PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
close (fd);
}
}
# endif
if (pool->mem == (void *) -1)
log_info ("can't mmap pool of %u bytes: %s - using malloc\n",
(unsigned) pool->size, strerror (errno));
else
{
pool = mmap (0, pool_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
close (fd);
pool->is_mmapped = 1;
pool->okay = 1;
}
}
#endif
if (pool == (void *) -1)
log_info ("can't mmap pool of %u bytes: %s - using malloc\n",
(unsigned) pool_size, strerror (errno));
else
{
pool_is_mmapped = 1;
pool_okay = 1;
}
#endif /*HAVE_MMAP*/
#endif
if (!pool_okay)
if (!pool->okay)
{
pool = malloc (pool_size);
if (!pool)
pool->mem = malloc (pool->size);
if (!pool->mem)
log_fatal ("can't allocate memory pool of %u bytes\n",
(unsigned) pool_size);
(unsigned) pool->size);
else
pool_okay = 1;
pool->okay = 1;
}
/* Initialize first memory block. */
mb = (memblock_t *) pool;
mb->size = pool_size;
mb = (memblock_t *) pool->mem;
mb->size = pool->size - BLOCK_HEAD_SIZE;
mb->flags = 0;
}
/* Enable overflow pool allocation in all cases. CHUNKSIZE is a hint
* on how large to allocate overflow pools. */
void
_gcry_secmem_set_auto_expand (unsigned int chunksize)
{
/* Round up to a multiple of the STANDARD_POOL_SIZE. */
chunksize = ((chunksize + (2*STANDARD_POOL_SIZE) - 1)
/ STANDARD_POOL_SIZE ) * STANDARD_POOL_SIZE;
if (chunksize < STANDARD_POOL_SIZE) /* In case of overflow. */
chunksize = STANDARD_POOL_SIZE;
SECMEM_LOCK;
auto_expand = chunksize;
SECMEM_UNLOCK;
}
void
_gcry_secmem_set_flags (unsigned flags)
{
@@ -424,6 +467,8 @@ _gcry_secmem_set_flags (unsigned flags)
was_susp = suspend_warning;
no_warning = flags & GCRY_SECMEM_FLAG_NO_WARNING;
suspend_warning = flags & GCRY_SECMEM_FLAG_SUSPEND_WARNING;
no_mlock = flags & GCRY_SECMEM_FLAG_NO_MLOCK;
no_priv_drop = flags & GCRY_SECMEM_FLAG_NO_PRIV_DROP;
/* and now issue the warning if it is not longer suspended */
if (was_susp && !suspend_warning && show_warning)
@@ -445,6 +490,8 @@ _gcry_secmem_get_flags (void)
flags = no_warning ? GCRY_SECMEM_FLAG_NO_WARNING : 0;
flags |= suspend_warning ? GCRY_SECMEM_FLAG_SUSPEND_WARNING : 0;
flags |= not_locked ? GCRY_SECMEM_FLAG_NOT_LOCKED : 0;
flags |= no_mlock ? GCRY_SECMEM_FLAG_NO_MLOCK : 0;
flags |= no_priv_drop ? GCRY_SECMEM_FLAG_NO_PRIV_DROP : 0;
SECMEM_UNLOCK;
@@ -452,16 +499,26 @@ _gcry_secmem_get_flags (void)
}
/* See _gcry_secmem_init. This function is expected to be called with
the secmem lock held. */
/* This function initializes the main memory pool MAINPOOL. It is
* expected to be called with the secmem lock held. */
static void
secmem_init (size_t n)
_gcry_secmem_init_internal (size_t n)
{
pooldesc_t *pool;
pool = &mainpool;
if (!n)
{
#ifdef USE_CAPABILITIES
/* drop all capabilities */
cap_set_proc (cap_from_text ("all-eip"));
if (!no_priv_drop)
{
cap_t cap;
cap = cap_from_text ("all-eip");
cap_set_proc (cap);
cap_free (cap);
}
#elif !defined(HAVE_DOSISH_SYSTEM)
uid_t uid;
@@ -479,10 +536,10 @@ secmem_init (size_t n)
{
if (n < MINIMUM_POOL_SIZE)
n = MINIMUM_POOL_SIZE;
if (! pool_okay)
if (! pool->okay)
{
init_pool (n);
lock_pool (pool, n);
init_pool (pool, n);
lock_pool_pages (pool->mem, n);
}
else
log_error ("Oops, secure memory pool already initialized\n");
@@ -500,22 +557,33 @@ _gcry_secmem_init (size_t n)
{
SECMEM_LOCK;
secmem_init (n);
_gcry_secmem_init_internal (n);
SECMEM_UNLOCK;
}
static void *
_gcry_secmem_malloc_internal (size_t size)
gcry_err_code_t
_gcry_secmem_module_init (void)
{
/* Not anymore needed. */
return 0;
}
static void *
_gcry_secmem_malloc_internal (size_t size, int xhint)
{
pooldesc_t *pool;
memblock_t *mb;
if (!pool_okay)
pool = &mainpool;
if (!pool->okay)
{
/* Try to initialize the pool if the user forgot about it. */
secmem_init (STANDARD_POOL_SIZE);
if (!pool_okay)
_gcry_secmem_init_internal (STANDARD_POOL_SIZE);
if (!pool->okay)
{
log_info (_("operation is not possible without "
"initialized secure memory\n"));
@@ -538,33 +606,108 @@ _gcry_secmem_malloc_internal (size_t size)
/* Blocks are always a multiple of 32. */
size = ((size + 31) / 32) * 32;
mb = mb_get_new ((memblock_t *) pool, size);
mb = mb_get_new (pool, (memblock_t *) pool->mem, size);
if (mb)
stats_update (size, 0);
{
stats_update (pool, mb->size, 0);
return &mb->aligned.c;
}
return mb ? &mb->aligned.c : NULL;
/* If we are called from xmalloc style functions resort to the
* overflow pools to return memory. We don't do this in FIPS mode,
* though. If the auto-expand option is active we do the expanding
* also for the standard malloc functions.
*
* The idea of using them by default only for the xmalloc function
* is so that a user can control whether memory will be allocated in
* the initial created mlock protected secmem area or may also be
* allocated from the overflow pools. */
if ((xhint || auto_expand) && !fips_mode ())
{
/* Check whether we can allocate from the overflow pools. */
for (pool = pool->next; pool; pool = pool->next)
{
mb = mb_get_new (pool, (memblock_t *) pool->mem, size);
if (mb)
{
stats_update (pool, mb->size, 0);
return &mb->aligned.c;
}
}
/* Allocate a new overflow pool. We put a new pool right after
* the mainpool so that the next allocation will happen in that
* pool and not in one of the older pools. When this new pool
* gets full we will try to find space in the older pools. */
pool = calloc (1, sizeof *pool);
if (!pool)
return NULL; /* Not enough memory for a new pool descriptor. */
pool->size = auto_expand? auto_expand : STANDARD_POOL_SIZE;
pool->mem = malloc (pool->size);
if (!pool->mem)
{
free (pool);
return NULL; /* Not enough memory available for a new pool. */
}
/* Initialize first memory block. */
mb = (memblock_t *) pool->mem;
mb->size = pool->size - BLOCK_HEAD_SIZE;
mb->flags = 0;
pool->okay = 1;
/* Take care: in _gcry_private_is_secure we do not lock and thus
* we assume that the second assignment below is atomic. Memory
* barrier prevents reordering of stores to new pool structure after
* MAINPOOL.NEXT assigment and prevents _gcry_private_is_secure seeing
* non-initialized POOL->NEXT pointers. */
pool->next = mainpool.next;
memory_barrier();
mainpool.next = pool;
/* After the first time we allocated an overflow pool, print a
* warning. */
if (!pool->next)
print_warn ();
/* Allocate. */
mb = mb_get_new (pool, (memblock_t *) pool->mem, size);
if (mb)
{
stats_update (pool, mb->size, 0);
return &mb->aligned.c;
}
}
return NULL;
}
/* Allocate a block from the secmem of SIZE. With XHINT set assume
* that the caller is a xmalloc style function. */
void *
_gcry_secmem_malloc (size_t size)
_gcry_secmem_malloc (size_t size, int xhint)
{
void *p;
SECMEM_LOCK;
p = _gcry_secmem_malloc_internal (size);
p = _gcry_secmem_malloc_internal (size, xhint);
SECMEM_UNLOCK;
return p;
}
static void
static int
_gcry_secmem_free_internal (void *a)
{
pooldesc_t *pool;
memblock_t *mb;
int size;
if (!a)
return;
for (pool = &mainpool; pool; pool = pool->next)
if (pool->okay && ptr_into_pool_p (pool, a))
break;
if (!pool)
return 0; /* A does not belong to use. */
mb = ADDR_TO_BLOCK (a);
size = mb->size;
@@ -572,42 +715,50 @@ _gcry_secmem_free_internal (void *a)
/* This does not make much sense: probably this memory is held in the
* cache. We do it anyway: */
#define MB_WIPE_OUT(byte) \
wipememory2 ((memblock_t *) ((char *) mb + BLOCK_HEAD_SIZE), (byte), size);
wipememory2 (((char *) mb + BLOCK_HEAD_SIZE), (byte), size)
MB_WIPE_OUT (0xff);
MB_WIPE_OUT (0xaa);
MB_WIPE_OUT (0x55);
MB_WIPE_OUT (0x00);
stats_update (0, size);
/* Update stats. */
stats_update (pool, 0, size);
mb->flags &= ~MB_FLAG_ACTIVE;
/* Update stats. */
mb_merge (pool, mb);
mb_merge (mb);
return 1; /* Freed. */
}
/* Wipe out and release memory. */
void
/* Wipe out and release memory. Returns true if this function
* actually released A. */
int
_gcry_secmem_free (void *a)
{
int mine;
if (!a)
return 1; /* Tell caller that we handled it. */
SECMEM_LOCK;
_gcry_secmem_free_internal (a);
mine = _gcry_secmem_free_internal (a);
SECMEM_UNLOCK;
return mine;
}
/* Realloc memory. */
void *
_gcry_secmem_realloc (void *p, size_t newsize)
static void *
_gcry_secmem_realloc_internal (void *p, size_t newsize, int xhint)
{
memblock_t *mb;
size_t size;
void *a;
SECMEM_LOCK;
mb = (memblock_t *) ((char *) p - ((size_t) &((memblock_t *) 0)->aligned.c));
mb = (memblock_t *) (void *) ((char *) p
- offsetof (memblock_t, aligned.c));
size = mb->size;
if (newsize < size)
{
@@ -616,7 +767,7 @@ _gcry_secmem_realloc (void *p, size_t newsize)
}
else
{
a = _gcry_secmem_malloc_internal (newsize);
a = _gcry_secmem_malloc_internal (newsize, xhint);
if (a)
{
memcpy (a, p, size);
@@ -625,17 +776,43 @@ _gcry_secmem_realloc (void *p, size_t newsize)
}
}
return a;
}
/* Realloc memory. With XHINT set assume that the caller is a xmalloc
* style function. */
void *
_gcry_secmem_realloc (void *p, size_t newsize, int xhint)
{
void *a;
SECMEM_LOCK;
a = _gcry_secmem_realloc_internal (p, newsize, xhint);
SECMEM_UNLOCK;
return a;
}
/* Return true if P points into the secure memory area. */
/* Return true if P points into the secure memory areas. */
int
_gcry_private_is_secure (const void *p)
{
return pool_okay && ptr_into_pool_p (p);
pooldesc_t *pool;
/* We do no lock here because once a pool is allocated it will not
* be removed anymore (except for gcry_secmem_term). Further, as
* assigment of POOL->NEXT in new pool structure is visible in
* this thread before assigment of MAINPOOL.NEXT, pool list can be
* iterated locklessly. This visiblity is ensured by memory barrier
* between POOL->NEXT and MAINPOOL.NEXT assignments in
* _gcry_secmem_malloc_internal. */
for (pool = &mainpool; pool; pool = pool->next)
if (pool->okay && ptr_into_pool_p (pool, p))
return 1;
return 0;
}
@@ -648,49 +825,77 @@ _gcry_private_is_secure (const void *p)
* there is no chance to get the secure memory cleaned.
*/
void
_gcry_secmem_term ()
_gcry_secmem_term (void)
{
if (!pool_okay)
return;
pooldesc_t *pool, *next;
wipememory2 (pool, 0xff, pool_size);
wipememory2 (pool, 0xaa, pool_size);
wipememory2 (pool, 0x55, pool_size);
wipememory2 (pool, 0x00, pool_size);
for (pool = &mainpool; pool; pool = next)
{
next = pool->next;
if (!pool->okay)
continue;
wipememory2 (pool->mem, 0xff, pool->size);
wipememory2 (pool->mem, 0xaa, pool->size);
wipememory2 (pool->mem, 0x55, pool->size);
wipememory2 (pool->mem, 0x00, pool->size);
if (0)
;
#if HAVE_MMAP
if (pool_is_mmapped)
munmap (pool, pool_size);
else if (pool->is_mmapped)
munmap (pool->mem, pool->size);
#endif
pool = NULL;
pool_okay = 0;
pool_size = 0;
else
free (pool->mem);
pool->mem = NULL;
pool->okay = 0;
pool->size = 0;
if (pool != &mainpool)
free (pool);
}
mainpool.next = NULL;
not_locked = 0;
}
/* Print stats of the secmem allocator. With EXTENDED passwed as true
* a detiled listing is returned (used for testing). */
void
_gcry_secmem_dump_stats ()
_gcry_secmem_dump_stats (int extended)
{
#if 1
SECMEM_LOCK;
if (pool_okay)
log_info ("secmem usage: %u/%lu bytes in %u blocks\n",
cur_alloced, (unsigned long)pool_size, cur_blocks);
secmem_dump_stats_internal (extended);
SECMEM_UNLOCK;
#else
memblock_t *mb;
int i;
SECMEM_LOCK;
for (i = 0, mb = (memblock_t *) pool;
ptr_into_pool_p (mb);
mb = mb_get_next (mb), i++)
log_info ("SECMEM: [%s] block: %i; size: %i\n",
(mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
i,
mb->size);
SECMEM_UNLOCK;
#endif
}
static void
secmem_dump_stats_internal (int extended)
{
pooldesc_t *pool;
memblock_t *mb;
int i, poolno;
for (pool = &mainpool, poolno = 0; pool; pool = pool->next, poolno++)
{
if (!extended)
{
if (pool->okay)
log_info ("%-13s %u/%lu bytes in %u blocks\n",
pool == &mainpool? "secmem usage:":"",
pool->cur_alloced, (unsigned long)pool->size,
pool->cur_blocks);
}
else
{
for (i = 0, mb = (memblock_t *) pool->mem;
ptr_into_pool_p (pool, mb);
mb = mb_get_next (pool, mb), i++)
log_info ("SECMEM: pool %d %s block %i size %i\n",
poolno,
(mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
i,
mb->size);
}
}
}