Bug 91481 (CVE-2019-15847) - POWER9 "DARN" RNG intrinsic produces repeated output (CVE-2019-15847)
Summary: POWER9 "DARN" RNG intrinsic produces repeated output (CVE-2019-15847)
Status: RESOLVED FIXED
Alias: CVE-2019-15847
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 9.2.0
: P3 normal
Target Milestone: 7.5
Assignee: Segher Boessenkool
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2019-08-18 14:41 UTC by Jack Lloyd
Modified: 2019-10-21 21:32 UTC (History)
4 users (show)

See Also:
Host:
Target: powerpc*
Build:
Known to work: 10.0, 6.5.0, 7.4.1, 8.3.1, 9.2.1
Known to fail: 7.1.0, 7.4.0, 8.3.0, 9.2.0
Last reconfirmed: 2019-08-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jack Lloyd 2019-08-18 14:41:27 UTC
The POWER9 ISA includes a hardware random number generator "DARN" which is similar to x86 RDRAND/RDSEED. Using the GCC intrinsics and *any optimization level* then `__builtin_darn()` and `__builtin_darn_raw()` produce repeated output:

$ cat darn.c
#include <stdio.h>
#include <stdint.h>

int main()
{
  uint64_t darn[32];
  for(size_t i = 0; i != 32; ++i)
    darn[i] = __builtin_darn(); // or __builtin_darn_raw()

  for(size_t i = 0; i != 32; ++i)
    printf("%016lX\n", darn[i]);

}
$ $HOME/opt/bin/powerpc64le-unknown-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=/home/lloyd/opt/bin/powerpc64le-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/home/lloyd/opt/libexec/gcc/powerpc64le-unknown-linux-gnu/9.2.0/lto-wrapper
Target: powerpc64le-unknown-linux-gnu
Configured with: ../gcc-9.2.0/configure --prefix=/home/lloyd/opt --enable-languages=c,c++
Thread model: posix
gcc version 9.2.0 (GCC)
$ $HOME/opt/bin/powerpc64le-unknown-linux-gnu-gcc -mcpu=power9 -O -m64 darn.c -o darn
$ ./darn
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
32A7727F89101CF3
...


The binary produces a unique value each time it is executed, but the same value repeats. If no optimization is used, then different values are produced. Since these instructions are supposed to be used to seed cryptographic random number generators, this is quite bad. I don't know PPC asm but my read of the generated code when optimizations are enabled is that `darn` is invoked just once and then the value is placed repeatedly into the array - maybe GCC has not been taught that this instruction is volatile and produces a different output each time it is used?

Originally observed with "gcc version 8.3.1 20190304 (Advance-Toolchain-at12.0) [revision 269374] (GCC)" on gcc135, same behavior with stock GCC 9.2.0.

I don't think there is an issue with the hardware; if using inline asm instead of the intrinsics, everything seems to work as expected.
Comment 1 Thomas Koenig 2019-08-19 04:51:36 UTC
See also https://xkcd.com/221/
Comment 2 Richard Biener 2019-08-19 06:55:21 UTC
Likely the builtins are wrongly declared const or pure.  novops, leaf, nothrow would be the correct choice here.
Comment 3 Jeffrey Walton 2019-08-21 03:16:33 UTC
Lloyd's finding can be confirmed on GCC135. For example,

    gcc135:~$ /opt/at12.0/bin/gcc -O3 -mcpu=power9 -m64 darn.c -o darn
    gcc135:~$ ./darn
    9FBE0B8B6E861BD6
    9FBE0B8B6E861BD6
    9FBE0B8B6E861BD6
    9FBE0B8B6E861BD6
    ...

I can't find a header with a declaration, though:

    gcc135:~$ grep -IR builtin_darn /opt/at12.0/ 2>/dev/null
    gcc135:~$ grep -IR builtin_darn /lib 2>/dev/null
    gcc135:~$

Does someone know where the header is located?
Comment 4 Thomas Koenig 2019-08-21 12:40:41 UTC
Look in the gcc sources, under gcc/config/rs6000/rs6000.c .
Comment 5 Segher Boessenkool 2019-08-21 14:09:54 UTC
The various darn patterns use unspec instead of unspec_volatile.

Mine.
Comment 6 Segher Boessenkool 2019-08-22 19:36:53 UTC
Author: segher
Date: Thu Aug 22 19:36:21 2019
New Revision: 274835

URL: https://gcc.gnu.org/viewcvs?rev=274835&root=gcc&view=rev
Log:
rs6000: Use unspec_volatile for darn (PR91481)

Every call to darn should deliver a *new* random number; such calls
should not be CSEd together.  So they should be unspec_volatile, not
plain unspec.


	PR target/91481
	* config/rs6000/rs6000.md (unspec): Delete UNSPEC_DARN, UNSPEC_DARN_32,
	and UNSPEC_DARN_RAW.
	(unspecv): New enumerator values UNSPECV_DARN, UNSPECV_DARN_32, and
	UNSPECV_DARN_RAW.
	(darn_32): Use an unspec_volatile, and UNSPECV_DARN_32.
	(darn_raw): Use an unspec_volatile, and UNSPECV_DARN_RAW.
	(darn): Use an unspec_volatile, and UNSPECV_DARN.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/rs6000/rs6000.md
Comment 7 Segher Boessenkool 2019-08-23 22:20:11 UTC
Author: segher
Date: Fri Aug 23 22:19:40 2019
New Revision: 274889

URL: https://gcc.gnu.org/viewcvs?rev=274889&root=gcc&view=rev
Log:
rs6000: New darn testcase (PR91481)

We used to implement darn with unspecs, not unspec_volatiles, which
means two darn instructions could be CSEd together.

This testcase tests it by adding together four random numbers.  If all
is well that means we get four darn instructions, because such a small
loop is unrolled fine at -O2 already.  If things go bad, combine will
combine it all to one darn and a shift left by two.


gcc/testsuite/
	PR target/91481
	* gcc.target/powerpc/darn-3.c: New testcase.

Added:
    trunk/gcc/testsuite/gcc.target/powerpc/darn-3.c
Modified:
    trunk/gcc/testsuite/ChangeLog
Comment 8 Segher Boessenkool 2019-08-30 13:51:58 UTC
Author: segher
Date: Fri Aug 30 13:51:26 2019
New Revision: 275175

URL: https://gcc.gnu.org/viewcvs?rev=275175&root=gcc&view=rev
Log:
	Backport from trunk
	2019-08-22  Segher Boessenkool  <segher@kernel.crashing.org>

	PR target/91481
	* config/rs6000/rs6000.md (unspec): Delete UNSPEC_DARN, UNSPEC_DARN_32,
	and UNSPEC_DARN_RAW.
	(unspecv): New enumerator values UNSPECV_DARN, UNSPECV_DARN_32, and
	UNSPECV_DARN_RAW.
	(darn_32): Use an unspec_volatile, and UNSPECV_DARN_32.
	(darn_raw): Use an unspec_volatile, and UNSPECV_DARN_RAW.
	(darn): Use an unspec_volatile, and UNSPECV_DARN.

Modified:
    branches/gcc-9-branch/gcc/ChangeLog
    branches/gcc-9-branch/gcc/config/rs6000/rs6000.md
Comment 9 Segher Boessenkool 2019-08-30 13:53:42 UTC
Author: segher
Date: Fri Aug 30 13:53:11 2019
New Revision: 275176

URL: https://gcc.gnu.org/viewcvs?rev=275176&root=gcc&view=rev
Log:
	Backport from trunk
	2019-08-23  Segher Boessenkool  <segher@kernel.crashing.org>

gcc/testsuite/
	PR target/91481
	* gcc.target/powerpc/darn-3.c: New testcase.

Added:
    branches/gcc-9-branch/gcc/testsuite/gcc.target/powerpc/darn-3.c
Modified:
    branches/gcc-9-branch/gcc/testsuite/ChangeLog
Comment 10 Segher Boessenkool 2019-08-30 14:16:11 UTC
Author: segher
Date: Fri Aug 30 14:15:39 2019
New Revision: 275181

URL: https://gcc.gnu.org/viewcvs?rev=275181&root=gcc&view=rev
Log:
	Backport from trunk
	2019-08-22  Segher Boessenkool  <segher@kernel.crashing.org>

	PR target/91481
	* config/rs6000/rs6000.md (unspec): Delete UNSPEC_DARN, UNSPEC_DARN_32,
	and UNSPEC_DARN_RAW.
	(unspecv): New enumerator values UNSPECV_DARN, UNSPECV_DARN_32, and
	UNSPECV_DARN_RAW.
	(darn_32): Use an unspec_volatile, and UNSPECV_DARN_32.
	(darn_raw): Use an unspec_volatile, and UNSPECV_DARN_RAW.
	(darn): Use an unspec_volatile, and UNSPECV_DARN.

Modified:
    branches/gcc-8-branch/gcc/ChangeLog
    branches/gcc-8-branch/gcc/config/rs6000/rs6000.md
Comment 11 Segher Boessenkool 2019-08-30 14:17:51 UTC
Author: segher
Date: Fri Aug 30 14:17:20 2019
New Revision: 275182

URL: https://gcc.gnu.org/viewcvs?rev=275182&root=gcc&view=rev
Log:
	Backport from trunk
	2019-08-23  Segher Boessenkool  <segher@kernel.crashing.org>

gcc/testsuite/
	PR target/91481
	* gcc.target/powerpc/darn-3.c: New testcase.

Added:
    branches/gcc-8-branch/gcc/testsuite/gcc.target/powerpc/darn-3.c
Modified:
    branches/gcc-8-branch/gcc/testsuite/ChangeLog
Comment 12 Segher Boessenkool 2019-08-30 14:24:26 UTC
Author: segher
Date: Fri Aug 30 14:23:55 2019
New Revision: 275185

URL: https://gcc.gnu.org/viewcvs?rev=275185&root=gcc&view=rev
Log:
	Backport from trunk
	2019-08-22  Segher Boessenkool  <segher@kernel.crashing.org>

	PR target/91481
	* config/rs6000/rs6000.md (unspec): Delete UNSPEC_DARN, UNSPEC_DARN_32,
	and UNSPEC_DARN_RAW.
	(unspecv): New enumerator values UNSPECV_DARN, UNSPECV_DARN_32, and
	UNSPECV_DARN_RAW.
	(darn_32): Use an unspec_volatile, and UNSPECV_DARN_32.
	(darn_raw): Use an unspec_volatile, and UNSPECV_DARN_RAW.
	(darn): Use an unspec_volatile, and UNSPECV_DARN.

Modified:
    branches/gcc-7-branch/gcc/ChangeLog
    branches/gcc-7-branch/gcc/config/rs6000/rs6000.md
Comment 13 Segher Boessenkool 2019-08-30 14:26:07 UTC
Author: segher
Date: Fri Aug 30 14:25:36 2019
New Revision: 275186

URL: https://gcc.gnu.org/viewcvs?rev=275186&root=gcc&view=rev
Log:
	Backport from trunk
	2019-08-23  Segher Boessenkool  <segher@kernel.crashing.org>

gcc/testsuite/
	PR target/91481
	* gcc.target/powerpc/darn-3.c: New testcase.

Added:
    branches/gcc-7-branch/gcc/testsuite/gcc.target/powerpc/darn-3.c
Modified:
    branches/gcc-7-branch/gcc/testsuite/ChangeLog
Comment 14 Segher Boessenkool 2019-08-30 16:48:24 UTC
Fixed everywhere.
Comment 15 Jack Lloyd 2019-08-30 16:53:23 UTC
Thanks for the fast fix and backporting
Comment 16 Segher Boessenkool 2019-08-31 18:58:36 UTC
Author: segher
Date: Sat Aug 31 18:58:04 2019
New Revision: 275244

URL: https://gcc.gnu.org/viewcvs?rev=275244&root=gcc&view=rev
Log:
rs6000: Fix darn-3.c for GCC 8 and GCC 7

Apparently I didn't properly test the testcase backport to GCC 8 and
GCC 7.  This makes it not fail there.


	PR target/91481
	* gcc.target/powerpc/darn-3.c: Fix testcase.

Modified:
    branches/gcc-8-branch/gcc/testsuite/ChangeLog
    branches/gcc-8-branch/gcc/testsuite/gcc.target/powerpc/darn-3.c
Comment 17 Segher Boessenkool 2019-08-31 19:02:24 UTC
Author: segher
Date: Sat Aug 31 19:01:52 2019
New Revision: 275245

URL: https://gcc.gnu.org/viewcvs?rev=275245&root=gcc&view=rev
Log:
rs6000: Fix darn-3.c for GCC 8 and GCC 7

Apparently I didn't properly test the testcase backport to GCC 8 and
GCC 7.  This makes it not fail there.


	PR target/91481
	* gcc.target/powerpc/darn-3.c: Fix testcase.

Modified:
    branches/gcc-7-branch/gcc/testsuite/ChangeLog
    branches/gcc-7-branch/gcc/testsuite/gcc.target/powerpc/darn-3.c
Comment 18 Florian Weimer 2019-09-01 07:44:09 UTC
I'm going to request a CVE ID for this.
Comment 19 Richard Biener 2019-09-03 07:55:18 UTC
DARN (or power9) is not supported in GCC 6 or older.
Comment 20 Kevin Shekleton 2019-10-21 18:22:58 UTC
Hi all. The NVD entry (https://nvd.nist.gov/vuln/detail/CVE-2019-15847) specifies that gcc 10.0 will fix this issue. Of course, 10.0 is not yet released and the 'Known to work' field on this Bugzilla entry states "10.0, 6.5.0, 7.4.1, 8.3.1, 9.2.1". Some questions:

1. Any ETA on when a fix versions will be released?

2. From the commits here it looks like this fix is being backported to match the 'Known to work' field here (thanks!). Is the NVD entry going to be updated to reflect accurate  affected versions of gcc?
Comment 21 Segher Boessenkool 2019-10-21 20:05:52 UTC
It will be fixed in the next releases of all still supported branches
(that's GCC 7, 8, and 9), and also in the upcoming GCC 10 release of
course.

If you are in a hurry, you can build your own compilers right now, the
problem has been fixed in all open release branches.

If, alternatively, you get your GCC from some distribution, ask them
about *their* release plans.  We don't know.

No future releases for GCC have been announced.  Judging from historical
trends the next (and last) GCC 7 release (7.5) will be in November, GCC 8
(8.4) in December, GCC 9 (9.3) in Februari, and GCC 10 (10.1) will be
there in May.  This is just *my* estimate, your mileage may vary, etc.
Comment 22 Jonathan Wakely 2019-10-21 20:09:01 UTC
(In reply to Segher Boessenkool from comment #21)
> No future releases for GCC have been announced.  Judging from historical
> trends the next (and last) GCC 7 release (7.5) will be in November, GCC 8
> (8.4) in December, GCC 9 (9.3) in Februari, and GCC 10 (10.1) will be
> there in May.  This is just *my* estimate, your mileage may vary, etc.

See https://gcc.gnu.org/develop.html/timeline for dates of point releases from the release branches, which can be used to judge the historical trends for yourself.
Comment 23 Jonathan Wakely 2019-10-21 20:09:44 UTC
(In reply to Jonathan Wakely from comment #22)
> See https://gcc.gnu.org/develop.html/timeline

Sorry, that should be https://gcc.gnu.org/develop.html#timeline
Comment 24 Kevin Shekleton 2019-10-21 20:58:17 UTC
Thanks, Segher. You mentioned 9.3 -- does that mean there won't be a 9.2.1 release? If so, will the 'Known to work' field here be updated?

Also, will someone from the GCC team request an update to the NVD database to correct the affected release versions?
Comment 25 Segher Boessenkool 2019-10-21 21:22:27 UTC
There is no 9.2.1 release, and there will not be one either.

See https://gcc.gnu.org/develop.html for how our numbering scheme works.
Very briefly, if the second number is 0, or the third number is *not* zero,
it isn't a release but some development version.

I have nothing to do with the NVD, and not with https://cve.mitre.org/ either.
I didn't request a CVE for this.  I am merely the maintainer of this code, I
am not involved with the vulnerability circus.
Comment 26 Kevin Shekleton 2019-10-21 21:32:07 UTC
Thanks for educating me on the numbering scheme, Segher. That's helpful info!

Florian - I see you requested the CVE. Will you be working to get the NVD entry updated with the appropriate affected releases/fix versions?