1 /* Copyright (c) 2019, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <gtest/gtest.h>
16 #include <stdlib.h>
17
18 #include <openssl/ctrdrbg.h>
19 #include <openssl/rand.h>
20
21 #include "getrandom_fillin.h"
22 #include "internal.h"
23
24 #if (defined(OPENSSL_X86_64) || defined(OPENSSL_AARCH64)) && \
25 !defined(BORINGSSL_SHARED_LIBRARY) && \
26 !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && defined(USE_NR_getrandom)
27
28 #include <linux/random.h>
29 #include <sys/ptrace.h>
30 #include <sys/socket.h>
31 #include <sys/syscall.h>
32 #include <sys/uio.h>
33 #include <sys/un.h>
34 #include <sys/user.h>
35
36 #include "fork_detect.h"
37
38 #if !defined(PTRACE_O_EXITKILL)
39 #define PTRACE_O_EXITKILL (1 << 20)
40 #endif
41
42 #if defined(BORINGSSL_FIPS)
43 static const bool kIsFIPS = true;
44 #if defined(OPENSSL_ANDROID)
45 static const bool kUsesDaemon = true;
46 #else
47 static const bool kUsesDaemon = false;
48 #endif
49 #else
50 static const bool kIsFIPS = false;
51 static const bool kUsesDaemon = false;
52 #endif
53
54 // kDaemonWriteLength is the number of bytes that the entropy daemon writes.
55 static const size_t kDaemonWriteLength = 496;
56
57 // This test can be run with $OPENSSL_ia32cap=~0x4000000000000000 in order to
58 // simulate the absence of RDRAND of machines that have it.
59
60 // Event represents a system call from urandom.c that is observed by the ptrace
61 // code in |GetTrace|.
62 struct Event {
63 enum class Syscall {
64 kGetRandom,
65 kOpen,
66 kUrandomRead,
67 kUrandomIoctl,
68 kSocket,
69 kConnect,
70 kSocketRead,
71 kSocketClose,
72 kAbort,
73 };
74
EventEvent75 explicit Event(Syscall syscall) : type(syscall) {}
76
operator ==Event77 bool operator==(const Event &other) const {
78 return type == other.type && length == other.length &&
79 flags == other.flags &&
80 ((filename == nullptr && other.filename == nullptr) ||
81 strcmp(filename, other.filename) == 0);
82 }
83
GetRandomEvent84 static Event GetRandom(size_t length, unsigned flags) {
85 Event e(Syscall::kGetRandom);
86 e.length = length;
87 e.flags = flags;
88 return e;
89 }
90
OpenEvent91 static Event Open(const char *filename) {
92 Event e(Syscall::kOpen);
93 e.filename = filename;
94 return e;
95 }
96
UrandomReadEvent97 static Event UrandomRead(size_t length) {
98 Event e(Syscall::kUrandomRead);
99 e.length = length;
100 return e;
101 }
102
UrandomIoctlEvent103 static Event UrandomIoctl() {
104 Event e(Syscall::kUrandomIoctl);
105 return e;
106 }
107
SocketEvent108 static Event Socket() {
109 Event e(Syscall::kSocket);
110 return e;
111 }
112
ConnectEvent113 static Event Connect() {
114 Event e(Syscall::kConnect);
115 return e;
116 }
117
SocketReadEvent118 static Event SocketRead(size_t length) {
119 Event e(Syscall::kSocketRead);
120 e.length = length;
121 return e;
122 }
123
SocketCloseEvent124 static Event SocketClose() {
125 Event e(Syscall::kSocketClose);
126 return e;
127 }
128
AbortEvent129 static Event Abort() {
130 Event e(Syscall::kAbort);
131 return e;
132 }
133
StringEvent134 std::string String() const {
135 char buf[256];
136
137 switch (type) {
138 case Syscall::kGetRandom:
139 snprintf(buf, sizeof(buf), "getrandom(_, %zu, %u)", length, flags);
140 break;
141
142 case Syscall::kOpen:
143 snprintf(buf, sizeof(buf), "open(%s, _)", filename);
144 break;
145
146 case Syscall::kUrandomRead:
147 snprintf(buf, sizeof(buf), "read(urandom_fd, _, %zu)", length);
148 break;
149
150 case Syscall::kUrandomIoctl:
151 return "ioctl(urandom_fd, RNDGETENTCNT, _)";
152
153 case Syscall::kSocket:
154 return "socket(UNIX, STREAM, _)";
155
156 case Syscall::kConnect:
157 return "connect(sock, _, _)";
158
159 case Syscall::kSocketRead:
160 snprintf(buf, sizeof(buf), "read(sock_fd, _, %zu)", length);
161 break;
162
163 case Syscall::kSocketClose:
164 return "close(sock)";
165
166 case Syscall::kAbort:
167 return "abort()";
168 }
169
170 return std::string(buf);
171 }
172
173 const Syscall type;
174 size_t length = 0;
175 unsigned flags = 0;
176 const char *filename = nullptr;
177 };
178
ToString(const std::vector<Event> & trace)179 static std::string ToString(const std::vector<Event> &trace) {
180 std::string ret;
181 for (const auto &event : trace) {
182 if (!ret.empty()) {
183 ret += ", ";
184 }
185 ret += event.String();
186 }
187 return ret;
188 }
189
190 // The following are flags to tell |GetTrace| to inject faults, using ptrace,
191 // into the entropy-related system calls.
192
193 // getrandom gives |ENOSYS|.
194 static const unsigned NO_GETRANDOM = 1;
195 // opening /dev/urandom fails.
196 static const unsigned NO_URANDOM = 2;
197 // getrandom always returns |EAGAIN| if given |GRNG_NONBLOCK|.
198 static const unsigned GETRANDOM_NOT_READY = 4;
199 // The ioctl on urandom returns only 255 bits of entropy the first time that
200 // it's called.
201 static const unsigned URANDOM_NOT_READY = 8;
202 // getrandom gives |EINVAL| unless |NO_GETRANDOM| is set.
203 static const unsigned GETRANDOM_ERROR = 16;
204 // Reading from /dev/urandom gives |EINVAL|.
205 static const unsigned URANDOM_ERROR = 32;
206 static const unsigned SOCKET_ERROR = 64;
207 static const unsigned CONNECT_ERROR = 128;
208 static const unsigned SOCKET_READ_ERROR = 256;
209 static const unsigned SOCKET_READ_SHORT = 512;
210 static const unsigned NEXT_FLAG = 1024;
211
212 // regs_read fetches the registers of |child_pid| and writes them to |out_regs|.
213 // That structure will contain at least the following members:
214 // syscall: the syscall number, if registers were read just before entering
215 // one.
216 // args[0..2]: syscall arguments, if registers were read just before
217 // entering one.
218 // ret: the syscall return value, if registers were read just after finishing
219 // one.
220 //
221 // This call returns true on success and false otherwise.
222 static bool regs_read(struct regs *out_regs, int child_pid);
223
224 // regs_set_ret sets the return value of the system call that |child_pid| has
225 // just finished, to |ret|. It returns true on success and false otherwise.
226 static bool regs_set_ret(int child_pid, int ret);
227
228 // regs_break_syscall causes the system call that |child_pid| is about to enter
229 // to fail to run.
230 static bool regs_break_syscall(int child_pid, const struct regs *orig_regs);
231
232 #if defined(OPENSSL_X86_64)
233
234 struct regs {
235 uintptr_t syscall;
236 uintptr_t args[3];
237 uintptr_t ret;
238 struct user_regs_struct regs;
239 };
240
regs_read(struct regs * out_regs,int child_pid)241 static bool regs_read(struct regs *out_regs, int child_pid) {
242 if (ptrace(PTRACE_GETREGS, child_pid, nullptr, &out_regs->regs) != 0) {
243 return false;
244 }
245
246 out_regs->syscall = out_regs->regs.orig_rax;
247 out_regs->ret = out_regs->regs.rax;
248 out_regs->args[0] = out_regs->regs.rdi;
249 out_regs->args[1] = out_regs->regs.rsi;
250 out_regs->args[2] = out_regs->regs.rdx;
251 return true;
252 }
253
regs_set_ret(int child_pid,int ret)254 static bool regs_set_ret(int child_pid, int ret) {
255 struct regs regs;
256 if (!regs_read(®s, child_pid)) {
257 return false;
258 }
259 regs.regs.rax = ret;
260 return ptrace(PTRACE_SETREGS, child_pid, nullptr, ®s.regs) == 0;
261 }
262
regs_break_syscall(int child_pid,const struct regs * orig_regs)263 static bool regs_break_syscall(int child_pid, const struct regs *orig_regs) {
264 // Replacing the syscall number with -1 doesn't work on AArch64 thus we set
265 // the first argument to -1, which suffices to break the syscalls that we care
266 // about here.
267 struct user_regs_struct regs;
268 memcpy(®s, &orig_regs->regs, sizeof(regs));
269 regs.rdi = -1;
270 return ptrace(PTRACE_SETREGS, child_pid, nullptr, ®s) == 0;
271 }
272
273 #elif defined(OPENSSL_AARCH64)
274
275 struct regs {
276 uintptr_t syscall;
277 uintptr_t args[3];
278 uintptr_t ret;
279 uint64_t regs[9];
280 };
281
regs_read(struct regs * out_regs,int child_pid)282 static bool regs_read(struct regs *out_regs, int child_pid) {
283 struct iovec io;
284 io.iov_base = out_regs->regs;
285 io.iov_len = sizeof(out_regs->regs);
286 if (ptrace(PTRACE_GETREGSET, child_pid, (void *)/*NT_PRSTATUS*/ 1, &io) !=
287 0) {
288 return false;
289 }
290
291 out_regs->syscall = out_regs->regs[8];
292 out_regs->ret = out_regs->regs[0];
293 out_regs->args[0] = out_regs->regs[0];
294 out_regs->args[1] = out_regs->regs[1];
295 out_regs->args[2] = out_regs->regs[2];
296
297 return true;
298 }
299
regs_set(int child_pid,const struct regs * orig_regs,uint64_t x0_value)300 static bool regs_set(int child_pid, const struct regs *orig_regs,
301 uint64_t x0_value) {
302 uint64_t regs[OPENSSL_ARRAY_SIZE(orig_regs->regs)];
303 memcpy(regs, orig_regs->regs, sizeof(regs));
304 regs[0] = x0_value;
305
306 struct iovec io;
307 io.iov_base = regs;
308 io.iov_len = sizeof(regs);
309 return ptrace(PTRACE_SETREGSET, child_pid, (void *)/*NT_PRSTATUS*/ 1, &io) ==
310 0;
311 }
312
regs_set_ret(int child_pid,int ret)313 static bool regs_set_ret(int child_pid, int ret) {
314 struct regs regs;
315 return regs_read(®s, child_pid) && regs_set(child_pid, ®s, ret);
316 }
317
regs_break_syscall(int child_pid,const struct regs * orig_regs)318 static bool regs_break_syscall(int child_pid, const struct regs *orig_regs) {
319 // Replacing the syscall number with -1 doesn't work on AArch64 thus we set
320 // the first argument to -1, which suffices to break the syscalls that we care
321 // about here.
322 return regs_set(child_pid, orig_regs, -1);
323 }
324
325 #endif
326
327 // SyscallResult is like std::optional<int>.
328 // TODO: use std::optional when we can use C++17.
329 class SyscallResult {
330 public:
operator =(int value)331 SyscallResult &operator=(int value) {
332 has_value_ = true;
333 value_ = value;
334 return *this;
335 }
336
value() const337 int value() const {
338 if (!has_value_) {
339 abort();
340 }
341 return value_;
342 }
343
has_value() const344 bool has_value() const { return has_value_; }
345
346 private:
347 bool has_value_ = false;
348 int value_ = 0;
349 };
350
351 // memcpy_to_remote copies |n| bytes from |in_src| in the local address space,
352 // to |dest| in the address space of |child_pid|.
memcpy_to_remote(int child_pid,uint64_t dest,const void * in_src,size_t n)353 static void memcpy_to_remote(int child_pid, uint64_t dest, const void *in_src,
354 size_t n) {
355 const uint8_t *src = reinterpret_cast<const uint8_t *>(in_src);
356
357 // ptrace always works with ill-defined "words", which appear to be 64-bit
358 // on 64-bit systems.
359 #if !defined(OPENSSL_64_BIT)
360 #error "This code probably doesn't work"
361 #endif
362
363 while (n) {
364 const uintptr_t aligned_addr = dest & ~7;
365 const uintptr_t offset = dest - aligned_addr;
366 const size_t space = 8 - offset;
367 size_t todo = n;
368 if (todo > space) {
369 todo = space;
370 }
371
372 uint64_t word;
373 if (offset == 0 && todo == 8) {
374 word = CRYPTO_load_u64_le(src);
375 } else {
376 uint8_t bytes[8];
377 CRYPTO_store_u64_le(
378 bytes, ptrace(PTRACE_PEEKDATA, child_pid,
379 reinterpret_cast<void *>(aligned_addr), nullptr));
380 memcpy(&bytes[offset], src, todo);
381 word = CRYPTO_load_u64_le(bytes);
382 }
383
384 ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, child_pid,
385 reinterpret_cast<void *>(aligned_addr),
386 reinterpret_cast<void *>(word)));
387
388 src += todo;
389 n -= todo;
390 dest += todo;
391 }
392 }
393
394 // GetTrace runs |thunk| in a forked process and observes the resulting system
395 // calls using ptrace. It simulates a variety of failures based on the contents
396 // of |flags| and records the observed events by appending to |out_trace|.
GetTrace(std::vector<Event> * out_trace,unsigned flags,std::function<void ()> thunk)397 static void GetTrace(std::vector<Event> *out_trace, unsigned flags,
398 std::function<void()> thunk) {
399 const int child_pid = fork();
400 ASSERT_NE(-1, child_pid);
401
402 if (child_pid == 0) {
403 // Child process
404 if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) {
405 perror("PTRACE_TRACEME");
406 _exit(1);
407 }
408 raise(SIGSTOP);
409 thunk();
410 _exit(0);
411 }
412
413 // Parent process
414 int status;
415 ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
416 ASSERT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
417
418 // Set options so that:
419 // a) the child process is killed once this process dies.
420 // b) System calls result in a WSTOPSIG value of (SIGTRAP | 0x80) rather
421 // than just SIGTRAP. (This doesn't matter here, but it's recommended
422 // practice so that it's distinct from the signal itself.)
423 ASSERT_EQ(0, ptrace(PTRACE_SETOPTIONS, child_pid, nullptr,
424 PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD))
425 << strerror(errno);
426
427 // urandom_fd tracks the file descriptor number for /dev/urandom in the child
428 // process, if it opens it.
429 int urandom_fd = -1;
430
431 // sock_fd tracks the file descriptor number for the socket to the entropy
432 // daemon, if one is opened.
433 int sock_fd = -1;
434
435 for (;;) {
436 // Advance the child to the next system call.
437 ASSERT_EQ(0, ptrace(PTRACE_SYSCALL, child_pid, 0, 0));
438 ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
439
440 // The child may have aborted rather than made a system call.
441 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGABRT) {
442 out_trace->push_back(Event::Abort());
443 break;
444 }
445
446 // Otherwise the only valid ptrace event is a system call stop.
447 ASSERT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80));
448
449 struct regs regs;
450 ASSERT_TRUE(regs_read(®s, child_pid));
451
452 bool is_opening_urandom = false;
453 bool is_socket_call = false;
454 bool is_urandom_ioctl = false;
455 uintptr_t ioctl_output_addr = 0;
456 bool is_socket_read = false;
457 uint64_t socket_read_bytes = 0;
458 // force_result is unset to indicate that the system call should run
459 // normally. Otherwise it's, e.g. -EINVAL, to indicate that the system call
460 // should not run and that the given value should be injected on return.
461 SyscallResult force_result;
462
463 switch (regs.syscall) {
464 case __NR_getrandom:
465 if (flags & NO_GETRANDOM) {
466 force_result = -ENOSYS;
467 } else if (flags & GETRANDOM_ERROR) {
468 force_result = -EINVAL;
469 } else if (flags & GETRANDOM_NOT_READY) {
470 if (regs.args[2] & GRND_NONBLOCK) {
471 force_result = -EAGAIN;
472 }
473 }
474 out_trace->push_back(
475 Event::GetRandom(/*length=*/regs.args[1], /*flags=*/regs.args[2]));
476 break;
477
478 case __NR_openat:
479 #if defined(OPENSSL_X86_64)
480 case __NR_open:
481 #endif
482 {
483 // It's assumed that any arguments to open(2) are constants in read-only
484 // memory and thus the pointer in the child's context will also be a
485 // valid pointer in our address space.
486 const char *filename = reinterpret_cast<const char *>(
487 (regs.syscall == __NR_openat) ? regs.args[1] : regs.args[0]);
488 out_trace->push_back(Event::Open(filename));
489 is_opening_urandom = strcmp(filename, "/dev/urandom") == 0;
490 if (is_opening_urandom && (flags & NO_URANDOM)) {
491 force_result = -ENOENT;
492 }
493 break;
494 }
495
496 case __NR_read: {
497 const int read_fd = regs.args[0];
498 if (urandom_fd >= 0 && urandom_fd == read_fd) {
499 out_trace->push_back(Event::UrandomRead(/*length=*/regs.args[2]));
500 if (flags & URANDOM_ERROR) {
501 force_result = -EINVAL;
502 }
503 } else if (sock_fd >= 0 && sock_fd == read_fd) {
504 uint64_t length = regs.args[2];
505 out_trace->push_back(Event::SocketRead(length));
506 if (flags & SOCKET_READ_ERROR) {
507 force_result = -EINVAL;
508 } else {
509 is_socket_read = true;
510 socket_read_bytes = length;
511
512 if (flags & SOCKET_READ_SHORT) {
513 ASSERT_GT(socket_read_bytes, 0u);
514 socket_read_bytes--;
515 flags &= ~SOCKET_READ_SHORT;
516 }
517 }
518 }
519 break;
520 }
521
522 case __NR_close: {
523 if (sock_fd >= 0 && static_cast<int>(regs.args[0]) == sock_fd) {
524 out_trace->push_back(Event::SocketClose());
525 sock_fd = -1;
526 }
527 break;
528 }
529
530 case __NR_ioctl: {
531 const int ioctl_fd = regs.args[0];
532 if (urandom_fd >= 0 && ioctl_fd == urandom_fd &&
533 regs.args[1] == RNDGETENTCNT) {
534 out_trace->push_back(Event::UrandomIoctl());
535 is_urandom_ioctl = true;
536 ioctl_output_addr = regs.args[2];
537 }
538 break;
539 }
540
541 case __NR_socket: {
542 const int family = regs.args[0];
543 const int type = regs.args[1];
544 if (family == AF_UNIX && type == SOCK_STREAM) {
545 out_trace->push_back(Event::Socket());
546 is_socket_call = true;
547 if (flags & SOCKET_ERROR) {
548 force_result = -EINVAL;
549 }
550 }
551 break;
552 }
553
554 case __NR_connect: {
555 const int connect_fd = regs.args[0];
556 if (sock_fd >= 0 && connect_fd == sock_fd) {
557 out_trace->push_back(Event::Connect());
558 if (flags & CONNECT_ERROR) {
559 force_result = -EINVAL;
560 } else {
561 // The test system might not have an entropy daemon running so
562 // inject a success result.
563 force_result = 0;
564 }
565 }
566
567 break;
568 }
569 }
570
571 if (force_result.has_value()) {
572 ASSERT_TRUE(regs_break_syscall(child_pid, ®s));
573 }
574
575 ASSERT_EQ(0, ptrace(PTRACE_SYSCALL, child_pid, 0, 0));
576 ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
577 // If the system call was exit/exit_group, the process may be terminated
578 // rather than have exited the system call.
579 if (WIFEXITED(status)) {
580 ASSERT_EQ(0, WEXITSTATUS(status));
581 return;
582 }
583
584 // Otherwise the next state must be a system call exit stop. This is
585 // indistinguishable from a system call entry, we just have to keep track
586 // and know that these events happen in pairs.
587 ASSERT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80));
588
589 if (force_result.has_value()) {
590 ASSERT_TRUE(regs_set_ret(child_pid, force_result.value()));
591 } else if (is_opening_urandom) {
592 ASSERT_TRUE(regs_read(®s, child_pid));
593 urandom_fd = regs.ret;
594 } else if (is_socket_call) {
595 ASSERT_TRUE(regs_read(®s, child_pid));
596 sock_fd = regs.ret;
597 } else if (is_urandom_ioctl) {
598 // The result is the number of bits of entropy that the kernel currently
599 // believes that it has. urandom.c waits until 256 bits are ready.
600 int result = 256;
601
602 // If we are simulating urandom not being ready then we have the ioctl
603 // indicate one too few bits of entropy the first time it's queried.
604 if (flags & URANDOM_NOT_READY) {
605 result--;
606 flags &= ~URANDOM_NOT_READY;
607 }
608
609 memcpy_to_remote(child_pid, ioctl_output_addr, &result, sizeof(result));
610 } else if (is_socket_read) {
611 // Simulate a response from the entropy daemon since it might not be
612 // running on the current system.
613 uint8_t entropy[kDaemonWriteLength];
614 ASSERT_LE(socket_read_bytes, sizeof(entropy));
615
616 for (size_t i = 0; i < sizeof(entropy); i++) {
617 entropy[i] = i & 0xff;
618 }
619 memcpy_to_remote(child_pid, regs.args[1], entropy, socket_read_bytes);
620
621 ASSERT_TRUE(regs_set_ret(child_pid, socket_read_bytes));
622 }
623 }
624 }
625
626 // TestFunction is the function that |GetTrace| is asked to trace.
TestFunction()627 static void TestFunction() {
628 uint8_t byte;
629 RAND_bytes(&byte, sizeof(byte));
630 RAND_bytes(&byte, sizeof(byte));
631 }
632
have_fork_detection()633 static bool have_fork_detection() { return CRYPTO_get_fork_generation() != 0; }
634
AppendDaemonEvents(std::vector<Event> * events,unsigned flags)635 static bool AppendDaemonEvents(std::vector<Event> *events, unsigned flags) {
636 events->push_back(Event::Socket());
637 if (flags & SOCKET_ERROR) {
638 return false;
639 }
640
641 bool ret = false;
642 events->push_back(Event::Connect());
643 if (flags & CONNECT_ERROR) {
644 goto out;
645 }
646
647 events->push_back(Event::SocketRead(kDaemonWriteLength));
648 if (flags & SOCKET_READ_ERROR) {
649 goto out;
650 }
651
652 if (flags & SOCKET_READ_SHORT) {
653 events->push_back(Event::SocketRead(1));
654 }
655
656 ret = true;
657
658 out:
659 events->push_back(Event::SocketClose());
660 return ret;
661 }
662
663 // TestFunctionPRNGModel is a model of how the urandom.c code will behave when
664 // |TestFunction| is run. It should return the same trace of events that
665 // |GetTrace| will observe the real code making.
TestFunctionPRNGModel(unsigned flags)666 static std::vector<Event> TestFunctionPRNGModel(unsigned flags) {
667 std::vector<Event> ret;
668 bool urandom_probed = false;
669 bool getrandom_ready = false;
670
671 const bool used_daemon = kUsesDaemon && AppendDaemonEvents(&ret, flags);
672
673 // Probe for getrandom support
674 ret.push_back(Event::GetRandom(1, GRND_NONBLOCK));
675 std::function<void()> wait_for_entropy;
676 std::function<bool(bool, size_t)> sysrand;
677
678 if (flags & NO_GETRANDOM) {
679 ret.push_back(Event::Open("/dev/urandom"));
680 if (flags & NO_URANDOM) {
681 ret.push_back(Event::Abort());
682 return ret;
683 }
684
685 wait_for_entropy = [&ret, &urandom_probed, flags] {
686 if (!kIsFIPS || urandom_probed) {
687 return;
688 }
689
690 // Probe urandom for entropy.
691 ret.push_back(Event::UrandomIoctl());
692 if (flags & URANDOM_NOT_READY) {
693 // If the first attempt doesn't report enough entropy, probe
694 // repeatedly until it does, which will happen with the second attempt.
695 ret.push_back(Event::UrandomIoctl());
696 }
697
698 urandom_probed = true;
699 };
700
701 sysrand = [&ret, &wait_for_entropy, flags](bool block, size_t len) {
702 if (block) {
703 wait_for_entropy();
704 }
705 ret.push_back(Event::UrandomRead(len));
706 if (flags & URANDOM_ERROR) {
707 ret.push_back(Event::Abort());
708 return false;
709 }
710 return true;
711 };
712 } else {
713 if (flags & GETRANDOM_ERROR) {
714 ret.push_back(Event::Abort());
715 return ret;
716 }
717
718 getrandom_ready = (flags & GETRANDOM_NOT_READY) == 0;
719 wait_for_entropy = [&ret, &getrandom_ready] {
720 if (getrandom_ready) {
721 return;
722 }
723
724 ret.push_back(Event::GetRandom(1, GRND_NONBLOCK));
725 ret.push_back(Event::GetRandom(1, 0));
726 getrandom_ready = true;
727 };
728 sysrand = [&ret, &wait_for_entropy](bool block, size_t len) {
729 if (block) {
730 wait_for_entropy();
731 }
732 ret.push_back(Event::GetRandom(len, block ? 0 : GRND_NONBLOCK));
733 return true;
734 };
735 }
736
737 const size_t kSeedLength = CTR_DRBG_ENTROPY_LEN * (kIsFIPS ? 10 : 1);
738 const size_t kAdditionalDataLength = 32;
739
740 if (!have_rdrand()) {
741 if ((!have_fork_detection() && !sysrand(true, kAdditionalDataLength)) ||
742 // Initialise CRNGT.
743 (!used_daemon && !sysrand(true, kSeedLength + (kIsFIPS ? 16 : 0))) ||
744 // Personalisation draw if the daemon was used.
745 (used_daemon && !sysrand(false, CTR_DRBG_ENTROPY_LEN)) ||
746 // Second entropy draw.
747 (!have_fork_detection() && !sysrand(true, kAdditionalDataLength))) {
748 return ret;
749 }
750 } else if (
751 // First additional data. If fast RDRAND isn't available then a
752 // non-blocking OS entropy draw will be tried.
753 (!have_fast_rdrand() && !have_fork_detection() &&
754 !sysrand(false, kAdditionalDataLength)) ||
755 // Opportuntistic entropy draw in FIPS mode because RDRAND was used.
756 // In non-FIPS mode it's just drawn from |CRYPTO_sysrand| in a blocking
757 // way.
758 !sysrand(!kIsFIPS, CTR_DRBG_ENTROPY_LEN) ||
759 // Second entropy draw's additional data.
760 (!have_fast_rdrand() && !have_fork_detection() &&
761 !sysrand(false, kAdditionalDataLength))) {
762 return ret;
763 }
764
765 return ret;
766 }
767
CheckInvariants(const std::vector<Event> & events)768 static void CheckInvariants(const std::vector<Event> &events) {
769 // If RDRAND is available then there should be no blocking syscalls in FIPS
770 // mode.
771 #if defined(BORINGSSL_FIPS)
772 if (have_rdrand()) {
773 for (const auto &event : events) {
774 switch (event.type) {
775 case Event::Syscall::kGetRandom:
776 if ((event.flags & GRND_NONBLOCK) == 0) {
777 ADD_FAILURE() << "Blocking getrandom found with RDRAND: "
778 << ToString(events);
779 }
780 break;
781
782 case Event::Syscall::kUrandomIoctl:
783 ADD_FAILURE() << "Urandom polling found with RDRAND: "
784 << ToString(events);
785 break;
786
787 default:
788 break;
789 }
790 }
791 }
792 #endif
793 }
794
795 // Tests that |TestFunctionPRNGModel| is a correct model for the code in
796 // urandom.c, at least to the limits of the the |Event| type.
TEST(URandomTest,Test)797 TEST(URandomTest, Test) {
798 char buf[256];
799
800 #define TRACE_FLAG(flag) \
801 snprintf(buf, sizeof(buf), #flag ": %d", (flags & flag) != 0); \
802 SCOPED_TRACE(buf);
803
804 for (unsigned flags = 0; flags < NEXT_FLAG; flags++) {
805 if (!kUsesDaemon && (flags & (SOCKET_ERROR | CONNECT_ERROR |
806 SOCKET_READ_ERROR | SOCKET_READ_SHORT))) {
807 // These cases are meaningless unless the code will try to use the entropy
808 // daemon.
809 continue;
810 }
811
812 TRACE_FLAG(NO_GETRANDOM);
813 TRACE_FLAG(NO_URANDOM);
814 TRACE_FLAG(GETRANDOM_NOT_READY);
815 TRACE_FLAG(URANDOM_NOT_READY);
816 TRACE_FLAG(GETRANDOM_ERROR);
817 TRACE_FLAG(URANDOM_ERROR);
818 TRACE_FLAG(SOCKET_ERROR);
819 TRACE_FLAG(CONNECT_ERROR);
820 TRACE_FLAG(SOCKET_READ_ERROR);
821 TRACE_FLAG(SOCKET_READ_SHORT);
822
823 const std::vector<Event> expected_trace = TestFunctionPRNGModel(flags);
824 CheckInvariants(expected_trace);
825 std::vector<Event> actual_trace;
826 GetTrace(&actual_trace, flags, TestFunction);
827
828 if (expected_trace != actual_trace) {
829 ADD_FAILURE() << "Expected: " << ToString(expected_trace)
830 << "\nFound: " << ToString(actual_trace);
831 }
832 }
833 }
834
main(int argc,char ** argv)835 int main(int argc, char **argv) {
836 ::testing::InitGoogleTest(&argc, argv);
837
838 if (getenv("BORINGSSL_IGNORE_MADV_WIPEONFORK")) {
839 CRYPTO_fork_detect_ignore_madv_wipeonfork_for_testing();
840 }
841
842 return RUN_ALL_TESTS();
843 }
844
845 #else
846
main(int argc,char ** argv)847 int main(int argc, char **argv) {
848 printf("PASS\n");
849 return 0;
850 }
851
852 #endif // (X86_64 || AARCH64) && !SHARED_LIBRARY &&
853 // !UNSAFE_DETERMINISTIC_MODE && USE_NR_getrandom
854