...
mongo::SecureRandom() holds a std::ifstream to read from /dev/urandom. std::ifstream is buffered by default, so the first use of the SecureRandom fills that 8kiB buffer. This is extremely wasteful, as a SecureRandom object is often used for a few words and discarded, and /dev/urandom entropy and/or computational load is a resource we don't want to squander unnecessarily. As a patch, we can reduce the buffering to maybe 64 bytes or so, possibly as part of SERVER-43641 which is in there anyway. Turning off buffering completely would incur read() syscalls on every use, which could be risky, so a 100X smaller buffer seems a good tradeoff. https://gist.github.com/BillyDonahue/53fa229d311cc6ac1f5ab21bd588e11f#file-gistfile2-txt Catchpoint 5 (call to syscall read), 0x00007ffff4e0534e in __libc_read (fd=6, buf=buf@entry=0x7fffeee07820, nbytes=nbytes@entry=8191) at ../sysdeps/unix/sysv/linux/read.c:27 27 ../sysdeps/unix/sysv/linux/read.c: No such file or directory. (gdb) bt #0 0x00007ffff4e0534e in __libc_read (fd=6, buf=buf@entry=0x7fffeee07820, nbytes=nbytes@entry=8191) at ../sysdeps/unix/sysv/linux/read.c:27 #1 0x00007ffff7916287 in std::_basic_file::xsgetn (this=this@entry=0x7fffeee004d8, __s=0x7fffeee07820 '\253' ..., __n=_n@entry=8191) at basic_file.cc:285 #2 0x00007ffff793ff30 in std::basic_filebuf >::underflow (this=0x7fffeee00470) at /home/billy/dev/10gen/toolchain-builder/tmp/build-gcc-v3.sh-sRY/build/x86_64-mongodb-linux/libstdc++-v3/include/bits/char_traits.h:350 #3 0x00007ffff78ee576 in std::basic_streambuf >::uflow (this=0x7fffeee00470) at /home/billy/dev/10gen/toolchain-builder/tmp/build-gcc-v3.sh-sRY/build/x86_64-mongodb-linux/libstdc++-v3/include/streambuf:707 #4 std::basic_streambuf >::xsgetn (this=this@entry=0x7fffeee00470, _s=s@entry=0x7fffffffd468 " \362\333\356\377\177", __n=_n@entry=8) at /home/billy/dev/10gen/toolchain-builder/tmp/build-gcc-v3.sh-sRY/build/x86_64-mongodb-linux/libstdc++-v3/include/bits/streambuf.tcc:64 #5 0x00007ffff79409e3 in std::basic_filebuf >::xsgetn (this=0x7fffeee00470, __s=0x7fffffffd468 " \362\333\356\377\177", __n=8) at /home/billy/dev/10gen/toolchain-builder/tmp/build-gcc-v3.sh-sRY/build/x86_64-mongodb-linux/libstdc++-v3/include/bits/codecvt.h:210 #6 0x00007ffff78e989d in std::basic_streambuf >::sgetn (__n=8, __s=0x7fffffffd468 " \362\333\356\377\177", this=) at /home/billy/dev/10gen/toolchain-builder/tmp/build-gcc-v3.sh-sRY/build/x86_64-mongodb-linux/libstdc++-v3/include/streambuf:364 #7 std::istream::read (this=0x7fffeee00460, __s=0x7fffffffd468 " \362\333\356\377\177", __n=8) at /home/billy/dev/10gen/toolchain-builder/tmp/build-gcc-v3.sh-sRY/build/x86_64-mongodb-linux/libstdc++-v3/include/bits/istream.tcc:667 #8 0x00007ffff7c9b2be in mongo::random_detail::SecureUrbg::State::operator() (this=0x7fffeee00460) at src/mongo/platform/random.cpp:127 #9 0x00007ffff7c9b02c in mongo::random_detail::SecureUrbg::operator() (this=0x7fffeedbf220) at src/mongo/platform/random.cpp:139 #10 0x00005555557397ee in std::uniform_int_distribution::operator() (this=0x7fffffffd5f0, __urng=..., __param=...) at /opt/mongodbtoolchain/stow/gcc-v3.sFn/include/c++/8.2.0/bits/uniform_int_dist.h:275 #11 0x0000555555736bd3 in std::uniform_int_distribution::operator() (this=0x7fffffffd5f0, __urng=...) at /opt/mongodbtoolchain/stow/gcc-v3.sFn/include/c++/8.2.0/bits/uniform_int_dist.h:166 #12 0x0000555555733f35 in mongo::RandomBase::_nextAny (this=0x7fffeedbf220) at src/mongo/platform/random.h:137 #13 0x000055555572f578 in mongo::RandomBase::nextInt64 (this=0x7fffeedbf220) at src/mongo/platform/random.h:120 #14 0x00007ffff7c7d232 in mongo::_mongoInitializerFunction_OIDGeneration (context=0x7fffffffd7b0) at src/mongo/bson/oid.cpp:58 ... #21 0x00007ffff7fe51f3 in main (argc=3, argv=0x7fffffffddb8, envp=0x7fffffffddd8) at src/mongo/unittest/unittest_main.cpp:52 #22 0x00007ffff4a24b97 in __libc_start_main (main=0x7ffff7fe519c , char*)>, argc=3, argv=0x7fffffffddb8, init=, fini=, rtld_fini=, stack_end=0x7fffffffdda8) at ../csu/libc-start.c:310 #23 0x00005555556f9cea in _start () (gdb)
xgen-internal-githook commented on Wed, 2 Oct 2019 04:42:49 +0000: Author: {'name': 'Billy Donahue', 'username': 'BillyDonahue', 'email': 'billy.donahue@mongodb.com'} Message: SERVER-43641 upgrade random.h Respecify PseudoRandom and SecureRandom as template instances of a `mongo::RandomBase` (Urbg is a UniformRandomBitGenerator). They will only vary in which algorithm they use for their source bits, and should otherwise support the same exact operations (e.g. `nextCanonicalDouble`). Fix range and stats errors in the implementations of those RandomBase methods, and specify them in terms of the vetted `` facilities. Test uniformity of nextInt32(max), which uses an inappropriate ( x % max) operation. Verify that refactor fixes this issue. Just keep a shared urandom file descriptor open. SecureRandom add fill, remove create, fix callers Obsoletes SERVER-43643 Re: SecureRandom 8kiB buffering Branch: master https://github.com/mongodb/mongo/commit/96da177c6ae7b7ed0f29983ad033d8a59524b0b2 billy.donahue commented on Sat, 28 Sep 2019 02:15:36 +0000: I'm now trying what should be a very efficient approach here. It's similar to what the Python interpreter does to support its os.urandom module and its internal hash randomization. It opens one file descriptor to /dev/urandom, and retains it forever. It goes back to read() from it when necessary, but it doesn't have to open() and close() it constantly and churn or compete for file descriptors. It's working fine in PoC. billy.donahue commented on Wed, 25 Sep 2019 20:27:36 +0000: https://mongodbcr.appspot.com/489550001/
SECURE_RANDOM_READ_LOC=src/mongo/platform/random.cpp:127 $ gdb $BUILD_DIR/mongo/platform/platform_test b $SECURE_RANDOM_READ_LOC run --suite=RandomTest --filter=Secure1 (hits breakpoint) b catch syscall continue