Use a securely seeded global PRNG for the VM.

It's not 2005 anymore.
This commit is contained in:
Mike Pall 2020-06-15 12:21:05 +02:00
parent 34e53736c6
commit a44f53acf5
22 changed files with 411 additions and 174 deletions

View File

@ -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_prng.o lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o \
lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.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 \

View File

@ -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_prng.c lj_prng.h lj_state.c lj_lex.h lj_alloc.h luajit.h \
lj_profile.h lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c \ lj_dispatch.c lj_ccallback.h lj_profile.h lj_vmevent.c lj_vmevent.h \
lj_strfmt.c lj_strfmt_num.c lj_api.c lj_profile.c lj_lex.c lualib.h \ lj_vmmath.c lj_strscan.c lj_strfmt.c lj_strfmt_num.c lj_api.c \
lj_parse.h lj_parse.c lj_bcread.c lj_bcdump.h lj_bcwrite.c lj_load.c \ lj_profile.c lj_lex.c lualib.h lj_parse.h lj_parse.c lj_bcread.c \
lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h \ lj_bcdump.h lj_bcwrite.c lj_load.c lj_ctype.c lj_cdata.c lj_cconv.h \
lj_ccallback.c lj_target.h lj_target_*.h lj_mcode.h lj_carith.c \ lj_cconv.c lj_ccall.c lj_ccall.h lj_ccallback.c lj_target.h \
lj_carith.h lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c \ lj_target_*.h lj_mcode.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h \
lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \ lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c lj_ircall.h lj_iropt.h \
lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \ lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \
lj_opt_sink.c lj_mcode.c lj_snap.c lj_record.c lj_record.h lj_ffrecord.h \ lj_opt_loop.c lj_snap.h lj_opt_split.c lj_opt_sink.c lj_mcode.c \
lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \ lj_snap.c lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \
lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \ lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h \
lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \ lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c \
lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \ lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c \
lib_ffi.c lib_init.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 \

View File

@ -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;

View File

@ -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. */ /* PRNG seeding function. */
#define TW223_GEN(i, k, q, s) \ static void random_seed(PRNGState *rs, double d)
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)
{ {
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. */ if (u.u64 < m) u.u64 += m; /* Ensure k[i] MSB of u[i] are non-zero. */
rs->gen[i] = u.u64; 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_prng_u64d(rs);
u.u64 = lj_math_random_step(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)))); PRNGState *rs = (PRNGState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
random_init(rs, lj_lib_checknum(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; PRNGState *rs = (PRNGState *)lua_newuserdata(L, sizeof(PRNGState));
rs = (RandomState *)lua_newuserdata(L, sizeof(RandomState)); lj_prng_seed_fixed(rs);
rs->valid = 0; /* Use lazy initialization to save some time on startup. */
LJ_LIB_REG(L, LUA_MATHLIBNAME, math); LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
return 1; return 1;
} }

View File

@ -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. static void *mmap_probe(PRNGState *rs, size_t size)
** 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)
{ {
/* 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)) { do {
hint_prng = mmap_probe_seed(); hint_addr = lj_prng_u64(rs) & (((uintptr_t)1<<LJ_ALLOC_MBITS)-LJ_PAGESIZE);
}
/* 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);
} 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
#elif LJ_ALLOC_MMAP_PROBE #define CALL_MMAP(prng, size) mmap_map32(prng, size)
#define CALL_MMAP(size) mmap_probe(size)
#else #else
static void *CALL_MMAP(size_t size) #define CALL_MMAP(prng, size) mmap_map32(size)
#endif
#elif LJ_ALLOC_MMAP_PROBE
#define CALL_MMAP(prng, size) mmap_probe(prng, size)
#else
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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]) {

View File

@ -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)])

View File

@ -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) \

View File

@ -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. */ TValue k64[LJ_K64__MAX]; /* Common 8 byte constants. */
uint32_t k32[LJ_K32__MAX]; /* Ditto for 4 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

View File

@ -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

View File

@ -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. */ #error "Missing OS support for explicit placement of executable memory"
#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);
}
#endif #endif
/* -- MCode area protection ----------------------------------------------- */ /* -- MCode area protection ----------------------------------------------- */
/* Define this ONLY if page protection twiddling becomes a bottleneck. */ #if LUAJIT_SECURITY_MCODE == 0
#ifdef LUAJIT_UNPROTECT_MCODE
/* 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 ** any *other* flaw in your C application logic, then any RWX memory pages
** simplifies writing an exploit considerably. ** 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

View File

@ -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
src/lj_prng.c Normal file
View File

@ -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
src/lj_prng.h Normal file
View File

@ -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

View File

@ -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);
} }

View File

@ -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)); PRNGState prng;
lua_State *L = &GG->L; GG_State *GG;
global_State *g = &GG->g; 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->allocf = allocf;
g->allocd = ud; 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));

View File

@ -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

View File

@ -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;

View File

@ -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"