lua sandbox code reformatting

Remove a ton of tabs in nhlua.c and add missing whitespace to a bunch
of 'if(test){' lines and to a few casts.

Also simplify? obj handling during garbage collection (does not fix
the current gc problem) in nhlobj.c.
This commit is contained in:
PatR
2022-05-28 12:35:44 -07:00
parent 5622a4a848
commit 3c402fb312
2 changed files with 313 additions and 313 deletions

View File

@@ -45,26 +45,26 @@ l_obj_check(lua_State *L, int indx)
static int static int
l_obj_gc(lua_State *L) l_obj_gc(lua_State *L)
{ {
struct obj *obj, *otmp;
struct _lua_obj *lo = l_obj_check(L, 1); struct _lua_obj *lo = l_obj_check(L, 1);
if (lo && lo->obj) { if (lo && (obj = lo->obj) != 0) {
if (lo->obj->lua_ref_cnt > 0) if (obj->lua_ref_cnt > 0)
lo->obj->lua_ref_cnt--; obj->lua_ref_cnt--;
/* free-floating objects with no other refs are deallocated. */ /* free-floating objects with no other refs are deallocated. */
if (!lo->obj->lua_ref_cnt if (!obj->lua_ref_cnt
&& (lo->obj->where == OBJ_FREE || lo->obj->where == OBJ_LUAFREE)) { && (obj->where == OBJ_FREE || obj->where == OBJ_LUAFREE)) {
if (Has_contents(lo->obj)) { if (Has_contents(obj)) {
struct obj *otmp; while ((otmp = obj->cobj) != 0) {
while ((otmp = lo->obj->cobj) != 0) {
obj_extract_self(otmp); obj_extract_self(otmp);
dealloc_obj(otmp); dealloc_obj(otmp);
} }
} }
dealloc_obj(lo->obj); obj->where = OBJ_FREE;
dealloc_obj(obj), obj = 0;
} }
lo->obj = NULL; lo->obj = NULL;
} }
return 0; return 0;
} }

View File

@@ -108,7 +108,7 @@ l_nhcore_init(void)
#if 1 #if 1
nhl_sandbox_info sbi = {NHL_SB_SAFE, 0, 0, 0}; nhl_sandbox_info sbi = {NHL_SB_SAFE, 0, 0, 0};
#else #else
/* Sample sbi for getting resource usage information. */ /* Sample sbi for getting resource usage information. */
nhl_sandbox_info sbi = {NHL_SB_SAFE|NHL_SB_REPORT2, 10000000, 10000000, 0}; nhl_sandbox_info sbi = {NHL_SB_SAFE|NHL_SB_REPORT2, 10000000, 10000000, 0};
#endif #endif
if ((g.luacore = nhl_init(&sbi)) != 0) { if ((g.luacore = nhl_init(&sbi)) != 0) {
@@ -121,7 +121,7 @@ l_nhcore_init(void)
nhcore_call_available[i] = TRUE; nhcore_call_available[i] = TRUE;
} }
} else } else
impossible("l_nhcore_init failed"); impossible("l_nhcore_init failed");
} }
void void
@@ -158,7 +158,7 @@ l_nhcore_call(int callidx)
lua_remove(g.luacore, -2); /* nhcore */ lua_remove(g.luacore, -2); /* nhcore */
if (nhl_pcall(g.luacore, 0, 1)) { if (nhl_pcall(g.luacore, 0, 1)) {
impossible("Lua error: %s", lua_tostring(g.luacore, -1)); impossible("Lua error: %s", lua_tostring(g.luacore, -1));
} }
} else { } else {
/*impossible("nhcore.%s is not a lua function", /*impossible("nhcore.%s is not a lua function",
nhcore_call_names[callidx]);*/ nhcore_call_names[callidx]);*/
@@ -1429,9 +1429,9 @@ init_u_data(lua_State *L)
static int static int
nhl_set_package_path(lua_State *L, const char *path) nhl_set_package_path(lua_State *L, const char *path)
{ {
if (LUA_TTABLE != lua_getglobal(L, "package")){ if (LUA_TTABLE != lua_getglobal(L, "package")) {
impossible("package not a table in nhl_set_package_path"); impossible("package not a table in nhl_set_package_path");
return 1; return 1;
}; };
lua_pushstring(L, path); lua_pushstring(L, path);
lua_setfield(L, -2, "path"); lua_setfield(L, -2, "path");
@@ -1460,32 +1460,29 @@ nhl_pcall(lua_State *L, int nargs, int nresults)
lua_insert(L, 1); lua_insert(L, 1);
(void)lua_getallocf(L, (void **)&nud); (void)lua_getallocf(L, (void **)&nud);
#ifdef NHL_SANDBOX #ifdef NHL_SANDBOX
if(nud && (nud->steps || nud->perpcall)){ if (nud && (nud->steps || nud->perpcall)) {
if(nud->perpcall) nud->steps = nud->perpcall; if (nud->perpcall)
if(setjmp(nud->jb)){ nud->steps = nud->perpcall;
/* panic, because we don't know if the game state is corrupt */ if (setjmp(nud->jb)) {
panic("time exceeded"); /* panic, because we don't know if the game state is corrupt */
} panic("time exceeded");
}
} }
#endif #endif
rv = lua_pcall(L, nargs, nresults, 1); rv = lua_pcall(L, nargs, nresults, 1);
lua_remove(L, 1); // remove handler lua_remove(L, 1); /* remove handler */
#ifdef NHL_SANDBOX #ifdef NHL_SANDBOX
if(nud if (nud && (nud->flags & (NHL_SB_REPORT | NHL_SB_REPORT2)) != 0
&& (nud->flags & (NHL_SB_REPORT|NHL_SB_REPORT2)) && (nud->memlimit || nud->osteps || nud->perpcall)) {
&& (nud->memlimit || nud->osteps || nud->perpcall) if (nud->flags & NHL_SB_REPORT2)
){ lua_gc(L, LUA_GCCOLLECT);
if(nud->flags & NHL_SB_REPORT2) pline("Lua context=%p RAM: %lu STEPS:%lu", (void *) L,
lua_gc(L, LUA_GCCOLLECT); (unsigned long) nud->inuse,
pline("Lua context=%p RAM: %lu STEPS:%lu", (unsigned long) (nud->perpcall
(void *)L, ? (nud->perpcall - nud->steps)
(unsigned long)nud->inuse, : (nud->osteps - nud->steps)));
(unsigned long)(nud->perpcall
? (nud->perpcall - nud->steps)
: (nud->osteps - nud->steps))
);
} }
#endif #endif
@@ -1588,11 +1585,11 @@ nhl_loadlua(lua_State *L, const char *fname)
ret = FALSE; ret = FALSE;
goto give_up; goto give_up;
} else { } else {
if(nhl_pcall(L, 0, LUA_MULTRET)) { if (nhl_pcall(L, 0, LUA_MULTRET)) {
impossible("Lua error: %s", lua_tostring(L, -1)); impossible("Lua error: %s", lua_tostring(L, -1));
ret = FALSE; ret = FALSE;
goto give_up; goto give_up;
} }
} }
give_up: give_up:
@@ -1608,25 +1605,25 @@ DISABLE_WARNING_CONDEXPR_IS_CONSTANT
lua_State * lua_State *
nhl_init(nhl_sandbox_info *sbi) nhl_init(nhl_sandbox_info *sbi)
{ {
/* It would be nice to import EXPECTED from each build system. XXX */ /* It would be nice to import EXPECTED from each build system. XXX */
/* And it would be nice to do it only once, but it's cheap. */ /* And it would be nice to do it only once, but it's cheap. */
#ifndef NHL_VERSION_EXPECTED #ifndef NHL_VERSION_EXPECTED
#define NHL_VERSION_EXPECTED 50404 #define NHL_VERSION_EXPECTED 50404
#endif #endif
#ifdef NHL_SANDBOX #ifdef NHL_SANDBOX
if(NHL_VERSION_EXPECTED != LUA_VERSION_RELEASE_NUM){ if (NHL_VERSION_EXPECTED != LUA_VERSION_RELEASE_NUM) {
panic( panic(
"sandbox doesn't know this Lua version: this=%d != expected=%d ", "sandbox doesn't know this Lua version: this=%d != expected=%d ",
LUA_VERSION_RELEASE_NUM, NHL_VERSION_EXPECTED); LUA_VERSION_RELEASE_NUM, NHL_VERSION_EXPECTED);
} }
#endif #endif
lua_State *L = nhlL_newstate(sbi); lua_State *L = nhlL_newstate(sbi);
iflags.in_lua = TRUE; iflags.in_lua = TRUE;
/* Temporary for development XXX */ /* Temporary for development XXX */
/* Turn this off in config.h to disable the sandbox. */ /* Turn this off in config.h to disable the sandbox. */
#ifdef NHL_SANDBOX #ifdef NHL_SANDBOX
nhlL_openlibs(L, sbi->flags); nhlL_openlibs(L, sbi->flags);
#else #else
@@ -1635,10 +1632,9 @@ nhl_init(nhl_sandbox_info *sbi)
#ifdef notyet #ifdef notyet
if (sbi->flags & NHL_SB_PACKAGE) { if (sbi->flags & NHL_SB_PACKAGE) {
/* XXX Is this still needed? */ /* XXX Is this still needed? */
if (nhl_set_package_path(L, "./?.lua")){ if (nhl_set_package_path(L, "./?.lua"))
return 0; return 0;
}
} }
#endif #endif
@@ -1658,10 +1654,10 @@ nhl_init(nhl_sandbox_info *sbi)
l_obj_register(L); l_obj_register(L);
/* nhlib.lua assumes the math table exists. */ /* nhlib.lua assumes the math table exists. */
if(LUA_TTABLE != lua_getglobal(L, "math")){ if (LUA_TTABLE != lua_getglobal(L, "math")) {
lua_newtable(L); lua_newtable(L);
lua_setglobal(L, "math"); lua_setglobal(L, "math");
} }
if (!nhl_loadlua(L, "nhlib.lua")) { if (!nhl_loadlua(L, "nhlib.lua")) {
@@ -1826,9 +1822,9 @@ static struct e ct_base_unsafe[] = {
/* possible ct_debug tables - likely to need changes */ /* possible ct_debug tables - likely to need changes */
static struct e ct_debug_debug[] = { static struct e ct_debug_debug[] = {
{NEVER, "debug"}, /* uses normal I/O so needs re-write */ {NEVER, "debug"}, /* uses normal I/O so needs re-write */
{IFFLAG, "getuservalue"}, {IFFLAG, "getuservalue"},
{NEVER, "gethook"}, /* see sethook */ {NEVER, "gethook"}, /* see sethook */
{IFFLAG, "getinfo"}, {IFFLAG, "getinfo"},
{IFFLAG, "getlocal"}, {IFFLAG, "getlocal"},
{IFFLAG, "getregistry"}, {IFFLAG, "getregistry"},
@@ -1837,7 +1833,7 @@ static struct e ct_debug_debug[] = {
{IFFLAG, "upvaluejoin"}, {IFFLAG, "upvaluejoin"},
{IFFLAG, "upvalueid"}, {IFFLAG, "upvalueid"},
{IFFLAG, "setuservalue"}, {IFFLAG, "setuservalue"},
{NEVER, "sethook"}, /* used for memory and step limits */ {NEVER, "sethook"}, /* used for memory and step limits */
{IFFLAG, "setlocal"}, {IFFLAG, "setlocal"},
{IFFLAG, "setmetatable"}, {IFFLAG, "setmetatable"},
{IFFLAG, "setupvalue"}, {IFFLAG, "setupvalue"},
@@ -1851,7 +1847,7 @@ static struct e ct_debug_safe[] = {
/* possible ct_os_ tables */ /* possible ct_os_ tables */
static struct e ct_os_time[] = { static struct e ct_os_time[] = {
{IFFLAG, "clock"}, /* is this portable? XXX */ {IFFLAG, "clock"}, /* is this portable? XXX */
{IFFLAG, "date"}, {IFFLAG, "date"},
{IFFLAG, "difftime"}, {IFFLAG, "difftime"},
{IFFLAG, "time"}, {IFFLAG, "time"},
@@ -1859,7 +1855,7 @@ static struct e ct_os_time[] = {
}; };
static struct e ct_os_files[] = { static struct e ct_os_files[] = {
{NEVER, "execute"}, /* not portable */ {NEVER, "execute"}, /* not portable */
{NEVER, "exit"}, {NEVER, "exit"},
{NEVER, "getenv"}, {NEVER, "getenv"},
{IFFLAG, "remove"}, {IFFLAG, "remove"},
@@ -1876,14 +1872,14 @@ static struct e ct_os_files[] = {
static void static void
nhl_clearfromtable(lua_State *L, int flag, int tndx, struct e *todo) nhl_clearfromtable(lua_State *L, int flag, int tndx, struct e *todo)
{ {
while(todo->when != EOT){ while (todo->when != EOT) {
lua_pushnil(L); lua_pushnil(L);
/* if we load the library at all, NEVER items must be erased /* if we load the library at all, NEVER items must be erased
* and IFFLAG items should be erased if !flag */ * and IFFLAG items should be erased if !flag */
if(todo->when==NEVER || !flag) { if (todo->when == NEVER || !flag) {
lua_setfield(L, tndx, todo->fnname); lua_setfield(L, tndx, todo->fnname);
} }
todo++; todo++;
} }
} }
#endif #endif
@@ -1893,8 +1889,8 @@ XXX
registry["org.nethack.nethack.sb.fs"][N]= registry["org.nethack.nethack.sb.fs"][N]=
CODEOBJECT CODEOBJECT
{ {
modepat: PATTERN, modepat: PATTERN,
filepat: PATTERN filepat: PATTERN
} }
CODEOBJECT CODEOBJECT
if string then if pcall(string,mode, dir, file) if string then if pcall(string,mode, dir, file)
@@ -1910,7 +1906,7 @@ return values from "call it":
*/ */
/* stack indexes: /* stack indexes:
* -1 table to index with ename * -1 table to index with ename
* params file * params file
* params+1 [mode] * params+1 [mode]
*/ */
@@ -1931,16 +1927,15 @@ start_luapat(void)
/* XXX set memory and step limits */ /* XXX set memory and step limits */
nhl_sandbox_info sbi = {NHL_SB_STRING, 0, 0, 0}; nhl_sandbox_info sbi = {NHL_SB_STRING, 0, 0, 0};
if((luapat = nhl_init(&sbi)) == NULL) if ((luapat = nhl_init(&sbi)) == NULL)
return FALSE; return FALSE;
/* load a pattern matching function */ /* load a pattern matching function */
rv = luaL_loadstring(luapat, rv = luaL_loadstring(luapat,
"function matches(s,p) return not not string.match(s,p) end"); "function matches(s,p) return not not string.match(s,p) end");
if(rv != LUA_OK){ if (rv != LUA_OK) {
panic("start_luapat: %d",rv); panic("start_luapat: %d",rv);
} }
return TRUE; return TRUE;
} }
#endif #endif
@@ -1948,9 +1943,9 @@ start_luapat(void)
static void static void
end_luapat(void) end_luapat(void)
{ {
if(luapat){ if (luapat) {
lua_close(luapat); lua_close(luapat);
luapat = NULL; luapat = NULL;
} }
} }
@@ -1958,32 +1953,32 @@ end_luapat(void)
static int static int
opencheckpat(lua_State *L, const char *ename, int param) opencheckpat(lua_State *L, const char *ename, int param)
{ {
/* careful - we're using 2 different and unrelated Lua states */ /* careful - we're using 2 different and unrelated Lua states */
const char *string; const char *string;
int rv; int rv;
lua_pushliteral(luapat, "matches"); /* function -0,+1 */ lua_pushliteral(luapat, "matches"); /* function -0,+1 */
string = lua_tolstring(L, param, NULL); /* mode or filename -0,+0 */ string = lua_tolstring(L, param, NULL); /* mode or filename -0,+0 */
lua_pushstring(luapat, string); /* -0,+1 */ lua_pushstring(luapat, string); /* -0,+1 */
(void)lua_getfield(L, -1, ename); /* pattern -0,+1 */ (void)lua_getfield(L, -1, ename); /* pattern -0,+1 */
lua_pop(L, 1); /* -1,+0 */ lua_pop(L, 1); /* -1,+0 */
string = lua_tolstring(L, -1, NULL); /* -0,+0 */ string = lua_tolstring(L, -1, NULL); /* -0,+0 */
lua_pushstring(luapat, string); /* -0,+1 */ lua_pushstring(luapat, string); /* -0,+1 */
if(nhl_pcall(luapat, 2, 1)){ /* -3,+1 */ if (nhl_pcall(luapat, 2, 1)) { /* -3,+1 */
/* impossible("access check internal error"); */ /* impossible("access check internal error"); */
return NHL_SBRV_FAIL; return NHL_SBRV_FAIL;
} }
rv = lua_toboolean(luapat, -1); /* -0,+0 */ rv = lua_toboolean(luapat, -1); /* -0,+0 */
#if 0 #if 0
if(lua_resetthread(luapat) != LUA_OK) if (lua_resetthread(luapat) != LUA_OK)
return NHL_SBRV_FAIL; return NHL_SBRV_FAIL;
is pop sufficient? XXX or wrong - look at the balance is pop sufficient? XXX or wrong - look at the balance
#else #else
lua_pop(luapat, 1); /* -1,+0 */ lua_pop(luapat, 1); /* -1,+0 */
#endif #endif
return rv ? NHL_SBRV_ACCEPT : NHL_SBRV_DENY; return rv ? NHL_SBRV_ACCEPT : NHL_SBRV_DENY;
} }
@@ -1994,110 +1989,113 @@ is pop sufficient? XXX or wrong - look at the balance
*/ */
#define HOOKTBLNAME "org.nethack.nethack.sb.fs" #define HOOKTBLNAME "org.nethack.nethack.sb.fs"
#ifdef notyet #ifdef notyet
static int (*io_open)(lua_State *) = NULL; /* XXX this may have to be in g TBD */ static int (*io_open)(lua_State *) = NULL; /* XXX this may have to be in g TBD */
#endif #endif
void void
nhl_pushhooked_open_table(lua_State *L){ nhl_pushhooked_open_table(lua_State *L)
{
int hot = lua_getfield(L, LUA_REGISTRYINDEX, HOOKTBLNAME); int hot = lua_getfield(L, LUA_REGISTRYINDEX, HOOKTBLNAME);
if (hot == LUA_TNONE) { if (hot == LUA_TNONE) {
lua_newtable(L); lua_newtable(L);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, HOOKTBLNAME); lua_setfield(L, LUA_REGISTRYINDEX, HOOKTBLNAME);
} }
} }
#ifdef notyet #ifdef notyet
static int static int
hooked_open(lua_State *L){ hooked_open(lua_State *L)
{
const char *mode; const char *mode;
static boolean never = TRUE; static boolean never = TRUE;
const char *filename; const char *filename;
int params; int params;
int hot; int hot;
if (never){ if (never) {
if(!start_luapat()) if (!start_luapat())
return NHL_SBRV_FAIL; return NHL_SBRV_FAIL;
never = FALSE; never = FALSE;
} }
filename = luaL_checkstring(L, 1); filename = luaL_checkstring(L, 1);
/* Unlike io.open, we want to treat mode as non-optional. */ /* Unlike io.open, we want to treat mode as non-optional. */
if (lua_gettop(L) < 2){ if (lua_gettop(L) < 2) {
lua_pushstring(L, "r"); lua_pushstring(L, "r");
} }
mode = luaL_optstring(L, 2, "r"); mode = luaL_optstring(L, 2, "r");
/* sandbox checks */ /* sandbox checks */
/* Do we need some ud from the calling state to let this be different /* Do we need some ud from the calling state to let this be different for
for each call without redoing the HO table?? Maybe for version 2. XXX */ each call without redoing the HO table?? Maybe for version 2. XXX */
params = lua_gettop(L)-1; /* point at first param */ params = lua_gettop(L)-1; /* point at first param */
nhl_pushhooked_open_table(L); nhl_pushhooked_open_table(L);
hot = lua_gettop(L); hot = lua_gettop(L);
if(lua_type(L, hot) == LUA_TTABLE){ if (lua_type(L, hot) == LUA_TTABLE) {
int idx; int idx;
for( for (idx = 1;
idx=1; lua_pushinteger(L, idx),
lua_pushinteger(L, idx), lua_geti(L, hot, idx),
lua_geti(L, hot, idx), !lua_isnoneornil(L, -1);
!lua_isnoneornil(L, -1); ++idx) {
idx++ /* top of stack is our configtbl[idx] */
){ switch (lua_type(L, -1)) {
/* top of stack is our configtbl[idx] */ /* lots of options to expand this with other types XXX */
switch(lua_type(L, -1)){ case LUA_TTABLE: {
/* lots of options to expand this with other types XXX */ int moderv, filerv;
case LUA_TTABLE: { moderv = opencheckpat(L, "modepat", params+1);
int moderv, filerv; if (moderv == NHL_SBRV_FAIL)
moderv = opencheckpat(L, "modepat", params+1); return moderv;
if (moderv == NHL_SBRV_FAIL) filerv = opencheckpat(L, "filepat", params);
return moderv; if (filerv == NHL_SBRV_FAIL)
filerv = opencheckpat(L, "filepat", params); return moderv;
if (filerv == NHL_SBRV_FAIL) if (filerv == moderv) {
return moderv; if (filerv == NHL_SBRV_DENY)
if(filerv == moderv){ return NHL_SBRV_DENY;
if(filerv == NHL_SBRV_DENY) if (filerv == NHL_SBRV_ACCEPT)
return NHL_SBRV_DENY; goto doopen;
if(filerv == NHL_SBRV_ACCEPT) }
goto doopen; break; /* try next entry */
} }
break; /* try next entry */ default:
} return NHL_SBRV_FAIL;
default: }
return NHL_SBRV_FAIL; }
}
}
} else } else
return NHL_SBRV_DENY; /* default to "no" */ return NHL_SBRV_DENY; /* default to "no" */
doopen: doopen:
lua_settop(L, params+1); lua_settop(L, params+1);
return (*io_open)(L); return (*io_open)(L);
} }
static boolean static boolean
hook_open(lua_State *L){ hook_open(lua_State *L)
{
boolean rv = FALSE; boolean rv = FALSE;
if(!io_open){ if (!io_open) {
int tos = lua_gettop(L); int tos = lua_gettop(L);
lua_pushglobaltable(L); lua_pushglobaltable(L);
if(lua_getfield(L, -1, "io") != LUA_TTABLE) goto out; if (lua_getfield(L, -1, "io") != LUA_TTABLE)
lua_getfield(L, -1, "open"); goto out;
/* The only way this can happen is if someone is messing with us, lua_getfield(L, -1, "open");
* and I'm not sure even that is possible. */ /* The only way this can happen is if someone is messing with us,
if(!lua_iscfunction(L, -1)) goto out; * and I'm not sure even that is possible. */
/* XXX This is fragile: C11 says casting func* to void* if (!lua_iscfunction(L, -1))
* doesn't have to work, but POSIX says it does. So it goto out;
* _should_ work everywhere but all we can do without messing /* XXX This is fragile: C11 says casting func* to void*
* around inside Lua is to try to keep the compiler quiet. */ * doesn't have to work, but POSIX says it does. So it
io_open = (int (*)(lua_State *))lua_topointer(L, -1); * _should_ work everywhere but all we can do without messing
lua_pushcfunction(L, hooked_open); * around inside Lua is to try to keep the compiler quiet. */
lua_setfield(L, -1, "open"); io_open = (int (*)(lua_State *))lua_topointer(L, -1);
rv = TRUE; lua_pushcfunction(L, hooked_open);
out: lua_setfield(L, -1, "open");
lua_settop(L, tos); rv = TRUE;
out:
lua_settop(L, tos);
} }
return rv; return rv;
} }
@@ -2107,50 +2105,51 @@ DISABLE_WARNING_CONDEXPR_IS_CONSTANT
#ifdef NHL_SANDBOX #ifdef NHL_SANDBOX
static void static void
nhlL_openlibs(lua_State *L, uint32_t lflags){ nhlL_openlibs(lua_State *L, uint32_t lflags)
/* translate lflags from user-friendly to internal */ {
if (NHL_SB_DEBUGGING & lflags){ /* translate lflags from user-friendly to internal */
lflags |= NHL_SB_DB_SAFE; if (NHL_SB_DEBUGGING & lflags) {
lflags |= NHL_SB_DB_SAFE;
} }
/* only for debugging the sandbox integration */ /* only for debugging the sandbox integration */
if (NHL_SB_ALL & lflags){ if (NHL_SB_ALL & lflags) {
lflags = -1; lflags = -1;
} else if (NHL_SB_SAFE & lflags){ } else if (NHL_SB_SAFE & lflags) {
lflags |= NHL_SB_BASE_BASE; lflags |= NHL_SB_BASE_BASE;
lflags |= NHL_SB_COROUTINE; lflags |= NHL_SB_COROUTINE;
lflags |= NHL_SB_TABLE; lflags |= NHL_SB_TABLE;
lflags |= NHL_SB_STRING; lflags |= NHL_SB_STRING;
lflags |= NHL_SB_MATH; lflags |= NHL_SB_MATH;
lflags |= NHL_SB_UTF8; lflags |= NHL_SB_UTF8;
} else if (NHL_SB_VERSION){ } else if (NHL_SB_VERSION) {
lflags |= NHL_SB_BASE_BASE; lflags |= NHL_SB_BASE_BASE;
} }
#ifdef notyet #ifdef notyet
/* Handling I/O is complex, so it's not available yet. I'll /* Handling I/O is complex, so it's not available yet. I'll
finish it if and when we need it. (keni) finish it if and when we need it. (keni)
- hooked open; array of tuples of (r/w/rw/a/etc, directory pat, file pat) - hooked open; array of tuples of (r/w/rw/a/etc, directory pat, file pat)
{"close", io_close}, but with no args closes default output, so needs hook {"close", io_close}, but with no args closes default output, so needs hook
{"flush", io_flush}, {"flush", io_flush},
{"lines", io_lines}, hook due to filename {"lines", io_lines}, hook due to filename
{"open", io_open}, hooked version: {"open", io_open}, hooked version:
only safe if mode not present or == "r" only safe if mode not present or == "r"
or WRITEIO or WRITEIO
only safe if path has no slashes only safe if path has no slashes
XXX probably need to be: matches port-specific list of paths XXX probably need to be: matches port-specific list of paths
WRITEIO needs a different list WRITEIO needs a different list
dlb integration? dlb integration?
may need to #define l_getc (but that wouldn't hook core) may need to #define l_getc (but that wouldn't hook core)
may need to #define fopen/fread/fwrite/feof/ftell (etc?) may need to #define fopen/fread/fwrite/feof/ftell (etc?)
ugh: lauxlib.c uses getc() below luaL_loadfilex ugh: lauxlib.c uses getc() below luaL_loadfilex
override in lua.h? override in lua.h?
ugh: liolib.c uses getc() below g_read->test_eof ugh: liolib.c uses getc() below g_read->test_eof
override in lua.h? override in lua.h?
{"read", io_read}, {"read", io_read},
{"type", io_type}, {"type", io_type},
{"input", io_input}, safe with a complex hook, but may be needed for read? {"input", io_input}, safe with a complex hook, but may be needed for read?
WRITEIO: needs changes to hooked open? WRITEIO: needs changes to hooked open?
{"output", io_output}, do we want to allow access to default output? {"output", io_output}, do we want to allow access to default output?
{"write", io_write}, {"write", io_write},
UNSAFEIO: UNSAFEIO:
{"popen", io_popen}, {"popen", io_popen},
@@ -2158,70 +2157,70 @@ UNSAFEIO:
*/ */
#endif #endif
if(lflags & NHL_SB_BASEMASK){ if (lflags & NHL_SB_BASEMASK) {
int baselib; int baselib;
/* load the entire library ... */ /* load the entire library ... */
luaL_requiref(L, LUA_GNAME, luaopen_base, 1); luaL_requiref(L, LUA_GNAME, luaopen_base, 1);
baselib = lua_gettop(L); baselib = lua_gettop(L);
/* ... and remove anything unsupported or not requested */ /* ... and remove anything unsupported or not requested */
DROPIF(NHL_SB_BASE_BASE, baselib, ct_base_base); DROPIF(NHL_SB_BASE_BASE, baselib, ct_base_base);
DROPIF(NHL_SB_BASE_ERROR, baselib, ct_base_error); DROPIF(NHL_SB_BASE_ERROR, baselib, ct_base_error);
DROPIF(NHL_SB_BASE_META, baselib, ct_base_meta); DROPIF(NHL_SB_BASE_META, baselib, ct_base_meta);
DROPIF(NHL_SB_BASE_GC, baselib, ct_base_iffy); DROPIF(NHL_SB_BASE_GC, baselib, ct_base_iffy);
DROPIF(NHL_SB_BASE_UNSAFE, baselib, ct_base_unsafe); DROPIF(NHL_SB_BASE_UNSAFE, baselib, ct_base_unsafe);
lua_pop(L, 1); lua_pop(L, 1);
} }
if(lflags & NHL_SB_COROUTINE){ if (lflags & NHL_SB_COROUTINE) {
luaL_requiref(L, LUA_COLIBNAME, luaopen_coroutine, 1); luaL_requiref(L, LUA_COLIBNAME, luaopen_coroutine, 1);
lua_pop(L, 1); lua_pop(L, 1);
} }
if(lflags & NHL_SB_TABLE){ if (lflags & NHL_SB_TABLE) {
luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1); luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
lua_pop(L, 1); lua_pop(L, 1);
} }
#ifdef notyet #ifdef notyet
if(lflags & NHL_SB_IO){ if (lflags & NHL_SB_IO) {
luaL_requiref(L, LUA_IOLIBNAME, luaopen_io, 1); luaL_requiref(L, LUA_IOLIBNAME, luaopen_io, 1);
lua_pop(L, 1); lua_pop(L, 1);
if(!hook_open(L)) if (!hook_open(L))
panic("can't hook io.open"); panic("can't hook io.open");
} }
#endif #endif
if(lflags & NHL_SB_OSMASK){ if (lflags & NHL_SB_OSMASK) {
int oslib; int oslib;
luaL_requiref(L, LUA_OSLIBNAME, luaopen_os, 1); luaL_requiref(L, LUA_OSLIBNAME, luaopen_os, 1);
oslib = lua_gettop(L); oslib = lua_gettop(L);
DROPIF(NHL_SB_OS_TIME, oslib, ct_os_time); DROPIF(NHL_SB_OS_TIME, oslib, ct_os_time);
DROPIF(NHL_SB_OS_FILES, oslib, ct_os_files); DROPIF(NHL_SB_OS_FILES, oslib, ct_os_files);
lua_pop(L, 1); lua_pop(L, 1);
} }
if(lflags & NHL_SB_STRING){ if (lflags & NHL_SB_STRING) {
luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1); luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
lua_pop(L, 1); lua_pop(L, 1);
} }
if(lflags & NHL_SB_MATH){ if (lflags & NHL_SB_MATH) {
luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1); luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1);
/* XXX Note that math.random uses Lua's built-in xoshiro256** /* XXX Note that math.random uses Lua's built-in xoshiro256**
* algorithm regardless of what the rest of the game uses. * algorithm regardless of what the rest of the game uses.
* Fixing this would require changing lmathlib.c. */ * Fixing this would require changing lmathlib.c. */
lua_pop(L, 1); lua_pop(L, 1);
} }
if(lflags & NHL_SB_UTF8){ if (lflags & NHL_SB_UTF8) {
luaL_requiref(L, LUA_UTF8LIBNAME, luaopen_utf8, 1); luaL_requiref(L, LUA_UTF8LIBNAME, luaopen_utf8, 1);
lua_pop(L, 1); lua_pop(L, 1);
} }
if(lflags & NHL_SB_DBMASK){ if (lflags & NHL_SB_DBMASK) {
int dblib; int dblib;
luaL_requiref(L, LUA_DBLIBNAME, luaopen_debug, 1); luaL_requiref(L, LUA_DBLIBNAME, luaopen_debug, 1);
dblib = lua_gettop(L); dblib = lua_gettop(L);
DROPIF(NHL_SB_DB_DB, dblib, ct_debug_debug); DROPIF(NHL_SB_DB_DB, dblib, ct_debug_debug);
DROPIF(NHL_SB_DB_SAFE, dblib, ct_debug_safe); DROPIF(NHL_SB_DB_SAFE, dblib, ct_debug_safe);
lua_pop(L, 1); lua_pop(L, 1);
} }
} }
#endif #endif
@@ -2236,97 +2235,96 @@ RESTORE_WARNING_CONDEXPR_IS_CONSTANT
* it's worth the processing time), it can be overridden. * it's worth the processing time), it can be overridden.
*/ */
#ifndef NHL_ALLOC_ADJUST #ifndef NHL_ALLOC_ADJUST
#define NHL_ALLOC_ADJUST(d) d = ((d+15) & ~15) #define NHL_ALLOC_ADJUST(d) d = (((d) + 15) & ~15)
#endif #endif
static void * static void *
nhl_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { nhl_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
nhl_user_data *nud = ud; nhl_user_data *nud = ud;
if(nud && nud->memlimit){ /* this state is size limited */ if (nud && nud->memlimit) { /* this state is size limited */
uint32_t delta; uint32_t delta = !ptr ? nsize : nsize - osize;
if(!ptr){
delta = nsize; NHL_ALLOC_ADJUST(delta);
} else { nud->inuse += delta;
delta = nsize-osize; if (nud->inuse > nud->memlimit)
} return 0;
NHL_ALLOC_ADJUST(delta);
nud->inuse += delta;
if(nud->inuse > nud->memlimit){
return 0;
}
} }
if (nsize == 0) { if (nsize == 0) {
free(ptr); free(ptr);
return NULL; return NULL;
} else }
return realloc(ptr, nsize); /*
* FIXME:
* Use of realloc() confuses MONITOR_HEAP.
*/
return realloc(ptr, nsize);
} }
static int static int
nhl_panic (lua_State *L) { nhl_panic(lua_State *L)
{
const char *msg = lua_tostring(L, -1); const char *msg = lua_tostring(L, -1);
if (msg == NULL) msg = "error object is not a string";
if (msg == NULL)
msg = "error object is not a string";
panic("unprotected error in call to Lua API (%s)\n", msg); panic("unprotected error in call to Lua API (%s)\n", msg);
return 0; /* return to Lua to abort */ return 0; /* return to Lua to abort */
} }
#ifdef NHL_SANDBOX #ifdef NHL_SANDBOX
static void static void
nhl_hookfn(lua_State *L, lua_Debug *ar UNUSED){ nhl_hookfn(lua_State *L, lua_Debug *ar UNUSED)
{
nhl_user_data *nud; nhl_user_data *nud;
(void)lua_getallocf(L, (void **)&nud); (void) lua_getallocf(L, (void **) &nud);
if (nud->steps <= NHL_SB_STEPSIZE) if (nud->steps <= NHL_SB_STEPSIZE)
longjmp(nud->jb, 1); longjmp(nud->jb, 1);
nud->steps -= NHL_SB_STEPSIZE; nud->steps -= NHL_SB_STEPSIZE;
} }
#endif #endif
static lua_State * static lua_State *
nhlL_newstate (nhl_sandbox_info *sbi) { nhlL_newstate(nhl_sandbox_info *sbi)
{
nhl_user_data *nud = 0; nhl_user_data *nud = 0;
if(sbi->memlimit || sbi->steps){ if (sbi->memlimit || sbi->steps) {
nud = nhl_alloc(NULL, NULL, 0, sizeof(struct nhl_user_data)); nud = nhl_alloc(NULL, NULL, 0, sizeof (struct nhl_user_data));
if(!nud) if (!nud)
return 0; return 0;
nud->memlimit = sbi->memlimit; nud->memlimit = sbi->memlimit;
nud->perpcall = 0; /* set up below, if needed */ nud->perpcall = 0; /* set up below, if needed */
nud->steps = 0; nud->steps = 0;
nud->osteps = 0; nud->osteps = 0;
nud->flags = sbi->flags; /* save reporting flags */ nud->flags = sbi->flags; /* save reporting flags */
uint32_t sz = sizeof(struct nhl_user_data); uint32_t sz = sizeof (struct nhl_user_data);
NHL_ALLOC_ADJUST(sz); NHL_ALLOC_ADJUST(sz);
nud->inuse = sz; nud->inuse = sz;
} }
lua_State *L = lua_newstate(nhl_alloc, nud); lua_State *L = lua_newstate(nhl_alloc, nud);
#if LUA_VERSION_NUM == 503
# define luai_likely(x) (x) lua_atpanic(L, nhl_panic);
#endif
if (luai_likely(L)) {
lua_atpanic(L, &nhl_panic);
#if LUA_VERSION_NUM == 504 #if LUA_VERSION_NUM == 504
/* no warning system at the moment - it requires concatenting lua_setwarnf(L, (lua_WarnFunction) 0, L);
* strings to fit NetHack's API XXX */
lua_setwarnf(L, 0, L); /* default is warnings off */
#endif #endif
}
#ifdef NHL_SANDBOX #ifdef NHL_SANDBOX
if (sbi->steps || sbi->perpcall){ if (sbi->steps || sbi->perpcall) {
if (sbi->steps && sbi->perpcall) if (sbi->steps && sbi->perpcall)
impossible("steps and perpcall both non-zero"); impossible("steps and perpcall both non-zero");
if (sbi->perpcall){ if (sbi->perpcall) {
nud->perpcall = sbi->perpcall; nud->perpcall = sbi->perpcall;
} else { } else {
nud->steps = sbi->steps; nud->steps = sbi->steps;
nud->osteps = sbi->steps; nud->osteps = sbi->steps;
} }
lua_sethook(L, nhl_hookfn, LUA_MASKCOUNT, NHL_SB_STEPSIZE); lua_sethook(L, nhl_hookfn, LUA_MASKCOUNT, NHL_SB_STEPSIZE);
} }
#endif #endif
@@ -2337,28 +2335,28 @@ nhlL_newstate (nhl_sandbox_info *sbi) {
(See end of comment for conclusion.) (See end of comment for conclusion.)
to make packages safe, we need something like: to make packages safe, we need something like:
if setuid/setgid (but does NH drop privs before we can check? TBD) if setuid/setgid (but does NH drop privs before we can check? TBD)
unsetenv LUA_CPATH, LUA_CPATH_5_4 (and this needs to change with unsetenv LUA_CPATH, LUA_CPATH_5_4 (and this needs to change with
version) maybe more version) maybe more
luaopen_package calls getenv luaopen_package calls getenv
unsetenv(LUA_PATH_VAR) unsetenv(LUA_PATH_VAR)
unsetenv(LUA_CPATH_VAR) unsetenv(LUA_CPATH_VAR)
unsetenv(LUA_PATH_VAR LUA_VERSUFFIX) unsetenv(LUA_PATH_VAR LUA_VERSUFFIX)
unsetenv(LUA_CPATH_VAR LUA_VERSUFFIX) unsetenv(LUA_CPATH_VAR LUA_VERSUFFIX)
package.config package.config
oackage[fieldname] = path oackage[fieldname] = path
NB: LUA_PATH_DEFAULT and LUA_CPATH_DEFAULT must be safe NB: LUA_PATH_DEFAULT and LUA_CPATH_DEFAULT must be safe
or we must setenv LUA_PATH_VAR and LUA_CPATH_VAR to something or we must setenv LUA_PATH_VAR and LUA_CPATH_VAR to something
safe safe
or we could just clean out the searchers table? or we could just clean out the searchers table?
package.searchers[preload,Lua,C,Croot] package.searchers[preload,Lua,C,Croot]
also, can setting package.path to something odd get Lua to load files also, can setting package.path to something odd get Lua to load files
it shouldn't? (see docs package.searchers) it shouldn't? (see docs package.searchers)
set (and disallow changing) package.cpath (etc?) set (and disallow changing) package.cpath (etc?)
loadlib.c: loadlib.c:
lsys_load -> dlopen Kill with undef LUA_USE_DLOPEN LUA_DL_DLL lsys_load -> dlopen Kill with undef LUA_USE_DLOPEN LUA_DL_DLL
searchpath -> readable -> fopen searchpath -> readable -> fopen
<- ll_searchpath <- ll_searchpath
<- findfile <- {searchers C, Croot, Lua} <- findfile <- {searchers C, Croot, Lua}
Probably the best thing to do is replace G.require with our own function Probably the best thing to do is replace G.require with our own function
that does whatever it is we need and completely ignore the package library. that does whatever it is we need and completely ignore the package library.
*/ */
@@ -2371,3 +2369,5 @@ BUT how do we compact the current history?
new branch, then compress there new branch, then compress there
XXX XXX
*/ */
/*nhlua.c*/