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.
See also https://xkcd.com/221/
Likely the builtins are wrongly declared const or pure. novops, leaf, nothrow would be the correct choice here.
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?
Look in the gcc sources, under gcc/config/rs6000/rs6000.c .
The various darn patterns use unspec instead of unspec_volatile. Mine.
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
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
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
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
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
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
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
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
Fixed everywhere.
Thanks for the fast fix and backporting
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
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
I'm going to request a CVE ID for this.
DARN (or power9) is not supported in GCC 6 or older.
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?
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.
(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.
(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
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?
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.
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?