15 #include <gtest/gtest.h>
23 #if defined(OPENSSL_X86_64) && !defined(BORINGSSL_SHARED_LIBRARY) && \
24 !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && defined(USE_NR_getrandom)
26 #include <linux/random.h>
27 #include <sys/ptrace.h>
28 #include <sys/syscall.h>
33 #if !defined(PTRACE_O_EXITKILL)
34 #define PTRACE_O_EXITKILL (1 << 20)
54 return type == other.type &&
length == other.length &&
55 flags == other.flags &&
56 ((
filename ==
nullptr && other.filename ==
nullptr) ||
57 strcmp(
filename, other.filename) == 0);
60 static Event GetRandom(
size_t length,
unsigned flags) {
61 Event
e(Syscall::kGetRandom);
67 static Event Open(
const char *
filename) {
68 Event
e(Syscall::kOpen);
73 static Event UrandomRead(
size_t length) {
74 Event
e(Syscall::kUrandomRead);
79 static Event UrandomIoctl() {
80 Event
e(Syscall::kUrandomIoctl);
84 static Event
Abort() {
85 Event
e(Syscall::kAbort);
93 case Syscall::kGetRandom:
101 case Syscall::kUrandomRead:
102 snprintf(
buf,
sizeof(
buf),
"read(urandom_fd, _, %zu)",
length);
105 case Syscall::kUrandomIoctl:
106 return "ioctl(urandom_fd, RNDGETENTCNT, _)";
108 case Syscall::kAbort:
123 for (
const auto &event : trace) {
127 ret +=
event.String();
136 static const unsigned NO_GETRANDOM = 1;
138 static const unsigned NO_URANDOM = 2;
140 static const unsigned GETRANDOM_NOT_READY = 4;
143 static const unsigned URANDOM_NOT_READY = 8;
145 static const unsigned GETRANDOM_ERROR = 16;
147 static const unsigned URANDOM_ERROR = 32;
148 static const unsigned NEXT_FLAG = 64;
153 static void GetTrace(std::vector<Event> *out_trace,
unsigned flags,
155 const int child_pid = fork();
158 if (child_pid == 0) {
160 if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) {
161 perror(
"PTRACE_TRACEME");
179 ASSERT_EQ(0, ptrace(PTRACE_SETOPTIONS, child_pid,
nullptr,
180 PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD))
189 ASSERT_EQ(0, ptrace(PTRACE_SYSCALL, child_pid, 0, 0));
193 if (WIFSTOPPED(
status) && WSTOPSIG(
status) == SIGABRT) {
201 struct user_regs_struct regs;
202 ASSERT_EQ(0, ptrace(PTRACE_GETREGS, child_pid,
nullptr, ®s));
203 const auto syscall_number = regs.orig_rax;
205 bool is_opening_urandom =
false;
206 bool is_urandom_ioctl =
false;
211 int inject_error = 0;
213 switch (syscall_number) {
215 if (
flags & NO_GETRANDOM) {
216 inject_error = -ENOSYS;
217 }
else if (
flags & GETRANDOM_ERROR) {
218 inject_error = -EINVAL;
219 }
else if (
flags & GETRANDOM_NOT_READY) {
220 if (regs.rdx & GRND_NONBLOCK) {
221 inject_error = -EAGAIN;
224 out_trace->push_back(
225 Event::GetRandom(regs.rsi, regs.rdx));
233 const char *
filename =
reinterpret_cast<const char *
>(
234 (syscall_number == __NR_openat) ? regs.rsi : regs.rdi);
235 out_trace->push_back(Event::Open(
filename));
236 is_opening_urandom = strcmp(
filename,
"/dev/urandom") == 0;
237 if (is_opening_urandom && (
flags & NO_URANDOM)) {
238 inject_error = -ENOENT;
244 const int read_fd = regs.rdi;
245 if (urandom_fd >= 0 && urandom_fd == read_fd) {
246 out_trace->push_back(Event::UrandomRead(regs.rdx));
247 if (
flags & URANDOM_ERROR) {
248 inject_error = -EINVAL;
255 const int ioctl_fd = regs.rdi;
256 if (urandom_fd >= 0 && ioctl_fd == urandom_fd &&
257 regs.rsi == RNDGETENTCNT) {
258 out_trace->push_back(Event::UrandomIoctl());
259 is_urandom_ioctl =
true;
260 ioctl_output_addr = regs.rdx;
270 ASSERT_EQ(0, ptrace(PTRACE_SETREGS, child_pid,
nullptr, ®s));
273 ASSERT_EQ(0, ptrace(PTRACE_SYSCALL, child_pid, 0, 0));
288 if (inject_error != -ENOSYS) {
289 ASSERT_EQ(0, ptrace(PTRACE_GETREGS, child_pid,
nullptr, ®s));
290 regs.rax = inject_error;
291 ASSERT_EQ(0, ptrace(PTRACE_SETREGS, child_pid,
nullptr, ®s));
293 }
else if (is_opening_urandom) {
294 ASSERT_EQ(0, ptrace(PTRACE_GETREGS, child_pid,
nullptr, ®s));
295 urandom_fd = regs.rax;
296 }
else if (is_urandom_ioctl) {
303 if (
flags & URANDOM_NOT_READY) {
305 flags &= ~URANDOM_NOT_READY;
311 const uintptr_t aligned_addr = ioctl_output_addr & ~7;
317 u.word = ptrace(PTRACE_PEEKDATA, child_pid,
318 reinterpret_cast<void *
>(aligned_addr),
nullptr);
320 ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, child_pid,
321 reinterpret_cast<void *
>(aligned_addr),
322 reinterpret_cast<void *
>(
u.word)));
334 static bool have_fork_detection() {
341 static std::vector<Event> TestFunctionPRNGModel(
unsigned flags) {
342 #if defined(BORINGSSL_FIPS)
343 static const bool is_fips =
true;
345 static const bool is_fips =
false;
348 std::vector<Event>
ret;
349 bool urandom_probed =
false;
350 bool getrandom_ready =
false;
353 ret.push_back(Event::GetRandom(1, GRND_NONBLOCK));
357 if (
flags & NO_GETRANDOM) {
358 ret.push_back(Event::Open(
"/dev/urandom"));
359 if (
flags & NO_URANDOM) {
365 if (!is_fips || urandom_probed) {
370 ret.push_back(Event::UrandomIoctl());
371 if (
flags & URANDOM_NOT_READY) {
374 ret.push_back(Event::UrandomIoctl());
377 urandom_probed =
true;
384 ret.push_back(Event::UrandomRead(
len));
385 if (
flags & URANDOM_ERROR) {
392 if (
flags & GETRANDOM_ERROR) {
397 getrandom_ready = (
flags & GETRANDOM_NOT_READY) == 0;
399 if (getrandom_ready) {
403 ret.push_back(Event::GetRandom(1, GRND_NONBLOCK));
404 ret.push_back(Event::GetRandom(1, 0));
405 getrandom_ready =
true;
411 ret.push_back(Event::GetRandom(
len,
block ? 0 : GRND_NONBLOCK));
417 const size_t kAdditionalDataLength = 32;
420 if ((!have_fork_detection() && !sysrand(
true, kAdditionalDataLength)) ||
422 (is_fips && !sysrand(
true, 16)) ||
423 !sysrand(
true, kSeedLength) ||
425 (!have_fork_detection() && !sysrand(
true, kAdditionalDataLength))) {
432 !sysrand(
false, kAdditionalDataLength)) ||
439 !sysrand(
false, kAdditionalDataLength))) {
449 #if defined(BORINGSSL_FIPS)
451 for (
const auto &event : events) {
452 switch (event.type) {
453 case Event::Syscall::kGetRandom:
454 if ((event.flags & GRND_NONBLOCK) == 0) {
455 ADD_FAILURE() <<
"Blocking getrandom found with RDRAND: "
460 case Event::Syscall::kUrandomIoctl:
461 ADD_FAILURE() <<
"Urandom polling found with RDRAND: "
478 #define TRACE_FLAG(flag) \
479 snprintf(buf, sizeof(buf), #flag ": %d", (flags & flag) != 0); \
483 TRACE_FLAG(NO_GETRANDOM);
484 TRACE_FLAG(NO_URANDOM);
485 TRACE_FLAG(GETRANDOM_NOT_READY);
486 TRACE_FLAG(URANDOM_NOT_READY);
487 TRACE_FLAG(GETRANDOM_ERROR);
488 TRACE_FLAG(URANDOM_ERROR);
490 const std::vector<Event> expected_trace = TestFunctionPRNGModel(
flags);
492 std::vector<Event> actual_trace;
495 if (expected_trace != actual_trace) {
497 <<
"\nFound: " <<
ToString(actual_trace);
502 int main(
int argc,
char **argv) {
505 if (
getenv(
"BORINGSSL_IGNORE_MADV_WIPEONFORK")) {
514 int main(
int argc,
char **argv) {
519 #endif // X86_64 && !SHARED_LIBRARY && !UNSAFE_DETERMINISTIC_MODE &&