lj_prng.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. ** Pseudo-random number generation.
  3. ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
  4. */
  5. #define lj_prng_c
  6. #define LUA_CORE
  7. /* To get the syscall prototype. */
  8. #if defined(__linux__) && !defined(_GNU_SOURCE)
  9. #define _GNU_SOURCE
  10. #endif
  11. #include "lj_def.h"
  12. #include "lj_arch.h"
  13. #include "lj_prng.h"
  14. /* -- PRNG step function -------------------------------------------------- */
  15. /* This implements a Tausworthe PRNG with period 2^223. Based on:
  16. ** Tables of maximally-equidistributed combined LFSR generators,
  17. ** Pierre L'Ecuyer, 1991, table 3, 1st entry.
  18. ** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
  19. **
  20. ** Important note: This PRNG is NOT suitable for cryptographic use!
  21. **
  22. ** But it works fine for math.random(), which has an API that's not
  23. ** suitable for cryptography, anyway.
  24. **
  25. ** When used as a securely seeded global PRNG, it substantially raises
  26. ** the difficulty for various attacks on the VM.
  27. */
  28. /* Update generator i and compute a running xor of all states. */
  29. #define TW223_GEN(rs, z, r, i, k, q, s) \
  30. z = rs->u[i]; \
  31. z = (((z<<q)^z) >> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<<s); \
  32. r ^= z; rs->u[i] = z;
  33. #define TW223_STEP(rs, z, r) \
  34. TW223_GEN(rs, z, r, 0, 63, 31, 18) \
  35. TW223_GEN(rs, z, r, 1, 58, 19, 28) \
  36. TW223_GEN(rs, z, r, 2, 55, 24, 7) \
  37. TW223_GEN(rs, z, r, 3, 47, 21, 8)
  38. /* PRNG step function with uint64_t result. */
  39. LJ_NOINLINE uint64_t LJ_FASTCALL lj_prng_u64(PRNGState *rs)
  40. {
  41. uint64_t z, r = 0;
  42. TW223_STEP(rs, z, r)
  43. return r;
  44. }
  45. /* PRNG step function with double in uint64_t result. */
  46. LJ_NOINLINE uint64_t LJ_FASTCALL lj_prng_u64d(PRNGState *rs)
  47. {
  48. uint64_t z, r = 0;
  49. TW223_STEP(rs, z, r)
  50. /* Returns a double bit pattern in the range 1.0 <= d < 2.0. */
  51. return (r & U64x(000fffff,ffffffff)) | U64x(3ff00000,00000000);
  52. }
  53. /* Condition seed: ensure k[i] MSB of u[i] are non-zero. */
  54. static LJ_AINLINE void lj_prng_condition(PRNGState *rs)
  55. {
  56. if (rs->u[0] < (1u << 1)) rs->u[0] += (1u << 1);
  57. if (rs->u[1] < (1u << 6)) rs->u[1] += (1u << 6);
  58. if (rs->u[2] < (1u << 9)) rs->u[2] += (1u << 9);
  59. if (rs->u[3] < (1u << 17)) rs->u[3] += (1u << 17);
  60. }
  61. /* -- PRNG seeding from OS ------------------------------------------------ */
  62. #if LUAJIT_SECURITY_PRNG == 0
  63. /* Nothing to define. */
  64. #elif LJ_TARGET_XBOX360
  65. extern int XNetRandom(void *buf, unsigned int len);
  66. #elif LJ_TARGET_PS3
  67. extern int sys_get_random_number(void *buf, uint64_t len);
  68. #elif LJ_TARGET_PS4 || LJ_TARGET_PS5 || LJ_TARGET_PSVITA
  69. extern int sceRandomGetRandomNumber(void *buf, size_t len);
  70. #elif LJ_TARGET_NX
  71. #include <unistd.h>
  72. #elif LJ_TARGET_WINDOWS || LJ_TARGET_XBOXONE
  73. #define WIN32_LEAN_AND_MEAN
  74. #include <windows.h>
  75. #if LJ_TARGET_UWP || LJ_TARGET_XBOXONE
  76. /* Must use BCryptGenRandom. */
  77. #include <bcrypt.h>
  78. #pragma comment(lib, "bcrypt.lib")
  79. #else
  80. /* If you wonder about this mess, then search online for RtlGenRandom. */
  81. typedef BOOLEAN (WINAPI *PRGR)(void *buf, ULONG len);
  82. static PRGR libfunc_rgr;
  83. #endif
  84. #elif LJ_TARGET_POSIX
  85. #if LJ_TARGET_LINUX
  86. /* Avoid a dependency on glibc 2.25+ and use the getrandom syscall instead. */
  87. #include <sys/syscall.h>
  88. #else
  89. #if LJ_TARGET_OSX && !LJ_TARGET_IOS
  90. /*
  91. ** In their infinite wisdom Apple decided to disallow getentropy() in the
  92. ** iOS App Store. Even though the call is common to all BSD-ish OS, it's
  93. ** recommended by Apple in their own security-related docs, and, to top
  94. ** off the foolery, /dev/urandom is handled by the same kernel code,
  95. ** yet accessing it is actually permitted (but less efficient).
  96. */
  97. #include <Availability.h>
  98. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
  99. #define LJ_TARGET_HAS_GETENTROPY 1
  100. #endif
  101. #elif (LJ_TARGET_BSD && !defined(__NetBSD__)) || LJ_TARGET_SOLARIS || LJ_TARGET_CYGWIN || LJ_TARGET_QNX
  102. #define LJ_TARGET_HAS_GETENTROPY 1
  103. #endif
  104. #if LJ_TARGET_HAS_GETENTROPY
  105. extern int getentropy(void *buf, size_t len)
  106. #ifdef __ELF__
  107. __attribute__((weak))
  108. #endif
  109. ;
  110. #endif
  111. #endif
  112. /* For the /dev/urandom fallback. */
  113. #include <fcntl.h>
  114. #include <unistd.h>
  115. #endif
  116. #if LUAJIT_SECURITY_PRNG == 0
  117. /* If you really don't care about security, then define
  118. ** LUAJIT_SECURITY_PRNG=0. This yields a predictable seed
  119. ** and provides NO SECURITY against various attacks on the VM.
  120. **
  121. ** BTW: This is NOT the way to get predictable table iteration,
  122. ** predictable trace generation, predictable bytecode generation, etc.
  123. */
  124. int LJ_FASTCALL lj_prng_seed_secure(PRNGState *rs)
  125. {
  126. lj_prng_seed_fixed(rs); /* The fixed seed is already conditioned. */
  127. return 1;
  128. }
  129. #else
  130. /* Securely seed PRNG from system entropy. Returns 0 on failure. */
  131. int LJ_FASTCALL lj_prng_seed_secure(PRNGState *rs)
  132. {
  133. #if LJ_TARGET_XBOX360
  134. if (XNetRandom(rs->u, (unsigned int)sizeof(rs->u)) == 0)
  135. goto ok;
  136. #elif LJ_TARGET_PS3
  137. if (sys_get_random_number(rs->u, sizeof(rs->u)) == 0)
  138. goto ok;
  139. #elif LJ_TARGET_PS4 || LJ_TARGET_PS5 || LJ_TARGET_PSVITA
  140. if (sceRandomGetRandomNumber(rs->u, sizeof(rs->u)) == 0)
  141. goto ok;
  142. #elif LJ_TARGET_NX
  143. if (getentropy(rs->u, sizeof(rs->u)) == 0)
  144. goto ok;
  145. #elif LJ_TARGET_UWP || LJ_TARGET_XBOXONE
  146. if (BCryptGenRandom(NULL, (PUCHAR)(rs->u), (ULONG)sizeof(rs->u),
  147. BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0)
  148. goto ok;
  149. #elif LJ_TARGET_WINDOWS
  150. /* Keep the library loaded in case multiple VMs are started. */
  151. if (!libfunc_rgr) {
  152. HMODULE lib = LJ_WIN_LOADLIBA("advapi32.dll");
  153. if (!lib) return 0;
  154. libfunc_rgr = (PRGR)GetProcAddress(lib, "SystemFunction036");
  155. if (!libfunc_rgr) return 0;
  156. }
  157. if (libfunc_rgr(rs->u, (ULONG)sizeof(rs->u)))
  158. goto ok;
  159. #elif LJ_TARGET_POSIX
  160. #if LJ_TARGET_LINUX && defined(SYS_getrandom)
  161. if (syscall(SYS_getrandom, rs->u, sizeof(rs->u), 0) == (long)sizeof(rs->u))
  162. goto ok;
  163. #elif LJ_TARGET_HAS_GETENTROPY
  164. #ifdef __ELF__
  165. if (&getentropy && getentropy(rs->u, sizeof(rs->u)) == 0)
  166. goto ok;
  167. #else
  168. if (getentropy(rs->u, sizeof(rs->u)) == 0)
  169. goto ok;
  170. #endif
  171. #endif
  172. /* Fallback to /dev/urandom. This may fail if the device is not
  173. ** existent or accessible in a chroot or container, or if the process
  174. ** or the OS ran out of file descriptors.
  175. */
  176. {
  177. int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC);
  178. if (fd != -1) {
  179. ssize_t n = read(fd, rs->u, sizeof(rs->u));
  180. (void)close(fd);
  181. if (n == (ssize_t)sizeof(rs->u))
  182. goto ok;
  183. }
  184. }
  185. #else
  186. /* Add an elif above for your OS with a secure PRNG seed.
  187. ** Note that fiddling around with rand(), getpid(), time() or coercing
  188. ** ASLR to yield a few bits of randomness is not helpful.
  189. ** If you don't want any security, then don't pretend you have any
  190. ** and simply define LUAJIT_SECURITY_PRNG=0 for the build.
  191. */
  192. #error "Missing secure PRNG seed for this OS"
  193. #endif
  194. return 0; /* Fail. */
  195. ok:
  196. lj_prng_condition(rs);
  197. (void)lj_prng_u64(rs);
  198. return 1; /* Success. */
  199. }
  200. #endif