randombytes_sysrandom.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <limits.h>
  5. #include <stdint.h>
  6. #include <string.h>
  7. #ifndef _WIN32
  8. # include <unistd.h>
  9. #endif
  10. #include <stdlib.h>
  11. #include <sys/types.h>
  12. #ifndef _WIN32
  13. # include <sys/stat.h>
  14. # include <sys/time.h>
  15. #endif
  16. #ifdef __linux__
  17. # define _LINUX_SOURCE
  18. #endif
  19. #ifdef HAVE_SYS_RANDOM_H
  20. # include <sys/random.h>
  21. #endif
  22. #ifdef __linux__
  23. # ifdef HAVE_GETRANDOM
  24. # define HAVE_LINUX_COMPATIBLE_GETRANDOM
  25. # else
  26. # include <sys/syscall.h>
  27. # if defined(SYS_getrandom) && defined(__NR_getrandom)
  28. # define getrandom(B, S, F) syscall(SYS_getrandom, (B), (int) (S), (F))
  29. # define HAVE_LINUX_COMPATIBLE_GETRANDOM
  30. # endif
  31. # endif
  32. #elif defined(__FreeBSD__) || defined(__DragonFly__)
  33. # include <sys/param.h>
  34. # if (defined(__FreeBSD_version) && __FreeBSD_version >= 1200000) || \
  35. (defined(__DragonFly_version) && __DragonFly_version >= 500700)
  36. # define HAVE_LINUX_COMPATIBLE_GETRANDOM
  37. # endif
  38. #endif
  39. #if !defined(NO_BLOCKING_RANDOM_POLL) && defined(__linux__)
  40. # define BLOCK_ON_DEV_RANDOM
  41. #endif
  42. #ifdef BLOCK_ON_DEV_RANDOM
  43. # include <poll.h>
  44. #endif
  45. #include "core.h"
  46. #include "private/common.h"
  47. #include "randombytes.h"
  48. #include "randombytes_sysrandom.h"
  49. #include "utils.h"
  50. #ifdef _WIN32
  51. /* `RtlGenRandom` is used over `CryptGenRandom` on Microsoft Windows based systems:
  52. * - `CryptGenRandom` requires pulling in `CryptoAPI` which causes unnecessary
  53. * memory overhead if this API is not being used for other purposes
  54. * - `RtlGenRandom` is thus called directly instead. A detailed explanation
  55. * can be found here: https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/
  56. *
  57. * In spite of the disclaimer on the `RtlGenRandom` documentation page that was
  58. * written back in the Windows XP days, this function is here to stay. The CRT
  59. * function `rand_s()` directly depends on it, so touching it would break many
  60. * applications released since Windows XP.
  61. *
  62. * Also note that Rust, Firefox and BoringSSL (thus, Google Chrome and everything
  63. * based on Chromium) also depend on it, and that libsodium allows the RNG to be
  64. * replaced without patching nor recompiling the library.
  65. */
  66. # include <windows.h>
  67. # define RtlGenRandom SystemFunction036
  68. # if defined(__cplusplus)
  69. extern "C"
  70. # endif
  71. BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
  72. # pragma comment(lib, "advapi32.lib")
  73. #endif
  74. #if defined(__OpenBSD__) || defined(__CloudABI__) || defined(__wasi__)
  75. # define HAVE_SAFE_ARC4RANDOM 1
  76. #endif
  77. #ifndef SSIZE_MAX
  78. # define SSIZE_MAX (SIZE_MAX / 2 - 1)
  79. #endif
  80. #ifdef HAVE_SAFE_ARC4RANDOM
  81. static uint32_t
  82. randombytes_sysrandom(void)
  83. {
  84. return arc4random();
  85. }
  86. static void
  87. randombytes_sysrandom_stir(void)
  88. {
  89. }
  90. static void
  91. randombytes_sysrandom_buf(void * const buf, const size_t size)
  92. {
  93. arc4random_buf(buf, size);
  94. }
  95. static int
  96. randombytes_sysrandom_close(void)
  97. {
  98. return 0;
  99. }
  100. #else /* HAVE_SAFE_ARC4RANDOM */
  101. typedef struct SysRandom_ {
  102. int random_data_source_fd;
  103. int initialized;
  104. int getrandom_available;
  105. } SysRandom;
  106. static SysRandom stream = {
  107. SODIUM_C99(.random_data_source_fd =) -1,
  108. SODIUM_C99(.initialized =) 0,
  109. SODIUM_C99(.getrandom_available =) 0
  110. };
  111. # ifndef _WIN32
  112. static ssize_t
  113. safe_read(const int fd, void * const buf_, size_t size)
  114. {
  115. unsigned char *buf = (unsigned char *) buf_;
  116. ssize_t readnb;
  117. assert(size > (size_t) 0U);
  118. assert(size <= SSIZE_MAX);
  119. do {
  120. while ((readnb = read(fd, buf, size)) < (ssize_t) 0 &&
  121. (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */
  122. if (readnb < (ssize_t) 0) {
  123. return readnb; /* LCOV_EXCL_LINE */
  124. }
  125. if (readnb == (ssize_t) 0) {
  126. break; /* LCOV_EXCL_LINE */
  127. }
  128. size -= (size_t) readnb;
  129. buf += readnb;
  130. } while (size > (ssize_t) 0);
  131. return (ssize_t) (buf - (unsigned char *) buf_);
  132. }
  133. # ifdef BLOCK_ON_DEV_RANDOM
  134. static int
  135. randombytes_block_on_dev_random(void)
  136. {
  137. struct pollfd pfd;
  138. int fd;
  139. int pret;
  140. fd = open("/dev/random", O_RDONLY);
  141. if (fd == -1) {
  142. return 0;
  143. }
  144. pfd.fd = fd;
  145. pfd.events = POLLIN;
  146. pfd.revents = 0;
  147. do {
  148. pret = poll(&pfd, 1, -1);
  149. } while (pret < 0 && (errno == EINTR || errno == EAGAIN));
  150. if (pret != 1) {
  151. (void) close(fd);
  152. errno = EIO;
  153. return -1;
  154. }
  155. return close(fd);
  156. }
  157. # endif /* BLOCK_ON_DEV_RANDOM */
  158. static int
  159. randombytes_sysrandom_random_dev_open(void)
  160. {
  161. /* LCOV_EXCL_START */
  162. struct stat st;
  163. static const char *devices[] = {
  164. # ifndef USE_BLOCKING_RANDOM
  165. "/dev/urandom",
  166. # endif
  167. "/dev/random", NULL
  168. };
  169. const char **device = devices;
  170. int fd;
  171. # ifdef BLOCK_ON_DEV_RANDOM
  172. if (randombytes_block_on_dev_random() != 0) {
  173. return -1;
  174. }
  175. # endif
  176. do {
  177. fd = open(*device, O_RDONLY);
  178. if (fd != -1) {
  179. if (fstat(fd, &st) == 0 &&
  180. # ifdef __COMPCERT__
  181. 1
  182. # elif defined(S_ISNAM)
  183. (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))
  184. # else
  185. S_ISCHR(st.st_mode)
  186. # endif
  187. ) {
  188. # if defined(F_SETFD) && defined(FD_CLOEXEC)
  189. (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
  190. # endif
  191. return fd;
  192. }
  193. (void) close(fd);
  194. } else if (errno == EINTR) {
  195. continue;
  196. }
  197. device++;
  198. } while (*device != NULL);
  199. errno = EIO;
  200. return -1;
  201. /* LCOV_EXCL_STOP */
  202. }
  203. # ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM
  204. static int
  205. _randombytes_linux_getrandom(void * const buf, const size_t size)
  206. {
  207. int readnb;
  208. assert(size <= 256U);
  209. do {
  210. readnb = getrandom(buf, size, 0);
  211. } while (readnb < 0 && (errno == EINTR || errno == EAGAIN));
  212. return (readnb == (int) size) - 1;
  213. }
  214. static int
  215. randombytes_linux_getrandom(void * const buf_, size_t size)
  216. {
  217. unsigned char *buf = (unsigned char *) buf_;
  218. size_t chunk_size = 256U;
  219. do {
  220. if (size < chunk_size) {
  221. chunk_size = size;
  222. assert(chunk_size > (size_t) 0U);
  223. }
  224. if (_randombytes_linux_getrandom(buf, chunk_size) != 0) {
  225. return -1;
  226. }
  227. size -= chunk_size;
  228. buf += chunk_size;
  229. } while (size > (size_t) 0U);
  230. return 0;
  231. }
  232. # endif /* HAVE_LINUX_COMPATIBLE_GETRANDOM */
  233. static void
  234. randombytes_sysrandom_init(void)
  235. {
  236. const int errno_save = errno;
  237. # ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM
  238. {
  239. unsigned char fodder[16];
  240. if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) {
  241. stream.getrandom_available = 1;
  242. errno = errno_save;
  243. return;
  244. }
  245. stream.getrandom_available = 0;
  246. }
  247. # endif
  248. if ((stream.random_data_source_fd =
  249. randombytes_sysrandom_random_dev_open()) == -1) {
  250. sodium_misuse(); /* LCOV_EXCL_LINE */
  251. }
  252. errno = errno_save;
  253. }
  254. # else /* _WIN32 */
  255. static void
  256. randombytes_sysrandom_init(void)
  257. {
  258. }
  259. # endif /* _WIN32 */
  260. static void
  261. randombytes_sysrandom_stir(void)
  262. {
  263. if (stream.initialized == 0) {
  264. randombytes_sysrandom_init();
  265. stream.initialized = 1;
  266. }
  267. }
  268. static void
  269. randombytes_sysrandom_stir_if_needed(void)
  270. {
  271. if (stream.initialized == 0) {
  272. randombytes_sysrandom_stir();
  273. }
  274. }
  275. static int
  276. randombytes_sysrandom_close(void)
  277. {
  278. int ret = -1;
  279. # ifndef _WIN32
  280. if (stream.random_data_source_fd != -1 &&
  281. close(stream.random_data_source_fd) == 0) {
  282. stream.random_data_source_fd = -1;
  283. stream.initialized = 0;
  284. ret = 0;
  285. }
  286. # ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM
  287. if (stream.getrandom_available != 0) {
  288. ret = 0;
  289. }
  290. # endif
  291. # else /* _WIN32 */
  292. if (stream.initialized != 0) {
  293. stream.initialized = 0;
  294. ret = 0;
  295. }
  296. # endif /* _WIN32 */
  297. return ret;
  298. }
  299. static void
  300. randombytes_sysrandom_buf(void * const buf, const size_t size)
  301. {
  302. randombytes_sysrandom_stir_if_needed();
  303. # if defined(ULLONG_MAX) && defined(SIZE_MAX)
  304. # if SIZE_MAX > ULLONG_MAX
  305. /* coverity[result_independent_of_operands] */
  306. assert(size <= ULLONG_MAX);
  307. # endif
  308. # endif
  309. # ifndef _WIN32
  310. # ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM
  311. if (stream.getrandom_available != 0) {
  312. if (randombytes_linux_getrandom(buf, size) != 0) {
  313. sodium_misuse(); /* LCOV_EXCL_LINE */
  314. }
  315. return;
  316. }
  317. # endif
  318. if (stream.random_data_source_fd == -1 ||
  319. safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) {
  320. sodium_misuse(); /* LCOV_EXCL_LINE */
  321. }
  322. # else /* _WIN32 */
  323. COMPILER_ASSERT(randombytes_BYTES_MAX <= 0xffffffffUL);
  324. if (size > (size_t) 0xffffffffUL) {
  325. sodium_misuse(); /* LCOV_EXCL_LINE */
  326. }
  327. if (! RtlGenRandom((PVOID) buf, (ULONG) size)) {
  328. sodium_misuse(); /* LCOV_EXCL_LINE */
  329. }
  330. # endif /* _WIN32 */
  331. }
  332. static uint32_t
  333. randombytes_sysrandom(void)
  334. {
  335. uint32_t r;
  336. randombytes_sysrandom_buf(&r, sizeof r);
  337. return r;
  338. }
  339. #endif /* HAVE_SAFE_ARC4RANDOM */
  340. static const char *
  341. randombytes_sysrandom_implementation_name(void)
  342. {
  343. return "sysrandom";
  344. }
  345. struct randombytes_implementation randombytes_sysrandom_implementation = {
  346. SODIUM_C99(.implementation_name =) randombytes_sysrandom_implementation_name,
  347. SODIUM_C99(.random =) randombytes_sysrandom,
  348. SODIUM_C99(.stir =) randombytes_sysrandom_stir,
  349. SODIUM_C99(.uniform =) NULL,
  350. SODIUM_C99(.buf =) randombytes_sysrandom_buf,
  351. SODIUM_C99(.close =) randombytes_sysrandom_close
  352. };