Permalink
Browse files

Flush secureRandom buffer on fork

Summary: On fork, flush the secureRandom buffer, so that we don't share entropy between the parent and child.

Reviewed By: ricklavoie

Differential Revision: D9196474

fbshipit-source-id: 12ff8488d814466186df61328a5f1d4000beb27f
  • Loading branch information...
fredemmott authored and facebook-github-bot committed Aug 8, 2018
1 parent 173b48d commit 8e927ee48b114c8a2f90d0cbd5ac753795a6761f
Showing with 40 additions and 2 deletions.
  1. +19 −2 folly/Random.cpp
  2. +21 −0 folly/test/RandomTest.cpp
@@ -72,6 +72,7 @@ void readRandomDevice(void* data, size_t size) {

class BufferedRandomDevice {
public:
static once_flag flag;
static constexpr size_t kDefaultBufferSize = 128;

explicit BufferedRandomDevice(size_t bufferSize = kDefaultBufferSize);
@@ -97,10 +98,28 @@ class BufferedRandomDevice {
unsigned char* ptr_;
};

once_flag BufferedRandomDevice::flag;
struct RandomTag {};

BufferedRandomDevice::BufferedRandomDevice(size_t bufferSize)
: bufferSize_(bufferSize),
buffer_(new unsigned char[bufferSize]),
ptr_(buffer_.get() + bufferSize) { // refill on first use
call_once(flag, [this]() {
detail::AtFork::registerHandler(
this,
/*prepare*/ []() { return true; },
/*parent*/ []() {},
/*child*/
[]() {
using Single = SingletonThreadLocal<BufferedRandomDevice, RandomTag>;
auto& t = Single::get();
// Clear out buffered data on fork.
//
// Ensure child and parent do not share same entropy pool.
t.ptr_ = t.buffer_.get() + t.bufferSize_;
});
});
}

void BufferedRandomDevice::getSlow(unsigned char* data, size_t size) {
@@ -124,8 +143,6 @@ void BufferedRandomDevice::getSlow(unsigned char* data, size_t size) {
ptr_ += size;
}

struct RandomTag {};

} // namespace

void Random::secureRandom(void* data, size_t size) {
@@ -138,3 +138,24 @@ TEST(Random, sanity) {
std::unordered_set<uint64_t>(vals.begin(), vals.end()).size());
}
}

TEST(Random, SecureFork) {
unsigned char buffer = 0;
// Init random buffer
folly::Random::secureRandom(&buffer, 1);

auto pid = fork();
EXPECT_NE(pid, -1);
if (pid) {
// parent
int status = 0;
folly::Random::secureRandom(&buffer, 1);
auto pid2 = wait(&status);
EXPECT_NE(WEXITSTATUS(status), buffer);
EXPECT_EQ(pid, pid2);
} else {
// child
folly::Random::secureRandom(&buffer, 1);
exit(buffer); // Do not print gtest results
}
}

0 comments on commit 8e927ee

Please sign in to comment.