[git] GCRYPT - branch, master, updated. libgcrypt-1.7.3-27-g95bac31

by Werner Koch cvs at cvs.gnupg.org
Wed Dec 7 17:04:41 CET 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  95bac312644ad45e486c94c2efd25d0748b9a20b (commit)
       via  b6870cf25c0b1eb9c127a94af8326c446421a472 (commit)
       via  b7df907dca4d525f8930c533b763ffce44ceed87 (commit)
       via  e366c19b34922c770af82cd035fd815680b29dee (commit)
      from  995ce697308320c6a52a307f83dc49eeb8d784b4 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 95bac312644ad45e486c94c2efd25d0748b9a20b
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Dec 7 17:01:19 2016 +0100

    Document the overflow pools and add a stupid test case.
    
    * tests/t-secmem.c (test_secmem_overflow): New func.
    (main): Disable warning and call new function.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 933d22d..cb539da 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -422,8 +422,11 @@ and freed memory, you need to initialize Libgcrypt this way:
      process might still be running with increased privileges and that
      the secure memory has not been initialized.  */
 
-  /* Allocate a pool of 16k secure memory.  This make the secure memory
-     available and also drops privileges where needed.  */
+  /* Allocate a pool of 16k secure memory.  This makes the secure memory
+     available and also drops privileges where needed.  Note that by
+     using functions like gcry_xmalloc_secure and gcry_mpi_snew Libgcrypt
+     may extend the secure memory pool with memory which lacks the
+     property of not being swapped out to disk.   */
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
 
 @anchor{sample-use-resume-secmem}
@@ -667,7 +670,10 @@ it right away.  This command should be executed right after
 This command disables the use of the mlock call for secure memory.
 Disabling the use of mlock may for example be done if an encrypted
 swap space is in use.  This command should be executed right after
- at code{gcry_check_version}.
+ at code{gcry_check_version}.  Note that by using functions like
+gcry_xmalloc_secure and gcry_mpi_snew Libgcrypt may extend the secure
+memory pool with memory which lacks the property of not being swapped
+out to disk (but will still be zeroed out on free).
 
 @item GCRYCTL_DISABLE_PRIV_DROP; Arguments: none
 This command sets a global flag to tell the secure memory subsystem
diff --git a/tests/t-secmem.c b/tests/t-secmem.c
index b464d02..cb2313e 100644
--- a/tests/t-secmem.c
+++ b/tests/t-secmem.c
@@ -57,6 +57,31 @@ test_secmem (void)
 }
 
 
+static void
+test_secmem_overflow (void)
+{
+  void *a[150];
+  int i;
+
+  memset (a, 0, sizeof a);
+
+  /* Allocating 150*512=75k should require more than one overflow buffer.  */
+  for (i=0; i < DIM(a); i++)
+    {
+      a[i] = gcry_xmalloc_secure (512);
+      if (verbose && !(i %40))
+        gcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
+    }
+
+  if (debug)
+    gcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
+  if (verbose)
+    gcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
+  for (i=0; i < DIM(a); i++)
+    xfree (a[i]);
+}
+
+
 /* This function is called when we ran out of core and there is no way
  * to return that error to the caller (xmalloc or mpi allocation).  */
 static int
@@ -132,10 +157,24 @@ main (int argc, char **argv)
   gcry_set_outofcore_handler (outofcore_handler, NULL);
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 
+  /* Libgcrypt prints a warning when the first overflow is allocated;
+   * we do not want to see that.  */
+  if (!verbose)
+    gcry_control (GCRYCTL_DISABLE_SECMEM_WARN, 0);
+
+
   test_secmem ();
+  test_secmem_overflow ();
+  /* FIXME: We need to improve the tests, for example by registering
+   * our own log handler and comparing the output of
+   * PRIV_CTL_DUMP_SECMEM_STATS to expected pattern.  */
 
   if (verbose)
-    gcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
+    {
+      gcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
+      gcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
+    }
   info ("All tests completed.  Errors: %d\n", errorcount);
+  gcry_control (GCRYCTL_TERM_SECMEM, 0 , 0);
   return !!errorcount;
 }

commit b6870cf25c0b1eb9c127a94af8326c446421a472
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Dec 7 16:59:57 2016 +0100

    Implement overflow secmem pools for xmalloc style allocators.
    
    * src/secmem.c (pooldesc_s): Add fields next, cur_alloced, and
    cur_blocks.
    (cur_alloced, cur_blocks): Remove vars.
    (ptr_into_pool_p): Make it inline.
    (stats_update): Add arg pool and update the new pool specific
    counters.
    (_gcry_secmem_malloc_internal): Add arg xhint and allocate overflow
    pools as needed.
    (_gcry_secmem_malloc): Pass XHINTS along.
    (_gcry_secmem_realloc_internal): Ditto.
    (_gcry_secmem_realloc): Ditto.
    (_gcry_secmem_free_internal): Take multiple pools in account.  Add
    return value to indicate whether the arg was freed.
    (_gcry_secmem_free): Add return value to indicate whether the arg was
    freed.
    (_gcry_private_is_secure): Take multiple pools in account.
    (_gcry_secmem_term): Release all pools.
    (_gcry_secmem_dump_stats): Print stats for all pools.
    * src/stdmem.c (_gcry_private_free): Replace _gcry_private_is_secure
    test with a direct call of _gcry_secmem_free to avoid double checking.
    --
    
    This patch avoids process termination due to an out-of-secure-memory
    condition in the MPI subsystem.  We consider it more important to have
    reliable MPI computations than process termination due the need for
    memory which is protected against being swapped out.  Using encrypted
    swap is anyway a more reliable protection than those mlock'ed pages.
    Note also that mlock'ed pages won't help against hibernation.
    
    GnuPG-bug-id: 2857
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/secmem.c b/src/secmem.c
index 928e03f..4fa267b 100644
--- a/src/secmem.c
+++ b/src/secmem.c
@@ -62,6 +62,10 @@ typedef struct memblock
 /* 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 *next;
+
   /* A memory buffer used as allocation pool.  */
   void *mem;
 
@@ -75,10 +79,15 @@ typedef struct pooldesc_s
   /* 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.  */
+/* 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;
 
 
@@ -91,9 +100,6 @@ static int suspend_warning;
 static int no_mlock;
 static int no_priv_drop;
 
-/* Stats.  */
-static unsigned int cur_alloced, cur_blocks;
-
 /* Lock protecting accesses to the memory pools.  */
 GPGRT_LOCK_DEFINE (secmem_lock);
 
@@ -111,7 +117,7 @@ GPGRT_LOCK_DEFINE (secmem_lock);
   (memblock_t *) (void *) ((char *) addr - BLOCK_HEAD_SIZE)
 
 /* Check whether P points into POOL.  */
-static int
+static inline int
 ptr_into_pool_p (pooldesc_t *pool, const void *p)
 {
   /* We need to convert pointers to addresses.  This is required by
@@ -126,17 +132,17 @@ ptr_into_pool_p (pooldesc_t *pool, const void *p)
 
 /* 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--;
     }
 }
 
@@ -567,7 +573,7 @@ _gcry_secmem_module_init ()
 
 
 static void *
-_gcry_secmem_malloc_internal (size_t size)
+_gcry_secmem_malloc_internal (size_t size, int xhint)
 {
   pooldesc_t *pool;
   memblock_t *mb;
@@ -603,9 +609,63 @@ _gcry_secmem_malloc_internal (size_t size)
 
   mb = mb_get_new (pool, (memblock_t *) pool->mem, size);
   if (mb)
-    stats_update (size, 0);
+    {
+      stats_update (pool, size, 0);
+      return &mb->aligned.c;
+    }
+
+  /* If we are called from xmalloc style function resort to the
+   * overflow pools to return memory.  We don't do this in FIPS mode,
+   * though. */
+  if (xhint && !fips_mode ())
+    {
+      for (pool = pool->next; pool; pool = pool->next)
+        {
+          mb = mb_get_new (pool, (memblock_t *) pool->mem, size);
+          if (mb)
+            {
+              stats_update (pool, 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 = STANDARD_POOL_SIZE;
+      pool->mem = malloc (pool->size);
+      if (!pool->mem)
+        return NULL; /* Not enough memory available for a new pool.  */
+      /* Initialize first memory block.  */
+      mb = (memblock_t *) pool->mem;
+      mb->size = pool->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.  */
+      pool->next = mainpool.next;
+      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, size, 0);
+          return &mb->aligned.c;
+        }
+    }
 
-  return mb ? &mb->aligned.c : NULL;
+  return NULL;
 }
 
 
@@ -617,20 +677,24 @@ _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;
 
-  pool = &mainpool;
+  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;
@@ -646,29 +710,35 @@ _gcry_secmem_free_internal (void *a)
   MB_WIPE_OUT (0x00);
 
   /* Update stats.  */
-  stats_update (0, size);
+  stats_update (pool, 0, size);
 
   mb->flags &= ~MB_FLAG_ACTIVE;
 
-
   mb_merge (pool, 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;
+    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;
 }
 
 
 static void *
-_gcry_secmem_realloc_internal (void *p, size_t newsize)
+_gcry_secmem_realloc_internal (void *p, size_t newsize, int xhint)
 {
   memblock_t *mb;
   size_t size;
@@ -684,7 +754,7 @@ _gcry_secmem_realloc_internal (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);
@@ -705,21 +775,27 @@ _gcry_secmem_realloc (void *p, size_t newsize, int xhint)
   void *a;
 
   SECMEM_LOCK;
-  a = _gcry_secmem_realloc_internal (p, newsize);
+  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)
 {
   pooldesc_t *pool;
 
-  pool = &mainpool;
-  return pool->okay && ptr_into_pool_p (pool, p);
+  /* We do no lock here because once a pool is allocatred it will not
+   * be removed anymore (except for gcry_secmem_term).  Further,
+   * adding a new pool to the list should be atomic.  */
+  for (pool = &mainpool; pool; pool = pool->next)
+    if (pool->okay && ptr_into_pool_p (pool, p))
+      return 1;
+
+  return 0;
 }
 
 
@@ -734,23 +810,33 @@ _gcry_private_is_secure (const void *p)
 void
 _gcry_secmem_term ()
 {
-  pooldesc_t *pool;
+  pooldesc_t *pool, *next;
 
-  pool = &mainpool;
-  if (!pool->okay)
-    return;
-
-  wipememory2 (pool->mem, 0xff, pool->size);
-  wipememory2 (pool->mem, 0xaa, pool->size);
-  wipememory2 (pool->mem, 0x55, pool->size);
-  wipememory2 (pool->mem, 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->mem, pool->size);
+      else if (pool->is_mmapped)
+        munmap (pool->mem, pool->size);
 #endif
-  pool->mem = 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;
 }
 
@@ -762,28 +848,31 @@ _gcry_secmem_dump_stats (int extended)
 {
   pooldesc_t *pool;
   memblock_t *mb;
-  int i;
+  int i, poolno;
 
   SECMEM_LOCK;
 
-  pool = &mainpool;
-  if (!extended)
+  for (pool = &mainpool, poolno = 0; pool; pool = pool->next, poolno++)
     {
-      if (pool->okay)
-        log_info ("secmem usage: %u/%lu bytes in %u blocks\n",
-                  cur_alloced, (unsigned long)pool->size, cur_blocks);
+      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);
+        }
     }
-  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 %p %s block %i size %i\n",
-                  pool,
-                  (mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
-                  i,
-                  mb->size);
-      }
-
   SECMEM_UNLOCK;
 }
diff --git a/src/secmem.h b/src/secmem.h
index c69fe88..29dd64f 100644
--- a/src/secmem.h
+++ b/src/secmem.h
@@ -25,7 +25,7 @@ void _gcry_secmem_init (size_t npool);
 void _gcry_secmem_term (void);
 void *_gcry_secmem_malloc (size_t size, int xhint) _GCRY_GCC_ATTR_MALLOC;
 void *_gcry_secmem_realloc (void *a, size_t newsize, int xhint);
-void _gcry_secmem_free (void *a);
+int  _gcry_secmem_free (void *a);
 void _gcry_secmem_dump_stats (int extended);
 void _gcry_secmem_set_flags (unsigned flags);
 unsigned _gcry_secmem_get_flags(void);
diff --git a/src/stdmem.c b/src/stdmem.c
index cf937ff..cbda8d8 100644
--- a/src/stdmem.c
+++ b/src/stdmem.c
@@ -230,15 +230,13 @@ _gcry_private_free (void *a)
   if (use_m_guard )
     {
       _gcry_private_check_heap(p);
-      if ( _gcry_private_is_secure(a) )
-        _gcry_secmem_free(p-EXTRA_ALIGN-4);
-      else
+      if (! _gcry_secmem_free (p - EXTRA_ALIGN - 4))
         {
-          free(p-EXTRA_ALIGN-4);
+          free (p - EXTRA_ALIGN - 4);
 	}
     }
-  else if ( _gcry_private_is_secure(a) )
-    _gcry_secmem_free(p);
-  else
-    free(p);
+  else if (!_gcry_secmem_free (p))
+    {
+      free(p);
+    }
 }

commit b7df907dca4d525f8930c533b763ffce44ceed87
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Dec 7 10:37:50 2016 +0100

    Give the secmem allocators a hint when a xmalloc calls them.
    
    * src/secmem.c (_gcry_secmem_malloc): New not yet used arg XHINT.
    (_gcry_secmem_realloc): Ditto.
    * src/stdmem.c (_gcry_private_malloc_secure): New arg XHINT to be
    passed to the secmem functions.
    (_gcry_private_realloc): Ditto.
    * src/g10lib.h (GCRY_ALLOC_FLAG_XHINT): New.
    * src/global.c (do_malloc): Pass this flag as XHINT to the private
    allocator.
    (_gcry_malloc_secure): Factor code out to ...
    (_gcry_malloc_secure_core): this.  Add arg XHINT.
    (_gcry_realloc): Factor code out to ...
    (_gcry_realloc_core): here.  Add arg XHINT.
    (_gcry_strdup): Factor code out to ...
    (_gcry_strdup_core): here.  Add arg XHINT.
    (_gcry_xrealloc): Use the core function and pass true for XHINT.
    (_gcry_xmalloc_secure): Ditto.
    (_gcry_xstrdup): Ditto.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/g10lib.h b/src/g10lib.h
index d4e3fef..f0a4628 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -392,6 +392,7 @@ gcry_err_code_t _gcry_mpi_init (void);
 
 /* Memory management.  */
 #define GCRY_ALLOC_FLAG_SECURE (1 << 0)
+#define GCRY_ALLOC_FLAG_XHINT  (1 << 1)  /* Called from xmalloc.  */
 
 
 /*-- sexp.c --*/
diff --git a/src/global.c b/src/global.c
index be112b7..cfb7618 100644
--- a/src/global.c
+++ b/src/global.c
@@ -787,7 +787,7 @@ do_malloc (size_t n, unsigned int flags, void **mem)
       if (alloc_secure_func)
 	m = (*alloc_secure_func) (n);
       else
-	m = _gcry_private_malloc_secure (n);
+	m = _gcry_private_malloc_secure (n, !!(flags & GCRY_ALLOC_FLAG_XHINT));
     }
   else
     {
@@ -821,16 +821,23 @@ _gcry_malloc (size_t n)
   return mem;
 }
 
-void *
-_gcry_malloc_secure (size_t n)
+static void *
+_gcry_malloc_secure_core (size_t n, int xhint)
 {
   void *mem = NULL;
 
-  do_malloc (n, GCRY_ALLOC_FLAG_SECURE, &mem);
+  do_malloc (n, (GCRY_ALLOC_FLAG_SECURE | (xhint? GCRY_ALLOC_FLAG_XHINT:0)),
+             &mem);
 
   return mem;
 }
 
+void *
+_gcry_malloc_secure (size_t n)
+{
+  return _gcry_malloc_secure_core (n, 0);
+}
+
 int
 _gcry_is_secure (const void *a)
 {
@@ -855,8 +862,8 @@ _gcry_check_heap( const void *a )
 #endif
 }
 
-void *
-_gcry_realloc (void *a, size_t n)
+static void *
+_gcry_realloc_core (void *a, size_t n, int xhint)
 {
   void *p;
 
@@ -873,12 +880,20 @@ _gcry_realloc (void *a, size_t n)
   if (realloc_func)
     p = realloc_func (a, n);
   else
-    p =  _gcry_private_realloc (a, n);
+    p =  _gcry_private_realloc (a, n, xhint);
   if (!p && !errno)
     gpg_err_set_errno (ENOMEM);
   return p;
 }
 
+
+void *
+_gcry_realloc (void *a, size_t n)
+{
+  return _gcry_realloc_core (a, n, 0);
+}
+
+
 void
 _gcry_free (void *p)
 {
@@ -941,12 +956,8 @@ _gcry_calloc_secure (size_t n, size_t m)
 }
 
 
-/* Create and return a copy of the null-terminated string STRING.  If
-   it is contained in secure memory, the copy will be contained in
-   secure memory as well.  In an out-of-memory condition, NULL is
-   returned.  */
-char *
-_gcry_strdup (const char *string)
+static char *
+_gcry_strdup_core (const char *string, int xhint)
 {
   char *string_cp = NULL;
   size_t string_n = 0;
@@ -954,7 +965,7 @@ _gcry_strdup (const char *string)
   string_n = strlen (string);
 
   if (_gcry_is_secure (string))
-    string_cp = _gcry_malloc_secure (string_n + 1);
+    string_cp = _gcry_malloc_secure_core (string_n + 1, xhint);
   else
     string_cp = _gcry_malloc (string_n + 1);
 
@@ -964,6 +975,15 @@ _gcry_strdup (const char *string)
   return string_cp;
 }
 
+/* Create and return a copy of the null-terminated string STRING.  If
+ * it is contained in secure memory, the copy will be contained in
+ * secure memory as well.  In an out-of-memory condition, NULL is
+ * returned.  */
+char *
+_gcry_strdup (const char *string)
+{
+  return _gcry_strdup_core (string, 0);
+}
 
 void *
 _gcry_xmalloc( size_t n )
@@ -987,7 +1007,7 @@ _gcry_xrealloc( void *a, size_t n )
 {
   void *p;
 
-  while ( !(p = _gcry_realloc( a, n )) )
+  while (!(p = _gcry_realloc_core (a, n, 1)))
     {
       if ( fips_mode ()
            || !outofcore_handler
@@ -1005,7 +1025,7 @@ _gcry_xmalloc_secure( size_t n )
 {
   void *p;
 
-  while ( !(p = _gcry_malloc_secure( n )) )
+  while (!(p = _gcry_malloc_secure_core (n, 1)))
     {
       if ( fips_mode ()
            || !outofcore_handler
@@ -1060,7 +1080,7 @@ _gcry_xstrdup (const char *string)
 {
   char *p;
 
-  while ( !(p = _gcry_strdup (string)) )
+  while ( !(p = _gcry_strdup_core (string, 1)) )
     {
       size_t n = strlen (string);
       int is_sec = !!_gcry_is_secure (string);
diff --git a/src/secmem.c b/src/secmem.c
index 54bbda1..928e03f 100644
--- a/src/secmem.c
+++ b/src/secmem.c
@@ -608,8 +608,11 @@ _gcry_secmem_malloc_internal (size_t size)
   return mb ? &mb->aligned.c : 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;
 
@@ -694,9 +697,10 @@ _gcry_secmem_realloc_internal (void *p, size_t newsize)
 }
 
 
-/* Realloc memory.  */
+/* Realloc memory.  With XHINT set assume that the caller is a xmalloc
+ * style function.  */
 void *
-_gcry_secmem_realloc (void *p, size_t newsize)
+_gcry_secmem_realloc (void *p, size_t newsize, int xhint)
 {
   void *a;
 
diff --git a/src/secmem.h b/src/secmem.h
index 764bfeb..c69fe88 100644
--- a/src/secmem.h
+++ b/src/secmem.h
@@ -23,8 +23,8 @@
 
 void _gcry_secmem_init (size_t npool);
 void _gcry_secmem_term (void);
-void *_gcry_secmem_malloc (size_t size) _GCRY_GCC_ATTR_MALLOC;
-void *_gcry_secmem_realloc (void *a, size_t newsize);
+void *_gcry_secmem_malloc (size_t size, int xhint) _GCRY_GCC_ATTR_MALLOC;
+void *_gcry_secmem_realloc (void *a, size_t newsize, int xhint);
 void _gcry_secmem_free (void *a);
 void _gcry_secmem_dump_stats (int extended);
 void _gcry_secmem_set_flags (unsigned flags);
diff --git a/src/stdmem.c b/src/stdmem.c
index 189da37..cf937ff 100644
--- a/src/stdmem.c
+++ b/src/stdmem.c
@@ -117,10 +117,11 @@ _gcry_private_malloc (size_t n)
 
 /*
  * Allocate memory of size N from the secure memory pool.  Return NULL
- * if we are out of memory.
+ * if we are out of memory.  XHINT tells the allocator that the caller
+ * used an xmalloc style call.
  */
 void *
-_gcry_private_malloc_secure (size_t n)
+_gcry_private_malloc_secure (size_t n, int xhint)
 {
   if (!n)
     {
@@ -133,7 +134,7 @@ _gcry_private_malloc_secure (size_t n)
     {
       char *p;
 
-      if ( !(p = _gcry_secmem_malloc (n +EXTRA_ALIGN+ 5)) )
+      if (!(p = _gcry_secmem_malloc (n + EXTRA_ALIGN + 5, xhint)))
         return NULL;
       ((byte*)p)[EXTRA_ALIGN+0] = n;
       ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ;
@@ -144,17 +145,18 @@ _gcry_private_malloc_secure (size_t n)
     }
   else
     {
-      return _gcry_secmem_malloc( n );
+      return _gcry_secmem_malloc (n, xhint);
     }
 }
 
 
 /*
- * Realloc and clear the old space
- * Return NULL if there is not enough memory.
+ * Realloc and clear the old space.  XHINT tells the allocator that
+ * the caller used an xmalloc style call.  Returns NULL if there is
+ * not enough memory.
  */
 void *
-_gcry_private_realloc ( void *a, size_t n )
+_gcry_private_realloc (void *a, size_t n, int xhint)
 {
   if (use_m_guard)
     {
@@ -172,7 +174,7 @@ _gcry_private_realloc ( void *a, size_t n )
       if( len >= n ) /* We don't shrink for now. */
         return a;
       if (p[-1] == MAGIC_SEC_BYTE)
-        b = _gcry_private_malloc_secure(n);
+        b = _gcry_private_malloc_secure (n, xhint);
       else
         b = _gcry_private_malloc(n);
       if (!b)
@@ -184,7 +186,7 @@ _gcry_private_realloc ( void *a, size_t n )
     }
   else if ( _gcry_private_is_secure(a) )
     {
-      return _gcry_secmem_realloc( a, n );
+      return _gcry_secmem_realloc (a, n, xhint);
     }
   else
     {
diff --git a/src/stdmem.h b/src/stdmem.h
index b476e7e..c52aab5 100644
--- a/src/stdmem.h
+++ b/src/stdmem.h
@@ -24,8 +24,8 @@
 void _gcry_private_enable_m_guard(void);
 
 void *_gcry_private_malloc (size_t n) _GCRY_GCC_ATTR_MALLOC;
-void *_gcry_private_malloc_secure (size_t n) _GCRY_GCC_ATTR_MALLOC;
-void *_gcry_private_realloc (void *a, size_t n);
+void *_gcry_private_malloc_secure (size_t n, int xhint) _GCRY_GCC_ATTR_MALLOC;
+void *_gcry_private_realloc (void *a, size_t n, int xhint);
 void _gcry_private_check_heap (const void *a);
 void _gcry_private_free (void *a);
 

commit e366c19b34922c770af82cd035fd815680b29dee
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Dec 7 10:01:39 2016 +0100

    tests: New test t-secmem.
    
    * src/secmem.c (_gcry_secmem_dump_stats): Add arg EXTENDED and adjust
    caller.
    * src/gcrypt-testapi.h (PRIV_CTL_DUMP_SECMEM_STATS): New.
    * src/global.c (_gcry_vcontrol): Implement that.
    * tests/t-secmem.c: New.
    * tests/Makefile.am (tests_bin): Add that test.
    --
    
    This test does not much right now.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/gcrypt-testapi.h b/src/gcrypt-testapi.h
index 23d3800..0417754 100644
--- a/src/gcrypt-testapi.h
+++ b/src/gcrypt-testapi.h
@@ -31,6 +31,7 @@
 #define PRIV_CTL_RUN_EXTRNG_TEST    59
 #define PRIV_CTL_DEINIT_EXTRNG_TEST 60
 #define PRIV_CTL_EXTERNAL_LOCK_TEST 61
+#define PRIV_CTL_DUMP_SECMEM_STATS  62
 
 #define EXTERNAL_LOCK_TEST_INIT       30111
 #define EXTERNAL_LOCK_TEST_LOCK       30112
diff --git a/src/global.c b/src/global.c
index 8e54efe..be112b7 100644
--- a/src/global.c
+++ b/src/global.c
@@ -380,7 +380,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       break;
 
     case GCRYCTL_DUMP_SECMEM_STATS:
-      _gcry_secmem_dump_stats ();
+      _gcry_secmem_dump_stats (0);
       break;
 
     case GCRYCTL_DROP_PRIVS:
@@ -613,7 +613,8 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
     case PRIV_CTL_EXTERNAL_LOCK_TEST:  /* Run external lock test */
       rc = external_lock_test (va_arg (arg_ptr, int));
       break;
-    case 62:  /* RFU */
+    case PRIV_CTL_DUMP_SECMEM_STATS:
+      _gcry_secmem_dump_stats (1);
       break;
 #if _GCRY_GCC_VERSION >= 40600
 # pragma GCC diagnostic pop
diff --git a/src/secmem.c b/src/secmem.c
index 1f92f17..54bbda1 100644
--- a/src/secmem.c
+++ b/src/secmem.c
@@ -751,33 +751,35 @@ _gcry_secmem_term ()
 }
 
 
+/* 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)
 {
   pooldesc_t *pool;
-
-#if 1
-  SECMEM_LOCK;
-
-  pool = &mainpool;
-  if (pool->okay)
-    log_info ("secmem usage: %u/%lu bytes in %u blocks\n",
-	      cur_alloced, (unsigned long)pool->size, cur_blocks);
-  SECMEM_UNLOCK;
-#else
   memblock_t *mb;
   int i;
 
   SECMEM_LOCK;
 
   pool = &mainpool;
-  for (i = 0, mb = (memblock_t *) pool->mem;
-       ptr_into_pool_p (pool, mb);
-       mb = mb_get_next (pool, mb), i++)
-    log_info ("SECMEM: [%s] block: %i; size: %i\n",
-	      (mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
-	      i,
-	      mb->size);
+  if (!extended)
+    {
+      if (pool->okay)
+        log_info ("secmem usage: %u/%lu bytes in %u blocks\n",
+                  cur_alloced, (unsigned long)pool->size, 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 %p %s block %i size %i\n",
+                  pool,
+                  (mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
+                  i,
+                  mb->size);
+      }
+
   SECMEM_UNLOCK;
-#endif
 }
diff --git a/src/secmem.h b/src/secmem.h
index 3577381..764bfeb 100644
--- a/src/secmem.h
+++ b/src/secmem.h
@@ -26,7 +26,7 @@ void _gcry_secmem_term (void);
 void *_gcry_secmem_malloc (size_t size) _GCRY_GCC_ATTR_MALLOC;
 void *_gcry_secmem_realloc (void *a, size_t newsize);
 void _gcry_secmem_free (void *a);
-void _gcry_secmem_dump_stats (void);
+void _gcry_secmem_dump_stats (int extended);
 void _gcry_secmem_set_flags (unsigned flags);
 unsigned _gcry_secmem_get_flags(void);
 int _gcry_private_is_secure (const void *p);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d462f30..374e72e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -19,7 +19,7 @@
 ## Process this file with automake to produce Makefile.in
 
 tests_bin = \
-        version mpitests t-sexp t-convert \
+        version t-secmem mpitests t-sexp t-convert \
 	t-mpi-bit t-mpi-point curves t-lock \
 	prime basic keygen pubkey hmac hashtest t-kdf keygrip \
 	fips186-dsa aeswrap pkcs1v2 random dsa-rfc6979 t-ed25519 t-cv25519
diff --git a/tests/t-secmem.c b/tests/t-secmem.c
new file mode 100644
index 0000000..b464d02
--- /dev/null
+++ b/tests/t-secmem.c
@@ -0,0 +1,141 @@
+/* t-secmem.c - Test the secmem memory allocator
+ * Copyright (C) 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
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define PGMNAME "t-secmem"
+
+#include "t-common.h"
+#include "../src/gcrypt-testapi.h"
+
+
+static void
+test_secmem (void)
+{
+  void *a[28];
+  void *b;
+  int i;
+
+  memset (a, 0, sizeof a);
+
+  /* Allocating 28*512=14k should work in the default 16k pool even
+   * with extrem alignment requirements.  */
+  for (i=0; i < DIM(a); i++)
+    a[i] = gcry_xmalloc_secure (512);
+
+  /* Allocating another 2k should fail for the default 16k pool.  */
+  b = gcry_malloc_secure (2048);
+  if (b)
+    fail ("allocation did not fail as expected\n");
+
+  for (i=0; i < DIM(a); i++)
+    xfree (a[i]);
+  xfree (b);
+}
+
+
+/* This function is called when we ran out of core and there is no way
+ * to return that error to the caller (xmalloc or mpi allocation).  */
+static int
+outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
+{
+  static int been_here;  /* Used to protect against recursive calls. */
+
+  (void)opaque;
+
+  /* Protect against a second call.  */
+  if (been_here)
+    return 0; /* Let libgcrypt call its own fatal error handler.  */
+  been_here = 1;
+
+  info ("outofcore handler invoked");
+  gcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
+  fail ("out of core%s while allocating %lu bytes",
+       (flags & 1)?" in secure memory":"", (unsigned long)req_n);
+
+  die ("stopped");
+  /*NOTREACHED*/
+  return 0;
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+
+  if (argc)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: " PGMNAME " [options]\n"
+                 "Options:\n"
+                 "  --verbose       print timings etc.\n"
+                 "  --debug         flyswatter\n"
+                 , stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        die ("unknown option '%s'", *argv);
+    }
+
+  if (!gcry_check_version (GCRYPT_VERSION))
+    die ("version mismatch; pgm=%s, library=%s\n",
+         GCRYPT_VERSION, gcry_check_version (NULL));
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+  gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+  gcry_set_outofcore_handler (outofcore_handler, NULL);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+  test_secmem ();
+
+  if (verbose)
+    gcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
+  info ("All tests completed.  Errors: %d\n", errorcount);
+  return !!errorcount;
+}

-----------------------------------------------------------------------

Summary of changes:
 doc/gcrypt.texi      |  12 ++-
 src/g10lib.h         |   1 +
 src/gcrypt-testapi.h |   1 +
 src/global.c         |  59 ++++++++-----
 src/secmem.c         | 227 ++++++++++++++++++++++++++++++++++++---------------
 src/secmem.h         |   8 +-
 src/stdmem.c         |  34 ++++----
 src/stdmem.h         |   4 +-
 tests/Makefile.am    |   2 +-
 tests/t-secmem.c     | 180 ++++++++++++++++++++++++++++++++++++++++
 10 files changed, 416 insertions(+), 112 deletions(-)
 create mode 100644 tests/t-secmem.c


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
Gnupg-commits at gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits




More information about the Gcrypt-devel mailing list