From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Eli Zaretskii Newsgroups: gmane.emacs.bugs Subject: bug#22202: 24.5; SECURITY ISSUE -- Emacs Server vulnerable to random number generator attack on Windows systems Date: Thu, 31 Dec 2015 16:14:00 +0200 Message-ID: <83io3ebt93.fsf@gnu.org> References: <83lh8ddy45.fsf@gnu.org> <8760zh81oo.fsf@isaac.fritz.box> <83mvssc4ix.fsf@gnu.org> <83r3i3bqpu.fsf@gnu.org> Reply-To: Eli Zaretskii NNTP-Posting-Host: plane.gmane.org X-Trace: ger.gmane.org 1451571263 1965 80.91.229.3 (31 Dec 2015 14:14:23 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 31 Dec 2015 14:14:23 +0000 (UTC) Cc: 22202@debbugs.gnu.org, demetriobenour@gmail.com, deng@randomsample.de To: Richard Copley Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Thu Dec 31 15:14:11 2015 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1aEdzX-0001fw-G4 for geb-bug-gnu-emacs@m.gmane.org; Thu, 31 Dec 2015 15:14:11 +0100 Original-Received: from localhost ([::1]:55913 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aEdzW-0002k8-Il for geb-bug-gnu-emacs@m.gmane.org; Thu, 31 Dec 2015 09:14:10 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:54030) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aEdzS-0002k0-Pw for bug-gnu-emacs@gnu.org; Thu, 31 Dec 2015 09:14:08 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aEdzO-0005YS-Mm for bug-gnu-emacs@gnu.org; Thu, 31 Dec 2015 09:14:06 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:43406) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aEdzO-0005YO-J5 for bug-gnu-emacs@gnu.org; Thu, 31 Dec 2015 09:14:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84) (envelope-from ) id 1aEdzO-0008Je-Fh for bug-gnu-emacs@gnu.org; Thu, 31 Dec 2015 09:14:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 31 Dec 2015 14:14:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 22202 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: security Original-Received: via spool by 22202-submit@debbugs.gnu.org id=B22202.145157121331915 (code B ref 22202); Thu, 31 Dec 2015 14:14:02 +0000 Original-Received: (at 22202) by debbugs.gnu.org; 31 Dec 2015 14:13:33 +0000 Original-Received: from localhost ([127.0.0.1]:51008 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84) (envelope-from ) id 1aEdyv-0008Ig-Dw for submit@debbugs.gnu.org; Thu, 31 Dec 2015 09:13:33 -0500 Original-Received: from eggs.gnu.org ([208.118.235.92]:34637) by debbugs.gnu.org with esmtp (Exim 4.84) (envelope-from ) id 1aEdyt-0008IT-Hl for 22202@debbugs.gnu.org; Thu, 31 Dec 2015 09:13:31 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aEdyn-0005Su-5S for 22202@debbugs.gnu.org; Thu, 31 Dec 2015 09:13:26 -0500 Original-Received: from fencepost.gnu.org ([2001:4830:134:3::e]:57681) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aEdyi-0005SU-DY; Thu, 31 Dec 2015 09:13:20 -0500 Original-Received: from 84.94.185.246.cable.012.net.il ([84.94.185.246]:2223 helo=HOME-C4E4A596F7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.82) (envelope-from ) id 1aEdyh-000516-Ip; Thu, 31 Dec 2015 09:13:19 -0500 In-reply-to: (message from Richard Copley on Wed, 30 Dec 2015 21:15:13 +0000) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:111060 Archived-At: > Date: Wed, 30 Dec 2015 21:15:13 +0000 > From: Richard Copley > Cc: David Engster , 22202@debbugs.gnu.org, > Demetri Obenour > > > That'd be the worst of both worlds, IMO: a not-so-good PRNG with no > > way whatsoever to get a repeatable sequence. Am I right? > > Oh dear. Yes. Worse than that, repeatability is part of the contract for > the lisp "random" function, so seed_random() and get_random() are > constrained to be deterministic. Right? > > Seems as though init_random() is the only place that could use > CryptGenRandom, which is a pity if you're trying to confine the > changes to w32.c. How about the following, then? (Not sure it's a good idea to read from /dev/random, as that could block; perhaps we should use /dev/urandom instead.) --- src/sysdep.c~2 2015-11-11 07:57:41.000000000 +0200 +++ src/sysdep.c 2015-12-31 16:09:46.987229300 +0200 @@ -2095,8 +2095,35 @@ seed_random (void *seed, ptrdiff_t seed_ void init_random (void) { - struct timespec t = current_timespec (); - uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec; + uintmax_t v; + struct timespec t; + bool success = false; + +#if HAVE_DEV_RANDOM + FILE *fp = fopen ("/dev/random", "rb"); + + if (fp) + { + int i; + + for (i = 0, v = 0; i < sizeof (uintmax_t); i++) + { + v <<= 8; + v |= fgetc (fp); + } + fclose (fp); + success = true; + } +#elif defined WINDOWSNT + if (w32_init_random (&v, sizeof v) == 0) + success = true; +#endif /* HAVE_DEV_RANDOM || WINDOWSNT */ + if (!success) + { + /* Fall back to current time value + PID. */ + t = current_timespec (); + v = getpid () ^ t.tv_sec ^ t.tv_nsec; + } seed_random (&v, sizeof v); } --- src/w32.c~0 2015-11-29 06:48:07.000000000 +0200 +++ src/w32.c 2015-12-31 16:05:06.775707600 +0200 @@ -224,6 +224,8 @@ typedef struct _REPARSE_DATA_BUFFER { #include /* should be after winsock2.h */ +#include + #include #include "w32.h" @@ -2093,6 +2095,34 @@ init_user_info (void) CloseHandle (token); } +static HCRYPTPROV w32_crypto_hprov; +static int +w32_init_crypt_random (void) +{ + if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + DebPrint (("CryptAcquireContext failed with error %x\n", + GetLastError ())); + w32_crypto_hprov = 0; + return -1; + } + return 0; +} + +int +w32_init_random (void *buf, ptrdiff_t buflen) +{ + if (w32_crypto_hprov) + w32_init_crypt_random (); + if (w32_crypto_hprov) + { + if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf)) + return 0; + } + return -1; +} + int random (void) { @@ -9386,6 +9416,8 @@ globals_of_w32 (void) extern void dynlib_reset_last_error (void); dynlib_reset_last_error (); #endif + + w32_crypto_hprov = (HCRYPTPROV)0; } /* For make-serial-process */ --- src/w32.h~2 2015-11-29 06:48:07.000000000 +0200 +++ src/w32.h 2015-12-31 16:09:21.960654500 +0200 @@ -222,6 +222,9 @@ extern int w32_memory_info (unsigned lon /* Compare 2 UTF-8 strings in locale-dependent fashion. */ extern int w32_compare_strings (const char *, const char *, char *, int); +/* Return a cryptographically secure seed for PRNG. */ +extern int w32_init_random (void *, ptrdiff_t); + #ifdef HAVE_GNUTLS #include --- src/fns.c~ 2015-11-22 07:57:20.000000000 +0200 +++ src/fns.c 2015-12-31 16:57:43.607286800 +0200 @@ -50,7 +50,8 @@ All integers representable in Lisp, i.e. and `most-positive-fixnum', inclusive, are equally likely. With positive integer LIMIT, return random number in interval [0,LIMIT). -With argument t, set the random number seed from the current time and pid. +With argument t, set the random number seed from the system's entropy +pool, or from the current time and pid if entropy is unavailable. With a string argument, set the seed based on the string's contents. Other values of LIMIT are ignored. --- configure.ac~2 2015-12-20 06:45:33.000000000 +0200 +++ configure.ac 2015-12-31 16:06:48.959511800 +0200 @@ -4145,6 +4145,22 @@ AC_TYPE_MBSTATE_T +AC_MSG_CHECKING([whether "/dev/random" is available]) +dev_random=no +dnl MSYS, being a Cygwin fork, thinks "/dev/random" does exist, so +dnl don't check this for the MinGW builds. +if test "${opsys}" != "mingw32"; then + if test -r "/dev/random"; then + AC_DEFINE(HAVE_DEV_RANDOM, 1, [Define if the system supports the "/dev/random" device.]) + dev_random=yes + fi +fi +if test $dev_random = yes; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + dnl Fixme: AC_SYS_POSIX_TERMIOS should probably be used, but it's not clear dnl how the tty code is related to POSIX and/or other versions of termios. dnl The following looks like a useful start.