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