Use explicit_bzero for wipememory
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Tue, 13 Nov 2018 20:08:50 +0000 (22:08 +0200)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Tue, 20 Nov 2018 19:18:01 +0000 (21:18 +0200)
* configure.ac (AC_CHECK_FUNCS): Check for 'explicit_bzero'.
* src/g10lib.h (wipememory2): Use _gcry_fast_wipememory if _SET is
zero.
(_gcry_fast_wipememory): New.
(_gcry_wipememory2): Rename to...
(_gcry_fast_wipememory2): ...this.
* src/misc.c (_gcry_wipememory): New.
(_gcry_wipememory2): Rename to...
(_gcry_fast_wipememory2): ...this.
(_gcry_fast_wipememory2) [HAVE_EXPLICIT_BZERO]: Use explicit_bzero if
SET is zero.
(_gcry_burn_stack): Use _gcry_fast_wipememory.
--

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
configure.ac
src/g10lib.h
src/misc.c

index 9803d51..5843884 100644 (file)
@@ -1772,6 +1772,7 @@ AC_CHECK_FUNCS(strtoul memmove stricmp atexit raise)
 AC_CHECK_FUNCS(strerror rand mmap getpagesize sysconf waitpid wait4)
 AC_CHECK_FUNCS(gettimeofday getrusage gethrtime clock_gettime syslog)
 AC_CHECK_FUNCS(syscall fcntl ftruncate flockfile)
+AC_CHECK_FUNCS(explicit_bzero)
 
 GNUPG_CHECK_MLOCK
 
index 9b21478..694c2d8 100644 (file)
@@ -334,15 +334,16 @@ void __gcry_burn_stack (unsigned int bytes);
        do { __gcry_burn_stack (bytes); \
             __gcry_burn_stack_dummy (); } while(0)
 
-
 /* To avoid that a compiler optimizes certain memset calls away, these
    macros may be used instead.  For small constant length buffers,
    memory wiping is inlined.  For non-constant or large length buffers,
-   memory is wiped with memset through _gcry_wipememory. */
-void _gcry_wipememory2(void *ptr, int set, size_t len);
+   memory is wiped with memset through _gcry_fast_wipememory. */
 #define wipememory2(_ptr,_set,_len) do { \
              if (!CONSTANT_P(_len) || _len > 64) { \
-               _gcry_wipememory2((void *)_ptr, _set, _len); \
+               if (CONSTANT_P(_set) && (_set) == 0) \
+                 _gcry_fast_wipememory((void *)_ptr, _len); \
+               else \
+                 _gcry_fast_wipememory2((void *)_ptr, _set, _len); \
              } else {\
                volatile char *_vptr = (volatile char *)(_ptr); \
                size_t _vlen = (_len); \
@@ -353,6 +354,9 @@ void _gcry_wipememory2(void *ptr, int set, size_t len);
            } while(0)
 #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
 
+void _gcry_fast_wipememory(void *ptr, size_t len);
+void _gcry_fast_wipememory2(void *ptr, int set, size_t len);
+
 #if defined(HAVE_GCC_ATTRIBUTE_PACKED) && \
     defined(HAVE_GCC_ATTRIBUTE_ALIGNED) && \
     defined(HAVE_GCC_ATTRIBUTE_MAY_ALIAS)
index 420ce74..bb39e1c 100644 (file)
@@ -32,6 +32,8 @@
 
 static int verbosity_level = 0;
 
+/* Prevent compiler from optimizing away the call to memset by accessing
+   memset through volatile pointer. */
 static void *(*volatile memset_ptr)(void *, int, size_t) = (void *)memset;
 
 static void (*fatal_error_handler)(void*,int, const char*) = NULL;
@@ -500,8 +502,37 @@ _gcry_strtokenize (const char *string, const char *delim)
 
 
 void
-_gcry_wipememory2 (void *ptr, int set, size_t len)
+_gcry_fast_wipememory (void *ptr, size_t len)
 {
+  /* Note: This function is called from wipememory/wipememory2 only if LEN
+     is large or unknown at compile time. New wipe function alternatives
+     need to be checked before adding to this function. New implementations
+     need to be faster than wipememory/wipememory2 macros in 'misc.h'.
+
+     Following implementations were found to have suboptimal performance:
+
+     - [_WIN32/mingw32] SecureZeroMemory; Inline function, equivalent to
+       volatile byte buffer set: while(buflen--) (volatile char *)(buf++)=set;
+   */
+#ifdef HAVE_EXPLICIT_BZERO
+  explicit_bzero (ptr, len);
+#else
+  memset_ptr (ptr, 0, len);
+#endif
+}
+
+
+void
+_gcry_fast_wipememory2 (void *ptr, int set, size_t len)
+{
+#ifdef HAVE_EXPLICIT_BZERO
+  if (set == 0)
+    {
+      explicit_bzero (ptr, len);
+      return;
+    }
+#endif
+
   memset_ptr (ptr, set, len);
 }
 
@@ -514,11 +545,11 @@ __gcry_burn_stack (unsigned int bytes)
   unsigned int buflen = ((!bytes + bytes) + 63) & ~63;
   char buf[buflen];
 
-  memset_ptr (buf, 0, buflen);
+  _gcry_fast_wipememory (buf, buflen);
 #else
   volatile char buf[64];
 
-  wipememory (buf, sizeof buf);
+  _gcry_fast_wipememory (buf, sizeof buf);
 
   if (bytes > sizeof buf)
       _gcry_burn_stack (bytes - sizeof buf);