• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&regs, child_pid)) {
257     return false;
258   }
259   regs.regs.rax = ret;
260   return ptrace(PTRACE_SETREGS, child_pid, nullptr, &regs.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(&regs, &orig_regs->regs, sizeof(regs));
269   regs.rdi = -1;
270   return ptrace(PTRACE_SETREGS, child_pid, nullptr, &regs) == 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(&regs, child_pid) && regs_set(child_pid, &regs, 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(&regs, 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, &regs));
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(&regs, child_pid));
593       urandom_fd = regs.ret;
594     } else if (is_socket_call) {
595       ASSERT_TRUE(regs_read(&regs, 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