[git] GCRYPT - branch, LIBGCRYPT-1-7-BRANCH, updated. libgcrypt-1.7.3-23-g1f1ab84

by Werner Koch cvs at cvs.gnupg.org
Wed Dec 7 17:33:16 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, LIBGCRYPT-1-7-BRANCH has been updated
       via  1f1ab84fd1dea3fee596d3223fe96b154b37aa6f (commit)
       via  73dca02b9cc6d542af153c527190832f9c421ef3 (commit)
       via  1433fce11c90bb44ada51071f342ad67b469ea81 (commit)
       via  2bc361485d8bc0d8cdb3b4ae6e304885eeaab889 (commit)
      from  a8b2d8b502d9cbc9157c261f12e4623ec20b3960 (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 1f1ab84fd1dea3fee596d3223fe96b154b37aa6f
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Dec 7 17:01:19 2016 +0100

    doc: Document the overflow pools.
    
    --

diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index c2c39ad..5b5fce2 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

commit 73dca02b9cc6d542af153c527190832f9c421ef3
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>
    
    (cherry picked from b6870cf25c0b1eb9c127a94af8326c446421a472)
    
    Resolved conflicts:
    * src/secmem.c (_gcry_secmem_dump_stats): Add arg extended.
    * src/secmem.h: Adjust prototype.
    * src/global.c (_gcry_vcontrol): Call _gcry_secmem_dump_stats with
    parm 0.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/global.c b/src/global.c
index f12f7d7..4283460 100644
--- a/src/global.c
+++ b/src/global.c
@@ -367,7 +367,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:
diff --git a/src/secmem.c b/src/secmem.c
index e838162..9f228f0 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;
+    }
 
-  return mb ? &mb->aligned.c : NULL;
+  /* 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 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,54 +810,68 @@ _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;
 }
 
 
 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;
+  int i, poolno;
 
   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);
+  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);
+        }
+    }
+
   SECMEM_UNLOCK;
-#endif
 }
diff --git a/src/secmem.h b/src/secmem.h
index 1c39f2a..29dd64f 100644
--- a/src/secmem.h
+++ b/src/secmem.h
@@ -25,8 +25,8 @@ 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);
-void _gcry_secmem_dump_stats (void);
+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);
 int _gcry_private_is_secure (const void *p);
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 1433fce11c90bb44ada51071f342ad67b469ea81
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 444c868..376b0bf 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -390,6 +390,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 8669a46..f12f7d7 100644
--- a/src/global.c
+++ b/src/global.c
@@ -768,7 +768,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
     {
@@ -802,16 +802,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)
 {
@@ -836,8 +843,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;
 
@@ -854,12 +861,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)
 {
@@ -922,12 +937,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;
@@ -935,7 +946,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);
 
@@ -945,6 +956,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 )
@@ -968,7 +988,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
@@ -986,7 +1006,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
@@ -1041,7 +1061,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 1f92f17..e838162 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 3577381..1c39f2a 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 (void);
 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 2bc361485d8bc0d8cdb3b4ae6e304885eeaab889
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Dec 6 21:20:54 2016 +0100

    Reorganize code in secmem.c.
    
    * src/secmem.c (pooldesc_t): New type to collect information about one
    pool.
    (pool_size): Remove.  Now a member of pooldesc_t.
    (pool_okay): Ditto.
    (pool_is_mmapped): Ditto.
    (pool): Rename variable ...
    (mainpool): And change type to pooldesc_t.
    (ptr_into_pool_p): Add arg 'pool'.
    (mb_get_next): Ditto.
    (mb_get_prev): Ditto.
    (mb_merge): Ditto.
    (mb_get_new): Ditto.
    (init_pool): Ditto.
    (lock_pool): Rename to ...
    (look_pool_pages: this.
    (secmem_init): Rename to ...
    (_gcry_secmem_init_internal): this.  Add local var POOL and init with
    address of MAINPOOL.
    (_gcry_secmem_malloc_internal): Add local var POOL and init with
    address of MAINPOOL.
    (_gcry_private_is_secure): Ditto.
    (_gcry_secmem_term): Ditto.
    (_gcry_secmem_dump_stats): Ditto.
    (_gcry_secmem_free_internal): Ditto.  Remove check for NULL arg.
    (_gcry_secmem_free): Add check for NULL arg before taking the lock.
    (_gcry_secmem_realloc): Factor most code out to ...
    (_gcry_secmem_realloc_internal): this.
    --
    
    This change prepares future work to allow the use of several pools.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/secmem.c b/src/secmem.c
index c4e8414..1f92f17 100644
--- a/src/secmem.c
+++ b/src/secmem.c
@@ -1,7 +1,7 @@
 /* secmem.c  -	memory allocation from a secure heap
  * Copyright (C) 1998, 1999, 2000, 2001, 2002,
  *               2003, 2007 Free Software Foundation, Inc.
- * Copyright (C) 2013 g10 Code GmbH
+ * Copyright (C) 2013, 2016 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -59,20 +59,30 @@ 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 memory buffer used as allocation pool.  */
+  void *mem;
+
+  /* The allocated size of MEM. */
+  size_t size;
+
+  /* Flag indicating that this memory pool is ready for use.  May be
+   * checked in an atexit function.  */
+  volatile int okay;
 
-/* Size of POOL in bytes.  */
-static size_t pool_size;
+  /* Flag indicating whether MEM is mmapped.  */
+  volatile int is_mmapped;
 
-/* True, if the memory pool is ready for use.  May be checked in an
-   atexit function.  */
-static volatile int pool_okay;
+} pooldesc_t;
 
-/* True, if the memory pool is mmapped.  */
-static volatile int pool_is_mmapped;
 
-/* FIXME?  */
+/* The pool of secure memory.  */
+static pooldesc_t mainpool;
+
+
+/* A couple of flags whith some beeing set early. */
 static int disable_secmem;
 static int show_warning;
 static int not_locked;
@@ -84,7 +94,7 @@ static int no_priv_drop;
 /* Stats.  */
 static unsigned int cur_alloced, cur_blocks;
 
-/* Lock protecting accesses to the memory pool.  */
+/* Lock protecting accesses to the memory pools.  */
 GPGRT_LOCK_DEFINE (secmem_lock);
 
 /* Convenient macros.  */
@@ -100,18 +110,18 @@ GPGRT_LOCK_DEFINE (secmem_lock);
 #define ADDR_TO_BLOCK(addr) \
   (memblock_t *) (void *) ((char *) addr - BLOCK_HEAD_SIZE)
 
-/* Check whether P points into the pool.  */
+/* Check whether P points into POOL.  */
 static int
-ptr_into_pool_p (const void *p)
+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.  See also
      http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
   */
   uintptr_t p_addr    = (uintptr_t)p;
-  uintptr_t pool_addr = (uintptr_t)pool;
+  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.  */
@@ -132,13 +142,13 @@ stats_update (size_t add, size_t sub)
 
 /* 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 *) (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;
@@ -147,18 +157,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
@@ -172,12 +182,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)))
     {
@@ -190,11 +200,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.  */
@@ -211,14 +221,14 @@ mb_get_new (memblock_t *block, size_t size)
 
 	    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;
@@ -235,9 +245,11 @@ 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;
@@ -367,11 +379,11 @@ lock_pool (void *p, size_t n)
 
 /* Initialize POOL.  */
 static void
-init_pool (size_t n)
+init_pool (pooldesc_t *pool, size_t n)
 {
   memblock_t *mb;
 
-  pool_size = n;
+  pool->size = n;
 
   if (disable_secmem)
     log_bug ("secure memory is disabled");
@@ -391,10 +403,10 @@ init_pool (size_t n)
 # endif
     pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val:DEFAULT_PAGE_SIZE;
 
-    pool_size = (pool_size + pgsize - 1) & ~(pgsize - 1);
+    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);
+    pool->mem = mmap (0, pool->size, PROT_READ | PROT_WRITE,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 # else /* map /dev/zero instead */
     {
       int fd;
@@ -403,40 +415,40 @@ init_pool (size_t n)
       if (fd == -1)
         {
           log_error ("can't open /dev/zero: %s\n", strerror (errno));
-          pool = (void *) -1;
+          pool->mem = (void *) -1;
         }
       else
         {
-          pool = mmap (0, pool_size,
-                       (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
+          pool->mem = mmap (0, pool->size,
+                           (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
           close (fd);
         }
     }
 # endif
-    if (pool == (void *) -1)
+    if (pool->mem == (void *) -1)
       log_info ("can't mmap pool of %u bytes: %s - using malloc\n",
-                (unsigned) pool_size, strerror (errno));
+                (unsigned) pool->size, strerror (errno));
     else
       {
-        pool_is_mmapped = 1;
-        pool_okay = 1;
+        pool->is_mmapped = 1;
+        pool->okay = 1;
       }
   }
 #endif /*HAVE_MMAP*/
 
-  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;
   mb->flags = 0;
 }
 
@@ -482,11 +494,14 @@ _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.  Itis
+ * 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
@@ -516,10 +531,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");
@@ -537,7 +552,7 @@ _gcry_secmem_init (size_t n)
 {
   SECMEM_LOCK;
 
-  secmem_init (n);
+  _gcry_secmem_init_internal (n);
 
   SECMEM_UNLOCK;
 }
@@ -554,13 +569,16 @@ _gcry_secmem_module_init ()
 static void *
 _gcry_secmem_malloc_internal (size_t size)
 {
+  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"));
@@ -583,7 +601,7 @@ _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);
 
@@ -605,11 +623,11 @@ _gcry_secmem_malloc (size_t size)
 static void
 _gcry_secmem_free_internal (void *a)
 {
+  pooldesc_t *pool;
   memblock_t *mb;
   int size;
 
-  if (!a)
-    return;
+  pool = &mainpool;
 
   mb = ADDR_TO_BLOCK (a);
   size = mb->size;
@@ -624,34 +642,35 @@ _gcry_secmem_free_internal (void *a)
   MB_WIPE_OUT (0x55);
   MB_WIPE_OUT (0x00);
 
+  /* Update stats.  */
   stats_update (0, size);
 
   mb->flags &= ~MB_FLAG_ACTIVE;
 
-  /* Update stats.  */
 
-  mb_merge (mb);
+  mb_merge (pool, mb);
 }
 
 /* Wipe out and release memory.  */
 void
 _gcry_secmem_free (void *a)
 {
+  if (!a)
+    return;
+
   SECMEM_LOCK;
   _gcry_secmem_free_internal (a);
   SECMEM_UNLOCK;
 }
 
-/* Realloc memory.  */
-void *
-_gcry_secmem_realloc (void *p, size_t newsize)
+
+static void *
+_gcry_secmem_realloc_internal (void *p, size_t newsize)
 {
   memblock_t *mb;
   size_t size;
   void *a;
 
-  SECMEM_LOCK;
-
   mb = (memblock_t *) (void *) ((char *) p
 				- ((size_t) &((memblock_t *) 0)->aligned.c));
   size = mb->size;
@@ -671,6 +690,18 @@ _gcry_secmem_realloc (void *p, size_t newsize)
 	}
     }
 
+  return a;
+}
+
+
+/* Realloc memory.  */
+void *
+_gcry_secmem_realloc (void *p, size_t newsize)
+{
+  void *a;
+
+  SECMEM_LOCK;
+  a = _gcry_secmem_realloc_internal (p, newsize);
   SECMEM_UNLOCK;
 
   return a;
@@ -681,7 +712,10 @@ _gcry_secmem_realloc (void *p, size_t newsize)
 int
 _gcry_private_is_secure (const void *p)
 {
-  return pool_okay && ptr_into_pool_p (p);
+  pooldesc_t *pool;
+
+  pool = &mainpool;
+  return pool->okay && ptr_into_pool_p (pool, p);
 }
 
 
@@ -696,20 +730,23 @@ _gcry_private_is_secure (const void *p)
 void
 _gcry_secmem_term ()
 {
-  if (!pool_okay)
+  pooldesc_t *pool;
+
+  pool = &mainpool;
+  if (!pool->okay)
     return;
 
-  wipememory2 (pool, 0xff, pool_size);
-  wipememory2 (pool, 0xaa, pool_size);
-  wipememory2 (pool, 0x55, pool_size);
-  wipememory2 (pool, 0x00, pool_size);
+  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 HAVE_MMAP
-  if (pool_is_mmapped)
-    munmap (pool, pool_size);
+  if (pool->is_mmapped)
+    munmap (pool->mem, pool->size);
 #endif
-  pool = NULL;
-  pool_okay = 0;
-  pool_size = 0;
+  pool->mem = NULL;
+  pool->okay = 0;
+  pool->size = 0;
   not_locked = 0;
 }
 
@@ -717,12 +754,15 @@ _gcry_secmem_term ()
 void
 _gcry_secmem_dump_stats ()
 {
+  pooldesc_t *pool;
+
 #if 1
   SECMEM_LOCK;
 
- if (pool_okay)
+  pool = &mainpool;
+  if (pool->okay)
     log_info ("secmem usage: %u/%lu bytes in %u blocks\n",
-	      cur_alloced, (unsigned long)pool_size, cur_blocks);
+	      cur_alloced, (unsigned long)pool->size, cur_blocks);
   SECMEM_UNLOCK;
 #else
   memblock_t *mb;
@@ -730,9 +770,10 @@ _gcry_secmem_dump_stats ()
 
   SECMEM_LOCK;
 
-  for (i = 0, mb = (memblock_t *) pool;
-       ptr_into_pool_p (mb);
-       mb = mb_get_next (mb), i++)
+  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,

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

Summary of changes:
 doc/gcrypt.texi |  12 +-
 src/g10lib.h    |   1 +
 src/global.c    |  56 ++++++---
 src/secmem.c    | 377 ++++++++++++++++++++++++++++++++++++++------------------
 src/secmem.h    |   8 +-
 src/stdmem.c    |  34 ++---
 src/stdmem.h    |   4 +-
 7 files changed, 327 insertions(+), 165 deletions(-)


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




More information about the Gnupg-commits mailing list