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