From 59f6972134f312863dc761bf66a954a8036d0d86 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 16 Jul 2017 16:22:33 -0700 Subject: [PATCH] Use explicit_bzero to clear GnuTLS keys * admin/merge-gnulib (GNULIB_MODULES): Add explicit_bzero. * lib/explicit_bzero.c, m4/explicit_bzero.m4: New files. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * src/gnutls.c (clear_storage): New function. (gnutls_symmetric_aead): Use it instead of memset. --- admin/merge-gnulib | 2 +- lib/explicit_bzero.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ lib/gnulib.mk.in | 13 +++++++++++- m4/explicit_bzero.m4 | 22 ++++++++++++++++++++ m4/gnulib-comp.m4 | 9 +++++++++ src/gnutls.c | 20 ++++++++++++++++-- 6 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 lib/explicit_bzero.c create mode 100644 m4/explicit_bzero.m4 diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 85921ba1ba6..2b1a16a10ec 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -30,7 +30,7 @@ GNULIB_MODULES=' careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 - diffseq dtoastr dtotimespec dup2 environ execinfo faccessat + diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog diff --git a/lib/explicit_bzero.c b/lib/explicit_bzero.c new file mode 100644 index 00000000000..262c68f9cd6 --- /dev/null +++ b/lib/explicit_bzero.c @@ -0,0 +1,48 @@ +/* Erasure of sensitive data, generic implementation. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + The GNU C Library 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +/* An assembler implementation of explicit_bzero can be created as an + assembler alias of an optimized bzero implementation. + Architecture-specific implementations also need to define + __explicit_bzero_chk. */ + +#if !_LIBC +# include +#endif + +#include + +/* glibc-internal users use __explicit_bzero_chk, and explicit_bzero + redirects to that. */ +#undef explicit_bzero + +/* Set LEN bytes of S to 0. The compiler will not delete a call to + this function, even if S is dead after the call. */ +void +explicit_bzero (void *s, size_t len) +{ +#ifdef HAVE_EXPLICIT_MEMSET + explicit_memset (s, 0, len); +#else + memset (s, '\0', len); +# ifdef __GNUC__ + /* Compiler barrier. */ + asm volatile ("" ::: "memory"); +# endif +#endif +} diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index ae5ae87a521..e20487b10b4 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -21,7 +21,7 @@ # the same distribution terms as the rest of that program. # # Generated by gnulib-tool. -# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 diffseq dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strftime strtoimax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings +# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avoid=utime-h --gnu-make --makefile-name=gnulib.mk.in --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 diffseq dtoastr dtotimespec dup2 environ execinfo explicit_bzero faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strftime strtoimax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimens vla warnings MOSTLYCLEANFILES += core *.stackdump @@ -1358,6 +1358,17 @@ EXTRA_libgnu_a_SOURCES += execinfo.c endif ## end gnulib module execinfo +## begin gnulib module explicit_bzero +ifeq (,$(OMIT_GNULIB_MODULE_explicit_bzero)) + + +EXTRA_DIST += explicit_bzero.c + +EXTRA_libgnu_a_SOURCES += explicit_bzero.c + +endif +## end gnulib module explicit_bzero + ## begin gnulib module faccessat ifeq (,$(OMIT_GNULIB_MODULE_faccessat)) diff --git a/m4/explicit_bzero.m4 b/m4/explicit_bzero.m4 new file mode 100644 index 00000000000..f9dc678207a --- /dev/null +++ b/m4/explicit_bzero.m4 @@ -0,0 +1,22 @@ +dnl Copyright 2017 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_EXPLICIT_BZERO], +[ + AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS]) + + dnl Persuade glibc to declare explicit_bzero. + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_FUNCS_ONCE([explicit_bzero]) + if test $ac_cv_func_explicit_bzero = no; then + HAVE_EXPLICIT_BZERO=0 + fi +]) + +AC_DEFUN([gl_PREREQ_EXPLICIT_BZERO], +[ + AC_CHECK_FUNCS([explicit_memset]) +]) diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 107645df4fd..038d78aafea 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -72,6 +72,7 @@ AC_DEFUN([gl_EARLY], # Code from module errno: # Code from module euidaccess: # Code from module execinfo: + # Code from module explicit_bzero: # Code from module extensions: # Code from module extern-inline: # Code from module faccessat: @@ -210,6 +211,12 @@ AC_DEFUN([gl_INIT], gl_UNISTD_MODULE_INDICATOR([environ]) gl_HEADER_ERRNO_H gl_EXECINFO_H + gl_FUNC_EXPLICIT_BZERO + if test $HAVE_EXPLICIT_BZERO = 0; then + AC_LIBOBJ([explicit_bzero]) + gl_PREREQ_EXPLICIT_BZERO + fi + gl_STRING_MODULE_INDICATOR([explicit_bzero]) AC_REQUIRE([gl_EXTERN_INLINE]) gl_FUNC_FACCESSAT if test $HAVE_FACCESSAT = 0; then @@ -837,6 +844,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/euidaccess.c lib/execinfo.c lib/execinfo.in.h + lib/explicit_bzero.c lib/faccessat.c lib/fcntl.c lib/fcntl.in.h @@ -967,6 +975,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/errno_h.m4 m4/euidaccess.m4 m4/execinfo.m4 + m4/explicit_bzero.m4 m4/extensions.m4 m4/extern-inline.m4 m4/faccessat.m4 diff --git a/src/gnutls.c b/src/gnutls.c index e6f01a9cfe1..7d19f90fbb8 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -1883,6 +1883,22 @@ The alist key is the cipher name. */) return ciphers; } +/* Zero out STORAGE (even if it will become inaccessible. It has + STORAGE_LENGTH bytes. The goal is to improve security a bit, in + case an Emacs module or some buggy part of Emacs attempts to + inspect STORAGE later to retrieve a secret. + + Calls to this function document when storage containing a secret is + known to go out of scope. This function is not guaranteed to erase + the secret, as copies of STORAGE may well be accessible elsewhere + on the machine. */ + +static void +clear_storage (void *storage, ptrdiff_t storage_length) +{ + explicit_bzero (storage, storage_length); +} + static Lisp_Object gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, Lisp_Object cipher, @@ -1949,7 +1965,7 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, if (ret < GNUTLS_E_SUCCESS) { - memset (storage, 0, storage_length); + clear_storage (storage, storage_length); SAFE_FREE (); gnutls_aead_cipher_deinit (acipher); if (encrypting) @@ -1963,7 +1979,7 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, gnutls_aead_cipher_deinit (acipher); Lisp_Object output = make_unibyte_string (storage, storage_length); - memset (storage, 0, storage_length); + clear_storage (storage, storage_length); SAFE_FREE (); return list2 (output, actual_iv); #else -- 2.39.2