2
0
Эх сурвалжийг харах

Use a securely seeded global PRNG for the VM.

It's not 2005 anymore.
Mike Pall 5 жил өмнө
parent
commit
a44f53acf5

+ 2 - 2
src/Makefile

@@ -485,8 +485,8 @@ LJLIB_C= $(LJLIB_O:.o=.c)
 
 
 LJCORE_O= lj_assert.o lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
 LJCORE_O= lj_assert.o lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
 	  lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
 	  lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
-	  lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \
-	  lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o \
+	  lj_prng.o lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o \
+	  lj_strscan.o lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o \
 	  lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
 	  lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
 	  lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
 	  lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
 	  lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
 	  lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \

+ 27 - 23
src/Makefile.dep

@@ -1,6 +1,6 @@
 lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
 lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
  lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \
  lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \
- lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h lj_alloc.h
+ lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h
 lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
 lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
  lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h \
  lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h \
  lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cconv.h \
  lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cconv.h \
@@ -28,7 +28,7 @@ lib_jit.o: lib_jit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
  lj_target.h lj_target_*.h lj_trace.h lj_dispatch.h lj_traceerr.h \
  lj_target.h lj_target_*.h lj_trace.h lj_dispatch.h lj_traceerr.h \
  lj_vm.h lj_vmevent.h lj_lib.h luajit.h lj_libdef.h
  lj_vm.h lj_vmevent.h lj_lib.h luajit.h lj_libdef.h
 lib_math.o: lib_math.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
 lib_math.o: lib_math.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
- lj_def.h lj_arch.h lj_lib.h lj_vm.h lj_libdef.h
+ lj_def.h lj_arch.h lj_lib.h lj_vm.h lj_prng.h lj_libdef.h
 lib_os.o: lib_os.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
 lib_os.o: lib_os.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
  lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_lib.h \
  lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_lib.h \
  lj_libdef.h
  lj_libdef.h
@@ -41,7 +41,8 @@ lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
 lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
 lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
  lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \
  lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \
  lj_tab.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
  lj_tab.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
-lj_alloc.o: lj_alloc.c lj_def.h lua.h luaconf.h lj_arch.h lj_alloc.h
+lj_alloc.o: lj_alloc.c lj_def.h lua.h luaconf.h lj_arch.h lj_alloc.h \
+ lj_prng.h
 lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
 lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
  lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
  lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
  lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
@@ -126,7 +127,7 @@ lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
 lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_buf.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
  lj_buf.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
  lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h \
  lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h \
- lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h
+ lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_prng.h
 lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
 lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h \
  lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h \
  lualib.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h \
  lualib.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h \
@@ -140,7 +141,7 @@ lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
  lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
  lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
 lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_gc.h lj_err.h lj_errmsg.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h \
  lj_gc.h lj_err.h lj_errmsg.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h \
- lj_dispatch.h lj_bc.h lj_traceerr.h lj_vm.h
+ lj_dispatch.h lj_bc.h lj_traceerr.h lj_prng.h lj_vm.h
 lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
 lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_meta.h lj_frame.h \
  lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_meta.h lj_frame.h \
  lj_bc.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h
  lj_bc.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h
@@ -172,11 +173,12 @@ lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \
  lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \
  lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h
  lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h
+lj_prng.o: lj_prng.c lj_def.h lua.h luaconf.h lj_arch.h lj_prng.h
 lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
  lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
  lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \
  lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \
  lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \
  lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \
- lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h
+ lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h lj_prng.h
 lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
 lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
  lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
  lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
  lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
@@ -184,7 +186,8 @@ lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
 lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h \
  lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h \
  lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h \
  lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h \
- lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_alloc.h luajit.h
+ lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_prng.h lj_lex.h \
+ lj_alloc.h luajit.h
 lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
 lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_err.h lj_errmsg.h lj_str.h lj_char.h
  lj_err.h lj_errmsg.h lj_str.h lj_char.h
 lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
@@ -199,7 +202,7 @@ lj_trace.o: lj_trace.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_frame.h lj_bc.h \
  lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_frame.h lj_bc.h \
  lj_state.h lj_ir.h lj_jit.h lj_iropt.h lj_mcode.h lj_trace.h \
  lj_state.h lj_ir.h lj_jit.h lj_iropt.h lj_mcode.h lj_trace.h \
  lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \
  lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \
- lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h
+ lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h lj_prng.h
 lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_gc.h lj_udata.h
  lj_gc.h lj_udata.h
 lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
 lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
@@ -214,21 +217,22 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_assert.c lj_obj.h \
  lj_traceerr.h lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h \
  lj_traceerr.h lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h \
  lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c \
  lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c \
  lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h lj_debug.c \
  lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h lj_debug.c \
- lj_state.c lj_lex.h lj_alloc.h luajit.h lj_dispatch.c lj_ccallback.h \
- lj_profile.h lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c \
- lj_strfmt.c lj_strfmt_num.c lj_api.c lj_profile.c lj_lex.c lualib.h \
- lj_parse.h lj_parse.c lj_bcread.c lj_bcdump.h lj_bcwrite.c lj_load.c \
- lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h \
- lj_ccallback.c lj_target.h lj_target_*.h lj_mcode.h lj_carith.c \
- lj_carith.h lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c \
- lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \
- lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \
- lj_opt_sink.c lj_mcode.c lj_snap.c lj_record.c lj_record.h lj_ffrecord.h \
- lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \
- lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \
- lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \
- lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \
- lib_ffi.c lib_init.c
+ lj_prng.c lj_prng.h lj_state.c lj_lex.h lj_alloc.h luajit.h \
+ lj_dispatch.c lj_ccallback.h lj_profile.h lj_vmevent.c lj_vmevent.h \
+ lj_vmmath.c lj_strscan.c lj_strfmt.c lj_strfmt_num.c lj_api.c \
+ lj_profile.c lj_lex.c lualib.h lj_parse.h lj_parse.c lj_bcread.c \
+ lj_bcdump.h lj_bcwrite.c lj_load.c lj_ctype.c lj_cdata.c lj_cconv.h \
+ lj_cconv.c lj_ccall.c lj_ccall.h lj_ccallback.c lj_target.h \
+ lj_target_*.h lj_mcode.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h \
+ lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c lj_ircall.h lj_iropt.h \
+ lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \
+ lj_opt_loop.c lj_snap.h lj_opt_split.c lj_opt_sink.c lj_mcode.c \
+ lj_snap.c lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \
+ lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h \
+ lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c \
+ lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c \
+ lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c lib_ffi.c \
+ lib_init.c
 luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
 luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
 host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \
 host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \
  lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \
  lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \

+ 2 - 6
src/lib_aux.c

@@ -345,17 +345,13 @@ LUALIB_API lua_State *luaL_newstate(void)
 
 
 #else
 #else
 
 
-#include "lj_alloc.h"
-
 LUALIB_API lua_State *luaL_newstate(void)
 LUALIB_API lua_State *luaL_newstate(void)
 {
 {
   lua_State *L;
   lua_State *L;
-  void *ud = lj_alloc_create();
-  if (ud == NULL) return NULL;
 #if LJ_64 && !LJ_GC64
 #if LJ_64 && !LJ_GC64
-  L = lj_state_newstate(lj_alloc_f, ud);
+  L = lj_state_newstate(LJ_ALLOCF_INTERNAL, NULL);
 #else
 #else
-  L = lua_newstate(lj_alloc_f, ud);
+  L = lua_newstate(LJ_ALLOCF_INTERNAL, NULL);
 #endif
 #endif
   if (L) G(L)->panic = panic;
   if (L) G(L)->panic = panic;
   return L;
   return L;

+ 14 - 39
src/lib_math.c

@@ -15,6 +15,7 @@
 #include "lj_obj.h"
 #include "lj_obj.h"
 #include "lj_lib.h"
 #include "lj_lib.h"
 #include "lj_vm.h"
 #include "lj_vm.h"
+#include "lj_prng.h"
 
 
 /* ------------------------------------------------------------------------ */
 /* ------------------------------------------------------------------------ */
 
 
@@ -105,34 +106,11 @@ LJLIB_PUSH(1e310) LJLIB_SET(huge)
 ** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
 ** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
 */
 */
 
 
-/* PRNG state. */
-struct RandomState {
-  uint64_t gen[4];	/* State of the 4 LFSR generators. */
-  int valid;		/* State is valid. */
-};
-
 /* Union needed for bit-pattern conversion between uint64_t and double. */
 /* Union needed for bit-pattern conversion between uint64_t and double. */
 typedef union { uint64_t u64; double d; } U64double;
 typedef union { uint64_t u64; double d; } U64double;
 
 
-/* Update generator i and compute a running xor of all states. */
-#define TW223_GEN(i, k, q, s) \
-  z = rs->gen[i]; \
-  z = (((z<<q)^z) >> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<<s); \
-  r ^= z; rs->gen[i] = z;
-
-/* PRNG step function. Returns a double in the range 1.0 <= d < 2.0. */
-LJ_NOINLINE uint64_t LJ_FASTCALL lj_math_random_step(RandomState *rs)
-{
-  uint64_t z, r = 0;
-  TW223_GEN(0, 63, 31, 18)
-  TW223_GEN(1, 58, 19, 28)
-  TW223_GEN(2, 55, 24,  7)
-  TW223_GEN(3, 47, 21,  8)
-  return (r & U64x(000fffff,ffffffff)) | U64x(3ff00000,00000000);
-}
-
-/* PRNG initialization function. */
-static void random_init(RandomState *rs, double d)
+/* PRNG seeding function. */
+static void random_seed(PRNGState *rs, double d)
 {
 {
   uint32_t r = 0x11090601;  /* 64-k[i] as four 8 bit constants. */
   uint32_t r = 0x11090601;  /* 64-k[i] as four 8 bit constants. */
   int i;
   int i;
@@ -141,24 +119,22 @@ static void random_init(RandomState *rs, double d)
     uint32_t m = 1u << (r&255);
     uint32_t m = 1u << (r&255);
     r >>= 8;
     r >>= 8;
     u.d = d = d * 3.14159265358979323846 + 2.7182818284590452354;
     u.d = d = d * 3.14159265358979323846 + 2.7182818284590452354;
-    if (u.u64 < m) u.u64 += m;  /* Ensure k[i] MSB of gen[i] are non-zero. */
-    rs->gen[i] = u.u64;
+    if (u.u64 < m) u.u64 += m;  /* Ensure k[i] MSB of u[i] are non-zero. */
+    rs->u[i] = u.u64;
   }
   }
-  rs->valid = 1;
   for (i = 0; i < 10; i++)
   for (i = 0; i < 10; i++)
-    lj_math_random_step(rs);
+    (void)lj_prng_u64(rs);
 }
 }
 
 
 /* PRNG extract function. */
 /* PRNG extract function. */
-LJLIB_PUSH(top-2)  /* Upvalue holds userdata with RandomState. */
+LJLIB_PUSH(top-2)  /* Upvalue holds userdata with PRNGState. */
 LJLIB_CF(math_random)		LJLIB_REC(.)
 LJLIB_CF(math_random)		LJLIB_REC(.)
 {
 {
   int n = (int)(L->top - L->base);
   int n = (int)(L->top - L->base);
-  RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
+  PRNGState *rs = (PRNGState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
   U64double u;
   U64double u;
   double d;
   double d;
-  if (LJ_UNLIKELY(!rs->valid)) random_init(rs, 0.0);
-  u.u64 = lj_math_random_step(rs);
+  u.u64 = lj_prng_u64d(rs);
   d = u.d - 1.0;
   d = u.d - 1.0;
   if (n > 0) {
   if (n > 0) {
 #if LJ_DUALNUM
 #if LJ_DUALNUM
@@ -203,11 +179,11 @@ LJLIB_CF(math_random)		LJLIB_REC(.)
 }
 }
 
 
 /* PRNG seed function. */
 /* PRNG seed function. */
-LJLIB_PUSH(top-2)  /* Upvalue holds userdata with RandomState. */
+LJLIB_PUSH(top-2)  /* Upvalue holds userdata with PRNGState. */
 LJLIB_CF(math_randomseed)
 LJLIB_CF(math_randomseed)
 {
 {
-  RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
-  random_init(rs, lj_lib_checknum(L, 1));
+  PRNGState *rs = (PRNGState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
+  random_seed(rs, lj_lib_checknum(L, 1));
   return 0;
   return 0;
 }
 }
 
 
@@ -217,9 +193,8 @@ LJLIB_CF(math_randomseed)
 
 
 LUALIB_API int luaopen_math(lua_State *L)
 LUALIB_API int luaopen_math(lua_State *L)
 {
 {
-  RandomState *rs;
-  rs = (RandomState *)lua_newuserdata(L, sizeof(RandomState));
-  rs->valid = 0;  /* Use lazy initialization to save some time on startup. */
+  PRNGState *rs = (PRNGState *)lua_newuserdata(L, sizeof(PRNGState));
+  lj_prng_seed_fixed(rs);
   LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
   LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
   return 1;
   return 1;
 }
 }

+ 38 - 45
src/lj_alloc.c

@@ -31,6 +31,7 @@
 #include "lj_def.h"
 #include "lj_def.h"
 #include "lj_arch.h"
 #include "lj_arch.h"
 #include "lj_alloc.h"
 #include "lj_alloc.h"
+#include "lj_prng.h"
 
 
 #ifndef LUAJIT_USE_SYSMALLOC
 #ifndef LUAJIT_USE_SYSMALLOC
 
 
@@ -140,7 +141,7 @@ static void init_mmap(void)
 #define INIT_MMAP()	init_mmap()
 #define INIT_MMAP()	init_mmap()
 
 
 /* Win64 32 bit MMAP via NtAllocateVirtualMemory. */
 /* Win64 32 bit MMAP via NtAllocateVirtualMemory. */
-static void *CALL_MMAP(size_t size)
+static void *mmap_plain(size_t size)
 {
 {
   DWORD olderr = GetLastError();
   DWORD olderr = GetLastError();
   void *ptr = NULL;
   void *ptr = NULL;
@@ -164,7 +165,7 @@ static void *direct_mmap(size_t size)
 #else
 #else
 
 
 /* Win32 MMAP via VirtualAlloc */
 /* Win32 MMAP via VirtualAlloc */
-static void *CALL_MMAP(size_t size)
+static void *mmap_plain(size_t size)
 {
 {
   DWORD olderr = GetLastError();
   DWORD olderr = GetLastError();
   void *ptr = LJ_WIN_VALLOC(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
   void *ptr = LJ_WIN_VALLOC(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
@@ -184,7 +185,8 @@ static void *direct_mmap(size_t size)
 
 
 #endif
 #endif
 
 
-#define DIRECT_MMAP(size)	direct_mmap(size)
+#define CALL_MMAP(prng, size)	mmap_plain(size)
+#define DIRECT_MMAP(prng, size)	direct_mmap(size)
 
 
 /* This function supports releasing coalesed segments */
 /* This function supports releasing coalesed segments */
 static int CALL_MUNMAP(void *ptr, size_t size)
 static int CALL_MUNMAP(void *ptr, size_t size)
@@ -228,30 +230,10 @@ static int CALL_MUNMAP(void *ptr, size_t size)
 
 
 #define LJ_ALLOC_MMAP_PROBE_LOWER	((uintptr_t)0x4000)
 #define LJ_ALLOC_MMAP_PROBE_LOWER	((uintptr_t)0x4000)
 
 
-/* No point in a giant ifdef mess. Just try to open /dev/urandom.
-** It doesn't really matter if this fails, since we get some ASLR bits from
-** every unsuitable allocation, too. And we prefer linear allocation, anyway.
-*/
-#include <fcntl.h>
-#include <unistd.h>
-
-static uintptr_t mmap_probe_seed(void)
-{
-  uintptr_t val;
-  int fd = open("/dev/urandom", O_RDONLY);
-  if (fd != -1) {
-    int ok = ((size_t)read(fd, &val, sizeof(val)) == sizeof(val));
-    (void)close(fd);
-    if (ok) return val;
-  }
-  return 1;  /* Punt. */
-}
-
-static void *mmap_probe(size_t size)
+static void *mmap_probe(PRNGState *rs, size_t size)
 {
 {
   /* Hint for next allocation. Doesn't need to be thread-safe. */
   /* Hint for next allocation. Doesn't need to be thread-safe. */
   static uintptr_t hint_addr = 0;
   static uintptr_t hint_addr = 0;
-  static uintptr_t hint_prng = 0;
   int olderr = errno;
   int olderr = errno;
   int retry;
   int retry;
   for (retry = 0; retry < LJ_ALLOC_MMAP_PROBE_MAX; retry++) {
   for (retry = 0; retry < LJ_ALLOC_MMAP_PROBE_MAX; retry++) {
@@ -283,15 +265,8 @@ static void *mmap_probe(size_t size)
       }
       }
     }
     }
     /* Finally, try pseudo-random probing. */
     /* Finally, try pseudo-random probing. */
-    if (LJ_UNLIKELY(hint_prng == 0)) {
-      hint_prng = mmap_probe_seed();
-    }
-    /* The unsuitable address we got has some ASLR PRNG bits. */
-    hint_addr ^= addr & ~((uintptr_t)(LJ_PAGESIZE-1));
-    do {  /* The PRNG itself is very weak, but see above. */
-      hint_prng = hint_prng * 1103515245 + 12345;
-      hint_addr ^= hint_prng * (uintptr_t)LJ_PAGESIZE;
-      hint_addr &= (((uintptr_t)1 << LJ_ALLOC_MBITS)-1);
+    do {
+      hint_addr = lj_prng_u64(rs) & (((uintptr_t)1<<LJ_ALLOC_MBITS)-LJ_PAGESIZE);
     } while (hint_addr < LJ_ALLOC_MMAP_PROBE_LOWER);
     } while (hint_addr < LJ_ALLOC_MMAP_PROBE_LOWER);
   }
   }
   errno = olderr;
   errno = olderr;
@@ -308,12 +283,16 @@ static void *mmap_probe(size_t size)
 #define LJ_ALLOC_MMAP32_START	((uintptr_t)0)
 #define LJ_ALLOC_MMAP32_START	((uintptr_t)0)
 #endif
 #endif
 
 
+#if LJ_ALLOC_MMAP_PROBE
+static void *mmap_map32(PRNGState *rs, size_t size)
+#else
 static void *mmap_map32(size_t size)
 static void *mmap_map32(size_t size)
+#endif
 {
 {
 #if LJ_ALLOC_MMAP_PROBE
 #if LJ_ALLOC_MMAP_PROBE
   static int fallback = 0;
   static int fallback = 0;
   if (fallback)
   if (fallback)
-    return mmap_probe(size);
+    return mmap_probe(rs, size);
 #endif
 #endif
   {
   {
     int olderr = errno;
     int olderr = errno;
@@ -323,7 +302,7 @@ static void *mmap_map32(size_t size)
 #if LJ_ALLOC_MMAP_PROBE
 #if LJ_ALLOC_MMAP_PROBE
     if (ptr == MFAIL) {
     if (ptr == MFAIL) {
       fallback = 1;
       fallback = 1;
-      return mmap_probe(size);
+      return mmap_probe(rs, size);
     }
     }
 #endif
 #endif
     return ptr;
     return ptr;
@@ -333,17 +312,22 @@ static void *mmap_map32(size_t size)
 #endif
 #endif
 
 
 #if LJ_ALLOC_MMAP32
 #if LJ_ALLOC_MMAP32
-#define CALL_MMAP(size)		mmap_map32(size)
+#if LJ_ALLOC_MMAP_PROBE
+#define CALL_MMAP(prng, size)	mmap_map32(prng, size)
+#else
+#define CALL_MMAP(prng, size)	mmap_map32(size)
+#endif
 #elif LJ_ALLOC_MMAP_PROBE
 #elif LJ_ALLOC_MMAP_PROBE
-#define CALL_MMAP(size)		mmap_probe(size)
+#define CALL_MMAP(prng, size)	mmap_probe(prng, size)
 #else
 #else
-static void *CALL_MMAP(size_t size)
+static void *mmap_plain(size_t size)
 {
 {
   int olderr = errno;
   int olderr = errno;
   void *ptr = mmap(NULL, size, MMAP_PROT, MMAP_FLAGS, -1, 0);
   void *ptr = mmap(NULL, size, MMAP_PROT, MMAP_FLAGS, -1, 0);
   errno = olderr;
   errno = olderr;
   return ptr;
   return ptr;
 }
 }
+#define CALL_MMAP(prng, size)	mmap_plain(size)
 #endif
 #endif
 
 
 #if LJ_64 && !LJ_GC64 && ((defined(__FreeBSD__) && __FreeBSD__ < 10) || defined(__FreeBSD_kernel__)) && !LJ_TARGET_PS4
 #if LJ_64 && !LJ_GC64 && ((defined(__FreeBSD__) && __FreeBSD__ < 10) || defined(__FreeBSD_kernel__)) && !LJ_TARGET_PS4
@@ -396,7 +380,7 @@ static void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, int flags)
 #endif
 #endif
 
 
 #ifndef DIRECT_MMAP
 #ifndef DIRECT_MMAP
-#define DIRECT_MMAP(s)		CALL_MMAP(s)
+#define DIRECT_MMAP(prng, s)	CALL_MMAP(prng, s)
 #endif
 #endif
 
 
 #ifndef CALL_MREMAP
 #ifndef CALL_MREMAP
@@ -555,6 +539,7 @@ struct malloc_state {
   mchunkptr  smallbins[(NSMALLBINS+1)*2];
   mchunkptr  smallbins[(NSMALLBINS+1)*2];
   tbinptr    treebins[NTREEBINS];
   tbinptr    treebins[NTREEBINS];
   msegment   seg;
   msegment   seg;
+  PRNGState  *prng;
 };
 };
 
 
 typedef struct malloc_state *mstate;
 typedef struct malloc_state *mstate;
@@ -837,11 +822,11 @@ static int has_segment_link(mstate m, msegmentptr ss)
 
 
 /* -----------------------  Direct-mmapping chunks ----------------------- */
 /* -----------------------  Direct-mmapping chunks ----------------------- */
 
 
-static void *direct_alloc(size_t nb)
+static void *direct_alloc(mstate m, size_t nb)
 {
 {
   size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
   size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
   if (LJ_LIKELY(mmsize > nb)) {     /* Check for wrap around 0 */
   if (LJ_LIKELY(mmsize > nb)) {     /* Check for wrap around 0 */
-    char *mm = (char *)(DIRECT_MMAP(mmsize));
+    char *mm = (char *)(DIRECT_MMAP(m->prng, mmsize));
     if (mm != CMFAIL) {
     if (mm != CMFAIL) {
       size_t offset = align_offset(chunk2mem(mm));
       size_t offset = align_offset(chunk2mem(mm));
       size_t psize = mmsize - offset - DIRECT_FOOT_PAD;
       size_t psize = mmsize - offset - DIRECT_FOOT_PAD;
@@ -853,6 +838,7 @@ static void *direct_alloc(size_t nb)
       return chunk2mem(p);
       return chunk2mem(p);
     }
     }
   }
   }
+  UNUSED(m);
   return NULL;
   return NULL;
 }
 }
 
 
@@ -1001,7 +987,7 @@ static void *alloc_sys(mstate m, size_t nb)
 
 
   /* Directly map large chunks */
   /* Directly map large chunks */
   if (LJ_UNLIKELY(nb >= DEFAULT_MMAP_THRESHOLD)) {
   if (LJ_UNLIKELY(nb >= DEFAULT_MMAP_THRESHOLD)) {
-    void *mem = direct_alloc(nb);
+    void *mem = direct_alloc(m, nb);
     if (mem != 0)
     if (mem != 0)
       return mem;
       return mem;
   }
   }
@@ -1010,7 +996,7 @@ static void *alloc_sys(mstate m, size_t nb)
     size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;
     size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;
     size_t rsize = granularity_align(req);
     size_t rsize = granularity_align(req);
     if (LJ_LIKELY(rsize > nb)) { /* Fail if wraps around zero */
     if (LJ_LIKELY(rsize > nb)) { /* Fail if wraps around zero */
-      char *mp = (char *)(CALL_MMAP(rsize));
+      char *mp = (char *)(CALL_MMAP(m->prng, rsize));
       if (mp != CMFAIL) {
       if (mp != CMFAIL) {
 	tbase = mp;
 	tbase = mp;
 	tsize = rsize;
 	tsize = rsize;
@@ -1237,12 +1223,13 @@ static void *tmalloc_small(mstate m, size_t nb)
 
 
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 
 
-void *lj_alloc_create(void)
+void *lj_alloc_create(PRNGState *rs)
 {
 {
   size_t tsize = DEFAULT_GRANULARITY;
   size_t tsize = DEFAULT_GRANULARITY;
   char *tbase;
   char *tbase;
   INIT_MMAP();
   INIT_MMAP();
-  tbase = (char *)(CALL_MMAP(tsize));
+  UNUSED(rs);
+  tbase = (char *)(CALL_MMAP(rs, tsize));
   if (tbase != CMFAIL) {
   if (tbase != CMFAIL) {
     size_t msize = pad_request(sizeof(struct malloc_state));
     size_t msize = pad_request(sizeof(struct malloc_state));
     mchunkptr mn;
     mchunkptr mn;
@@ -1261,6 +1248,12 @@ void *lj_alloc_create(void)
   return NULL;
   return NULL;
 }
 }
 
 
+void lj_alloc_setprng(void *msp, PRNGState *rs)
+{
+  mstate ms = (mstate)msp;
+  ms->prng = rs;
+}
+
 void lj_alloc_destroy(void *msp)
 void lj_alloc_destroy(void *msp)
 {
 {
   mstate ms = (mstate)msp;
   mstate ms = (mstate)msp;

+ 2 - 1
src/lj_alloc.h

@@ -9,7 +9,8 @@
 #include "lj_def.h"
 #include "lj_def.h"
 
 
 #ifndef LUAJIT_USE_SYSMALLOC
 #ifndef LUAJIT_USE_SYSMALLOC
-LJ_FUNC void *lj_alloc_create(void);
+LJ_FUNC void *lj_alloc_create(PRNGState *rs);
+LJ_FUNC void lj_alloc_setprng(void *msp, PRNGState *rs);
 LJ_FUNC void lj_alloc_destroy(void *msp);
 LJ_FUNC void lj_alloc_destroy(void *msp);
 LJ_FUNC void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize);
 LJ_FUNC void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize);
 #endif
 #endif

+ 15 - 0
src/lj_arch.h

@@ -633,4 +633,19 @@ extern void *LJ_WIN_LOADLIBA(const char *path);
 #define LJ_52			0
 #define LJ_52			0
 #endif
 #endif
 
 
+/* -- VM security --------------------------------------------------------- */
+
+/* Don't make any changes here. Instead build with:
+**   make "XCFLAGS=-DLUAJIT_SECURITY_flag=value"
+*/
+
+/* Security defaults. */
+#ifndef LUAJIT_SECURITY_PRNG
+#define LUAJIT_SECURITY_PRNG	1
+#endif
+
+#ifndef LUAJIT_SECURITY_MCODE
+#define LUAJIT_SECURITY_MCODE	1
+#endif
+
 #endif
 #endif

+ 5 - 0
src/lj_def.h

@@ -372,4 +372,9 @@ static LJ_AINLINE uint32_t lj_getu32(const void *v)
   extern void LJ_ASSERT_NAME(__LINE__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1])
   extern void LJ_ASSERT_NAME(__LINE__)(int STATIC_ASSERTION_FAILED[(cond)?1:-1])
 #endif
 #endif
 
 
+/* PRNG state. Need this here, details in lj_prng.h. */
+typedef struct PRNGState {
+  uint64_t u[4];
+} PRNGState;
+
 #endif
 #endif

+ 1 - 1
src/lj_ffrecord.c

@@ -616,7 +616,7 @@ static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd)
   GCudata *ud = udataV(&J->fn->c.upvalue[0]);
   GCudata *ud = udataV(&J->fn->c.upvalue[0]);
   TRef tr, one;
   TRef tr, one;
   lj_ir_kgc(J, obj2gco(ud), IRT_UDATA);  /* Prevent collection. */
   lj_ir_kgc(J, obj2gco(ud), IRT_UDATA);  /* Prevent collection. */
-  tr = lj_ir_call(J, IRCALL_lj_math_random_step, lj_ir_kptr(J, uddata(ud)));
+  tr = lj_ir_call(J, IRCALL_lj_prng_u64d, lj_ir_kptr(J, uddata(ud)));
   one = lj_ir_knum_one(J);
   one = lj_ir_knum_one(J);
   tr = emitir(IRTN(IR_SUB), tr, one);
   tr = emitir(IRTN(IR_SUB), tr, one);
   if (J->base[0]) {
   if (J->base[0]) {

+ 1 - 1
src/lj_ir.c

@@ -31,7 +31,7 @@
 #include "lj_vm.h"
 #include "lj_vm.h"
 #include "lj_strscan.h"
 #include "lj_strscan.h"
 #include "lj_strfmt.h"
 #include "lj_strfmt.h"
-#include "lj_lib.h"
+#include "lj_prng.h"
 
 
 /* Some local macros to save typing. Undef'd at the end. */
 /* Some local macros to save typing. Undef'd at the end. */
 #define IR(ref)			(&J->cur.ir[(ref)])
 #define IR(ref)			(&J->cur.ir[(ref)])

+ 1 - 1
src/lj_ircall.h

@@ -172,7 +172,7 @@ typedef struct CCallInfo {
   _(ANY,	lj_gc_step_jit,		2,  FS, NIL, CCI_L) \
   _(ANY,	lj_gc_step_jit,		2,  FS, NIL, CCI_L) \
   _(ANY,	lj_gc_barrieruv,	2,  FS, NIL, 0) \
   _(ANY,	lj_gc_barrieruv,	2,  FS, NIL, 0) \
   _(ANY,	lj_mem_newgco,		2,  FS, PGC, CCI_L) \
   _(ANY,	lj_mem_newgco,		2,  FS, PGC, CCI_L) \
-  _(ANY,	lj_math_random_step, 1, FS, NUM, CCI_CASTU64) \
+  _(ANY,	lj_prng_u64d,		1,  FS, NUM, CCI_CASTU64) \
   _(ANY,	lj_vm_modi,		2,  FN, INT, 0) \
   _(ANY,	lj_vm_modi,		2,  FN, INT, 0) \
   _(ANY,	log10,			1,   N, NUM, XA_FP) \
   _(ANY,	log10,			1,   N, NUM, XA_FP) \
   _(ANY,	exp,			1,   N, NUM, XA_FP) \
   _(ANY,	exp,			1,   N, NUM, XA_FP) \

+ 2 - 11
src/lj_jit.h

@@ -438,9 +438,9 @@ typedef struct jit_State {
   int32_t framedepth;	/* Current frame depth. */
   int32_t framedepth;	/* Current frame depth. */
   int32_t retdepth;	/* Return frame depth (count of RETF). */
   int32_t retdepth;	/* Return frame depth (count of RETF). */
 
 
+  uint32_t k32[LJ_K32__MAX];  /* Common 4 byte constants used by backends. */
   TValue ksimd[LJ_KSIMD__MAX*2+1];  /* 16 byte aligned SIMD constants. */
   TValue ksimd[LJ_KSIMD__MAX*2+1];  /* 16 byte aligned SIMD constants. */
-  TValue k64[LJ_K64__MAX];  /* Common 8 byte constants used by backends. */
-  uint32_t k32[LJ_K32__MAX];  /* Ditto for 4 byte constants. */
+  TValue k64[LJ_K64__MAX];  /* Common 8 byte constants. */
 
 
   IRIns *irbuf;		/* Temp. IR instruction buffer. Biased with REF_BIAS. */
   IRIns *irbuf;		/* Temp. IR instruction buffer. Biased with REF_BIAS. */
   IRRef irtoplim;	/* Upper limit of instuction buffer (biased). */
   IRRef irtoplim;	/* Upper limit of instuction buffer (biased). */
@@ -472,7 +472,6 @@ typedef struct jit_State {
 
 
   HotPenalty penalty[PENALTY_SLOTS];  /* Penalty slots. */
   HotPenalty penalty[PENALTY_SLOTS];  /* Penalty slots. */
   uint32_t penaltyslot;	/* Round-robin index into penalty slots. */
   uint32_t penaltyslot;	/* Round-robin index into penalty slots. */
-  uint32_t prngstate;	/* PRNG state. */
 
 
 #ifdef LUAJIT_ENABLE_TABLE_BUMP
 #ifdef LUAJIT_ENABLE_TABLE_BUMP
   RBCHashEntry rbchash[RBCHASH_SLOTS];  /* Reverse bytecode map. */
   RBCHashEntry rbchash[RBCHASH_SLOTS];  /* Reverse bytecode map. */
@@ -516,12 +515,4 @@ jit_State;
 #define lj_assertJ(c, ...)	((void)J)
 #define lj_assertJ(c, ...)	((void)J)
 #endif
 #endif
 
 
-/* Trivial PRNG e.g. used for penalty randomization. */
-static LJ_AINLINE uint32_t LJ_PRNG_BITS(jit_State *J, int bits)
-{
-  /* Yes, this LCG is very weak, but that doesn't matter for our use case. */
-  J->prngstate = J->prngstate * 1103515245 + 12345;
-  return J->prngstate >> (32-bits);
-}
-
 #endif
 #endif

+ 0 - 5
src/lj_lib.h

@@ -107,9 +107,4 @@ LJ_FUNC int lj_lib_postreg(lua_State *L, lua_CFunction cf, int id,
 #define LIBINIT_FFID	0xfe
 #define LIBINIT_FFID	0xfe
 #define LIBINIT_END	0xff
 #define LIBINIT_END	0xff
 
 
-/* Exported library functions. */
-
-typedef struct RandomState RandomState;
-LJ_FUNC uint64_t LJ_FASTCALL lj_math_random_step(RandomState *rs);
-
 #endif
 #endif

+ 12 - 29
src/lj_mcode.c

@@ -14,6 +14,7 @@
 #include "lj_mcode.h"
 #include "lj_mcode.h"
 #include "lj_trace.h"
 #include "lj_trace.h"
 #include "lj_dispatch.h"
 #include "lj_dispatch.h"
+#include "lj_prng.h"
 #endif
 #endif
 #if LJ_HASJIT || LJ_HASFFI
 #if LJ_HASJIT || LJ_HASFFI
 #include "lj_vm.h"
 #include "lj_vm.h"
@@ -118,52 +119,34 @@ static int mcode_setprot(void *p, size_t sz, int prot)
   return mprotect(p, sz, prot);
   return mprotect(p, sz, prot);
 }
 }
 
 
-#elif LJ_64
-
-#error "Missing OS support for explicit placement of executable memory"
-
 #else
 #else
 
 
-/* Fallback allocator. This will fail if memory is not executable by default. */
-#define LUAJIT_UNPROTECT_MCODE
-#define MCPROT_RW	0
-#define MCPROT_RX	0
-#define MCPROT_RWX	0
-
-static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot)
-{
-  UNUSED(hint); UNUSED(prot);
-  return lj_mem_new(J->L, sz);
-}
-
-static void mcode_free(jit_State *J, void *p, size_t sz)
-{
-  lj_mem_free(J2G(J), p, sz);
-}
+#error "Missing OS support for explicit placement of executable memory"
 
 
 #endif
 #endif
 
 
 /* -- MCode area protection ----------------------------------------------- */
 /* -- MCode area protection ----------------------------------------------- */
 
 
-/* Define this ONLY if page protection twiddling becomes a bottleneck. */
-#ifdef LUAJIT_UNPROTECT_MCODE
+#if LUAJIT_SECURITY_MCODE == 0
 
 
-/* It's generally considered to be a potential security risk to have
+/* Define this ONLY if page protection twiddling becomes a bottleneck.
+**
+** It's generally considered to be a potential security risk to have
 ** pages with simultaneous write *and* execute access in a process.
 ** pages with simultaneous write *and* execute access in a process.
 **
 **
 ** Do not even think about using this mode for server processes or
 ** Do not even think about using this mode for server processes or
-** apps handling untrusted external data (such as a browser).
+** apps handling untrusted external data.
 **
 **
 ** The security risk is not in LuaJIT itself -- but if an adversary finds
 ** The security risk is not in LuaJIT itself -- but if an adversary finds
-** any *other* flaw in your C application logic, then any RWX memory page
-** simplifies writing an exploit considerably.
+** any *other* flaw in your C application logic, then any RWX memory pages
+** simplify writing an exploit considerably.
 */
 */
 #define MCPROT_GEN	MCPROT_RWX
 #define MCPROT_GEN	MCPROT_RWX
 #define MCPROT_RUN	MCPROT_RWX
 #define MCPROT_RUN	MCPROT_RWX
 
 
 static void mcode_protect(jit_State *J, int prot)
 static void mcode_protect(jit_State *J, int prot)
 {
 {
-  UNUSED(J); UNUSED(prot);
+  UNUSED(J); UNUSED(prot); UNUSED(mcode_setprot);
 }
 }
 
 
 #else
 #else
@@ -242,7 +225,7 @@ static void *mcode_alloc(jit_State *J, size_t sz)
     }
     }
     /* Next try probing 64K-aligned pseudo-random addresses. */
     /* Next try probing 64K-aligned pseudo-random addresses. */
     do {
     do {
-      hint = LJ_PRNG_BITS(J, LJ_TARGET_JUMPRANGE-16) << 16;
+      hint = lj_prng_u64(&J2G(J)->prng) & ((1u<<LJ_TARGET_JUMPRANGE)-0x10000);
     } while (!(hint + sz < range+range));
     } while (!(hint + sz < range+range));
     hint = target + hint - range;
     hint = target + hint - range;
   }
   }
@@ -331,7 +314,7 @@ void lj_mcode_abort(jit_State *J)
 /* Set/reset protection to allow patching of MCode areas. */
 /* Set/reset protection to allow patching of MCode areas. */
 MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish)
 MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish)
 {
 {
-#ifdef LUAJIT_UNPROTECT_MCODE
+#if LUAJIT_SECURITY_MCODE == 0
   UNUSED(J); UNUSED(ptr); UNUSED(finish);
   UNUSED(J); UNUSED(ptr); UNUSED(finish);
   return NULL;
   return NULL;
 #else
 #else

+ 1 - 0
src/lj_obj.h

@@ -620,6 +620,7 @@ typedef struct global_State {
   GCRef cur_L;		/* Currently executing lua_State. */
   GCRef cur_L;		/* Currently executing lua_State. */
   MRef jit_base;	/* Current JIT code L->base or NULL. */
   MRef jit_base;	/* Current JIT code L->base or NULL. */
   MRef ctype_state;	/* Pointer to C type state. */
   MRef ctype_state;	/* Pointer to C type state. */
+  PRNGState prng;	/* Global PRNG state. */
   GCRef gcroot[GCROOT_MAX];  /* GC roots. */
   GCRef gcroot[GCROOT_MAX];  /* GC roots. */
 } global_State;
 } global_State;
 
 

+ 225 - 0
src/lj_prng.c

@@ -0,0 +1,225 @@
+/*
+** Pseudo-random number generation.
+** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#define lj_prng_c
+#define LUA_CORE
+
+/* To get the syscall prototype. */
+#if defined(__linux__) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
+#include "lj_def.h"
+#include "lj_arch.h"
+#include "lj_prng.h"
+
+/* -- PRNG step function -------------------------------------------------- */
+
+/* This implements a Tausworthe PRNG with period 2^223. Based on:
+**   Tables of maximally-equidistributed combined LFSR generators,
+**   Pierre L'Ecuyer, 1991, table 3, 1st entry.
+** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
+**
+** Important note: This PRNG is NOT suitable for cryptographic use!
+**
+** But it works fine for math.random(), which has an API that's not
+** suitable for cryptography, anyway.
+**
+** When used as a securely seeded global PRNG, it substantially raises
+** the difficulty for various attacks on the VM.
+*/
+
+/* Update generator i and compute a running xor of all states. */
+#define TW223_GEN(rs, z, r, i, k, q, s) \
+  z = rs->u[i]; \
+  z = (((z<<q)^z) >> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<<s); \
+  r ^= z; rs->u[i] = z;
+
+#define TW223_STEP(rs, z, r) \
+  TW223_GEN(rs, z, r, 0, 63, 31, 18) \
+  TW223_GEN(rs, z, r, 1, 58, 19, 28) \
+  TW223_GEN(rs, z, r, 2, 55, 24,  7) \
+  TW223_GEN(rs, z, r, 3, 47, 21,  8)
+
+/* PRNG step function with uint64_t result. */
+LJ_NOINLINE uint64_t LJ_FASTCALL lj_prng_u64(PRNGState *rs)
+{
+  uint64_t z, r = 0;
+  TW223_STEP(rs, z, r)
+  return r;
+}
+
+/* PRNG step function with double in uint64_t result. */
+LJ_NOINLINE uint64_t LJ_FASTCALL lj_prng_u64d(PRNGState *rs)
+{
+  uint64_t z, r = 0;
+  TW223_STEP(rs, z, r)
+  /* Returns a double bit pattern in the range 1.0 <= d < 2.0. */
+  return (r & U64x(000fffff,ffffffff)) | U64x(3ff00000,00000000);
+}
+
+/* Condition seed: ensure k[i] MSB of u[i] are non-zero. */
+static LJ_AINLINE void lj_prng_condition(PRNGState *rs)
+{
+  if (rs->u[0] < (1u << 1)) rs->u[0] += (1u << 1);
+  if (rs->u[1] < (1u << 6)) rs->u[1] += (1u << 6);
+  if (rs->u[2] < (1u << 9)) rs->u[2] += (1u << 9);
+  if (rs->u[3] < (1u << 17)) rs->u[3] += (1u << 17);
+}
+
+/* -- PRNG seeding from OS ------------------------------------------------ */
+
+#if LUAJIT_SECURITY_PRNG == 0
+
+/* Nothing to define. */
+
+#elif LJ_TARGET_XBOX360
+
+extern int XNetRandom(void *buf, unsigned int len);
+
+#elif LJ_TARGET_PS3
+
+extern int sys_get_random_number(void *buf, uint64_t len);
+
+#elif LJ_TARGET_PS4 || LJ_TARGET_PSVITA
+
+extern int sceRandomGetRandomNumber(void *buf, size_t len);
+
+#elif LJ_TARGET_WINDOWS || LJ_TARGET_XBOXONE
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#if LJ_TARGET_UWP || LJ_TARGET_XBOXONE
+/* Must use BCryptGenRandom. */
+#include <bcrypt.h>
+#pragma comment(lib, "bcrypt.lib")
+#else
+/* If you wonder about this mess, then search online for RtlGenRandom. */
+typedef BOOLEAN (WINAPI *PRGR)(void *buf, ULONG len);
+static PRGR libfunc_rgr;
+#endif
+
+#elif LJ_TARGET_POSIX
+
+#if LJ_TARGET_LINUX
+/* Avoid a dependency on glibc 2.25+ and use the getrandom syscall instead. */
+#include <sys/syscall.h>
+#elif LJ_TARGET_OSX || LJ_TARGET_BSD || LJ_TARGET_SOLARIS || LJ_TARGET_CYGWIN
+extern int getentropy(void *buf, size_t len);
+#ifdef __ELF__
+  __attribute__((weak))
+#endif
+;
+#endif
+
+/* For the /dev/urandom fallback. */
+#include <fcntl.h>
+#include <unistd.h>
+
+#endif
+
+#if LUAJIT_SECURITY_PRNG == 0
+
+/* If you really don't care about security, then define
+** LUAJIT_SECURITY_PRNG=0. This yields a predictable seed
+** and provides NO SECURITY against various attacks on the VM.
+**
+** BTW: This is NOT the way to get predictable table iteration,
+** predictable trace generation, predictable bytecode generation, etc.
+*/
+int LJ_FASTCALL lj_prng_seed_secure(PRNGState *rs)
+{
+  lj_prng_seed_fixed(rs);  /* The fixed seed is already conditioned. */
+  return 1;
+}
+
+#else
+
+/* Securely seed PRNG from system entropy. Returns 0 on failure. */
+int LJ_FASTCALL lj_prng_seed_secure(PRNGState *rs)
+{
+#if LJ_TARGET_XBOX360
+
+  if (XNetRandom(rs->u, (unsigned int)sizeof(rs->u)) == 0)
+    goto ok;
+
+#elif LJ_TARGET_PS3
+
+  if (sys_get_random_number(rs->u, sizeof(rs->u)) == 0)
+    goto ok;
+
+#elif LJ_TARGET_PS4 || LJ_TARGET_PSVITA
+
+  if (sceRandomGetRandomNumber(rs->u, sizeof(rs->u) == 0)
+    goto ok;
+
+#elif LJ_TARGET_UWP || LJ_TARGET_XBOXONE
+
+  if (BCryptGenRandom(NULL, (PUCHAR)(rs->u), (ULONG)sizeof(rs->u),
+		      BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0)
+    goto ok;
+
+#elif LJ_TARGET_WINDOWS
+
+  /* Keep the library loaded in case multiple VMs are started. */
+  if (!libfunc_rgr) {
+    HMODULE lib = LJ_WIN_LOADLIBA("advapi32.dll");
+    if (!lib) return 0;
+    libfunc_rgr = (PRGR)GetProcAddress(lib, "SystemFunction036");
+    if (!libfunc_rgr) return 0;
+  }
+  if (libfunc_rgr(rs->u, (ULONG)sizeof(rs->u)))
+    goto ok;
+
+#elif LJ_TARGET_POSIX
+
+#if LJ_TARGET_LINUX && defined(SYS_getrandom)
+
+  if (syscall(SYS_getrandom, rs->u, sizeof(rs->u), 0) == (long)sizeof(rs->u))
+    goto ok;
+
+#elif LJ_TARGET_OSX || LJ_TARGET_BSD || LJ_TARGET_SOLARIS || LJ_TARGET_CYGWIN
+
+  if ((!__ELF__ || getentropy) && getentropy(rs->u, sizeof(rs->u)) == 0)
+    goto ok;
+
+#endif
+
+  /* Fallback to /dev/urandom. This may fail if the device is not
+  ** existent or accessible in a chroot or container, or if the process
+  ** or the OS ran out of file descriptors.
+  */
+  {
+    int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC);
+    if (fd != -1) {
+      ssize_t n = read(fd, rs->u, sizeof(rs->u));
+      (void)close(fd);
+      if (n == (ssize_t)sizeof(rs->u))
+	goto ok;
+    }
+  }
+
+#else
+
+  /* Add an elif above for your OS with a secure PRNG seed.
+  ** Note that fiddling around with rand(), getpid(), time() or coercing
+  ** ASLR to yield a few bits of randomness is not helpful.
+  ** If you don't want any security, then don't pretend you have any
+  ** and simply define LUAJIT_SECURITY_PRNG=0 for the build.
+  */
+#error "Missing secure PRNG seed for this OS"
+
+#endif
+  return 0;  /* Fail. */
+
+ok:
+  lj_prng_condition(rs);
+  (void)lj_prng_u64(rs);
+  return 1;  /* Success. */
+}
+
+#endif
+

+ 24 - 0
src/lj_prng.h

@@ -0,0 +1,24 @@
+/*
+** Pseudo-random number generation.
+** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _LJ_PRNG_H
+#define _LJ_PRNG_H
+
+#include "lj_def.h"
+
+LJ_FUNC int LJ_FASTCALL lj_prng_seed_secure(PRNGState *rs);
+LJ_FUNC uint64_t LJ_FASTCALL lj_prng_u64(PRNGState *rs);
+LJ_FUNC uint64_t LJ_FASTCALL lj_prng_u64d(PRNGState *rs);
+
+/* This is just the precomputed result of lib_math.c:random_seed(rs, 0.0). */
+static LJ_AINLINE void lj_prng_seed_fixed(PRNGState *rs)
+{
+  rs->u[0] = U64x(a0d27757,0a345b8c);
+  rs->u[1] = U64x(764a296c,5d4aa64f);
+  rs->u[2] = U64x(51220704,070adeaa);
+  rs->u[3] = U64x(2a2717b5,a7b7b927);
+}
+
+#endif

+ 2 - 1
src/lj_record.c

@@ -33,6 +33,7 @@
 #include "lj_snap.h"
 #include "lj_snap.h"
 #include "lj_dispatch.h"
 #include "lj_dispatch.h"
 #include "lj_vm.h"
 #include "lj_vm.h"
+#include "lj_prng.h"
 
 
 /* Some local macros to save typing. Undef'd at the end. */
 /* Some local macros to save typing. Undef'd at the end. */
 #define IR(ref)			(&J->cur.ir[(ref)])
 #define IR(ref)			(&J->cur.ir[(ref)])
@@ -1696,7 +1697,7 @@ static void check_call_unroll(jit_State *J, TraceNo lnk)
       if (lnk) {  /* Possible tail- or up-recursion. */
       if (lnk) {  /* Possible tail- or up-recursion. */
 	lj_trace_flush(J, lnk);  /* Flush trace that only returns. */
 	lj_trace_flush(J, lnk);  /* Flush trace that only returns. */
 	/* Set a small, pseudo-random hotcount for a quick retry of JFUNC*. */
 	/* Set a small, pseudo-random hotcount for a quick retry of JFUNC*. */
-	hotcount_set(J2GG(J), J->pc+1, LJ_PRNG_BITS(J, 4));
+	hotcount_set(J2GG(J), J->pc+1, lj_prng_u64(&J2G(J)->prng) & 15u);
       }
       }
       lj_trace_err(J, LJ_TRERR_CUNROLL);
       lj_trace_err(J, LJ_TRERR_CUNROLL);
     }
     }

+ 31 - 7
src/lj_state.c

@@ -25,6 +25,7 @@
 #include "lj_trace.h"
 #include "lj_trace.h"
 #include "lj_dispatch.h"
 #include "lj_dispatch.h"
 #include "lj_vm.h"
 #include "lj_vm.h"
+#include "lj_prng.h"
 #include "lj_lex.h"
 #include "lj_lex.h"
 #include "lj_alloc.h"
 #include "lj_alloc.h"
 #include "luajit.h"
 #include "luajit.h"
@@ -185,16 +186,33 @@ static void close_state(lua_State *L)
 }
 }
 
 
 #if LJ_64 && !LJ_GC64 && !(defined(LUAJIT_USE_VALGRIND) && defined(LUAJIT_USE_SYSMALLOC))
 #if LJ_64 && !LJ_GC64 && !(defined(LUAJIT_USE_VALGRIND) && defined(LUAJIT_USE_SYSMALLOC))
-lua_State *lj_state_newstate(lua_Alloc f, void *ud)
+lua_State *lj_state_newstate(lua_Alloc allocf, void *allocd)
 #else
 #else
-LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
+LUA_API lua_State *lua_newstate(lua_Alloc allocf, void *allocd)
 #endif
 #endif
 {
 {
-  GG_State *GG = (GG_State *)f(ud, NULL, 0, sizeof(GG_State));
-  lua_State *L = &GG->L;
-  global_State *g = &GG->g;
+  PRNGState prng;
+  GG_State *GG;
+  lua_State *L;
+  global_State *g;
+  /* We need the PRNG for the memory allocator, so initialize this first. */
+  if (!lj_prng_seed_secure(&prng)) {
+    lj_assertX(0, "secure PRNG seeding failed");
+    /* Can only return NULL here, so this errors with "not enough memory". */
+    return NULL;
+  }
+#ifndef LUAJIT_USE_SYSMALLOC
+  if (allocf == LJ_ALLOCF_INTERNAL) {
+    allocd = lj_alloc_create(&prng);
+    if (!allocd) return NULL;
+    allocf = lj_alloc_f;
+  }
+#endif
+  GG = (GG_State *)allocf(allocd, NULL, 0, sizeof(GG_State));
   if (GG == NULL || !checkptrGC(GG)) return NULL;
   if (GG == NULL || !checkptrGC(GG)) return NULL;
   memset(GG, 0, sizeof(GG_State));
   memset(GG, 0, sizeof(GG_State));
+  L = &GG->L;
+  g = &GG->g;
   L->gct = ~LJ_TTHREAD;
   L->gct = ~LJ_TTHREAD;
   L->marked = LJ_GC_WHITE0 | LJ_GC_FIXED | LJ_GC_SFIXED;  /* Prevent free. */
   L->marked = LJ_GC_WHITE0 | LJ_GC_FIXED | LJ_GC_SFIXED;  /* Prevent free. */
   L->dummy_ffid = FF_C;
   L->dummy_ffid = FF_C;
@@ -202,8 +220,14 @@ LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
   g->gc.currentwhite = LJ_GC_WHITE0 | LJ_GC_FIXED;
   g->gc.currentwhite = LJ_GC_WHITE0 | LJ_GC_FIXED;
   g->strempty.marked = LJ_GC_WHITE0;
   g->strempty.marked = LJ_GC_WHITE0;
   g->strempty.gct = ~LJ_TSTR;
   g->strempty.gct = ~LJ_TSTR;
-  g->allocf = f;
-  g->allocd = ud;
+  g->allocf = allocf;
+  g->allocd = allocd;
+  g->prng = prng;
+#ifndef LUAJIT_USE_SYSMALLOC
+  if (allocf == lj_alloc_f) {
+    lj_alloc_setprng(allocd, &g->prng);
+  }
+#endif
   setgcref(g->mainthref, obj2gco(L));
   setgcref(g->mainthref, obj2gco(L));
   setgcref(g->uvhead.prev, obj2gco(&g->uvhead));
   setgcref(g->uvhead.prev, obj2gco(&g->uvhead));
   setgcref(g->uvhead.next, obj2gco(&g->uvhead));
   setgcref(g->uvhead.next, obj2gco(&g->uvhead));

+ 2 - 0
src/lj_state.h

@@ -32,4 +32,6 @@ LJ_FUNC void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L);
 LJ_FUNC lua_State *lj_state_newstate(lua_Alloc f, void *ud);
 LJ_FUNC lua_State *lj_state_newstate(lua_Alloc f, void *ud);
 #endif
 #endif
 
 
+#define LJ_ALLOCF_INTERNAL	((lua_Alloc)(void *)(uintptr_t)(1237<<4))
+
 #endif
 #endif

+ 2 - 1
src/lj_trace.c

@@ -30,6 +30,7 @@
 #include "lj_vm.h"
 #include "lj_vm.h"
 #include "lj_vmevent.h"
 #include "lj_vmevent.h"
 #include "lj_target.h"
 #include "lj_target.h"
+#include "lj_prng.h"
 
 
 /* -- Error handling ------------------------------------------------------ */
 /* -- Error handling ------------------------------------------------------ */
 
 
@@ -384,7 +385,7 @@ static void penalty_pc(jit_State *J, GCproto *pt, BCIns *pc, TraceError e)
     if (mref(J->penalty[i].pc, const BCIns) == pc) {  /* Cache slot found? */
     if (mref(J->penalty[i].pc, const BCIns) == pc) {  /* Cache slot found? */
       /* First try to bump its hotcount several times. */
       /* First try to bump its hotcount several times. */
       val = ((uint32_t)J->penalty[i].val << 1) +
       val = ((uint32_t)J->penalty[i].val << 1) +
-	    LJ_PRNG_BITS(J, PENALTY_RNDBITS);
+	    (lj_prng_u64(&J2G(J)->prng) & ((1u<<PENALTY_RNDBITS)-1));
       if (val > PENALTY_MAX) {
       if (val > PENALTY_MAX) {
 	blacklist_pc(pt, pc);  /* Blacklist it, if that didn't help. */
 	blacklist_pc(pt, pc);  /* Blacklist it, if that didn't help. */
 	return;
 	return;

+ 1 - 0
src/ljamalg.c

@@ -31,6 +31,7 @@
 #include "lj_udata.c"
 #include "lj_udata.c"
 #include "lj_meta.c"
 #include "lj_meta.c"
 #include "lj_debug.c"
 #include "lj_debug.c"
+#include "lj_prng.c"
 #include "lj_state.c"
 #include "lj_state.c"
 #include "lj_dispatch.c"
 #include "lj_dispatch.c"
 #include "lj_vmevent.c"
 #include "lj_vmevent.c"