You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

248 line
7.3 KiB

  1. /* Copyright (c) 2014, 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. #include <openssl/rand.h>
  15. #if !defined(OPENSSL_WINDOWS)
  16. #include <assert.h>
  17. #include <errno.h>
  18. #include <fcntl.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <openssl/thread.h>
  22. #include <openssl/mem.h>
  23. #include "internal.h"
  24. #include "../internal.h"
  25. /* This file implements a PRNG by reading from /dev/urandom, optionally with a
  26. * fork-safe buffer.
  27. *
  28. * If buffering is enabled then it maintains a global, linked list of buffers.
  29. * Threads which need random bytes grab a buffer from the list under a lock and
  30. * copy out the bytes that they need. In the rare case that the buffer is
  31. * empty, it's refilled from /dev/urandom outside of the lock.
  32. *
  33. * Large requests are always serviced from /dev/urandom directly.
  34. *
  35. * Each buffer contains the PID of the process that created it and it's tested
  36. * against the current PID each time. Thus processes that fork will discard all
  37. * the buffers filled by the parent process. There are two problems with this:
  38. *
  39. * 1) glibc maintains a cache of the current PID+PPID and, if this cache isn't
  40. * correctly invalidated, the getpid() will continue to believe that
  41. * it's the old process. Glibc depends on the glibc wrappers for fork,
  42. * vfork and clone being used in order to invalidate the getpid() cache.
  43. *
  44. * 2) If a process forks, dies and then its child forks, it's possible that
  45. * the third process will end up with the same PID as the original process.
  46. * If the second process never used any random values then this will mean
  47. * that the third process has stale, cached values and won't notice.
  48. */
  49. /* BUF_SIZE is intended to be a 4K allocation with malloc overhead. struct
  50. * rand_buffer also fits in this space and the remainder is entropy. */
  51. #define BUF_SIZE (4096 - 16)
  52. /* rand_buffer contains unused, random bytes. These structures form a linked
  53. * list via the |next| pointer, which is NULL in the final element. */
  54. struct rand_buffer {
  55. size_t used; /* used contains the number of bytes of |rand| that have
  56. been consumed. */
  57. struct rand_buffer *next;
  58. pid_t pid; /* pid contains the pid at the time that the buffer was
  59. created so that data is not duplicated after a fork. */
  60. pid_t ppid; /* ppid contains the parent pid in order to try and reduce
  61. the possibility of duplicated PID confusing the
  62. detection of a fork. */
  63. uint8_t rand[];
  64. };
  65. /* rand_bytes_per_buf is the number of actual entropy bytes in a buffer. */
  66. static const size_t rand_bytes_per_buf = BUF_SIZE - sizeof(struct rand_buffer);
  67. static struct CRYPTO_STATIC_MUTEX global_lock = CRYPTO_STATIC_MUTEX_INIT;
  68. /* list_head is the start of a global, linked-list of rand_buffer objects. It's
  69. * protected by |global_lock|. */
  70. static struct rand_buffer *list_head;
  71. /* urandom_fd is a file descriptor to /dev/urandom. It's protected by
  72. * |global_lock|. */
  73. static int urandom_fd = -2;
  74. /* urandom_buffering controls whether buffering is enabled (1) or not (0). This
  75. * is protected by |global_lock|. */
  76. static int urandom_buffering = 0;
  77. /* urandom_get_fd_locked returns a file descriptor to /dev/urandom. The caller
  78. * of this function must hold |global_lock|. */
  79. static int urandom_get_fd_locked(void) {
  80. if (urandom_fd != -2) {
  81. return urandom_fd;
  82. }
  83. urandom_fd = open("/dev/urandom", O_RDONLY);
  84. return urandom_fd;
  85. }
  86. /* RAND_cleanup frees all buffers, closes any cached file descriptor
  87. * and resets the global state. */
  88. void RAND_cleanup(void) {
  89. struct rand_buffer *cur;
  90. CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
  91. while ((cur = list_head)) {
  92. list_head = cur->next;
  93. OPENSSL_free(cur);
  94. }
  95. if (urandom_fd >= 0) {
  96. close(urandom_fd);
  97. }
  98. urandom_fd = -2;
  99. list_head = NULL;
  100. CRYPTO_STATIC_MUTEX_unlock(&global_lock);
  101. }
  102. /* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In
  103. * the case of an error it returns 0. */
  104. static char read_full(int fd, uint8_t *out, size_t len) {
  105. ssize_t r;
  106. while (len > 0) {
  107. do {
  108. r = read(fd, out, len);
  109. } while (r == -1 && errno == EINTR);
  110. if (r <= 0) {
  111. return 0;
  112. }
  113. out += r;
  114. len -= r;
  115. }
  116. return 1;
  117. }
  118. /* CRYPTO_sysrand puts |num| random bytes into |out|. */
  119. void CRYPTO_sysrand(uint8_t *out, size_t requested) {
  120. int fd;
  121. struct rand_buffer *buf;
  122. size_t todo;
  123. pid_t pid, ppid;
  124. if (requested == 0) {
  125. return;
  126. }
  127. CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
  128. fd = urandom_get_fd_locked();
  129. if (fd < 0) {
  130. CRYPTO_STATIC_MUTEX_unlock(&global_lock);
  131. abort();
  132. return;
  133. }
  134. /* If buffering is not enabled, or if the request is large, then the
  135. * result comes directly from urandom. */
  136. if (!urandom_buffering || requested > BUF_SIZE / 2) {
  137. CRYPTO_STATIC_MUTEX_unlock(&global_lock);
  138. if (!read_full(fd, out, requested)) {
  139. abort();
  140. }
  141. return;
  142. }
  143. pid = getpid();
  144. ppid = getppid();
  145. for (;;) {
  146. buf = list_head;
  147. if (buf && buf->pid == pid && buf->ppid == ppid &&
  148. rand_bytes_per_buf - buf->used >= requested) {
  149. memcpy(out, &buf->rand[buf->used], requested);
  150. buf->used += requested;
  151. CRYPTO_STATIC_MUTEX_unlock(&global_lock);
  152. return;
  153. }
  154. /* If we don't immediately have enough entropy with the correct
  155. * PID, remove the buffer from the list in order to gain
  156. * exclusive access and unlock. */
  157. if (buf) {
  158. list_head = buf->next;
  159. }
  160. CRYPTO_STATIC_MUTEX_unlock(&global_lock);
  161. if (!buf) {
  162. buf = (struct rand_buffer *)OPENSSL_malloc(BUF_SIZE);
  163. if (!buf) {
  164. abort();
  165. return;
  166. }
  167. /* The buffer doesn't contain any random bytes yet
  168. * so we mark it as fully used so that it will be
  169. * filled below. */
  170. buf->used = rand_bytes_per_buf;
  171. buf->next = NULL;
  172. buf->pid = pid;
  173. buf->ppid = ppid;
  174. }
  175. if (buf->pid == pid && buf->ppid == ppid) {
  176. break;
  177. }
  178. /* We have forked and so cannot use these bytes as they
  179. * may have been used in another process. */
  180. OPENSSL_free(buf);
  181. CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
  182. }
  183. while (requested > 0) {
  184. todo = rand_bytes_per_buf - buf->used;
  185. if (todo > requested) {
  186. todo = requested;
  187. }
  188. memcpy(out, &buf->rand[buf->used], todo);
  189. requested -= todo;
  190. out += todo;
  191. buf->used += todo;
  192. if (buf->used < rand_bytes_per_buf) {
  193. break;
  194. }
  195. if (!read_full(fd, buf->rand, rand_bytes_per_buf)) {
  196. OPENSSL_free(buf);
  197. abort();
  198. return;
  199. }
  200. buf->used = 0;
  201. }
  202. CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
  203. assert(list_head != buf);
  204. buf->next = list_head;
  205. list_head = buf;
  206. CRYPTO_STATIC_MUTEX_unlock(&global_lock);
  207. }
  208. #endif /* !OPENSSL_WINDOWS */