]> granicus.if.org Git - nethack/commitdiff
Lua sandbox
authornhkeni <keni@his.com>
Sat, 7 May 2022 21:45:36 +0000 (17:45 -0400)
committernhkeni <keni@his.com>
Sat, 7 May 2022 21:45:36 +0000 (17:45 -0400)
Change table format to handle functions never to be included.
Clean up bit masks and tables of functions.
Remove some old comments and out-of-date code.

include/global.h
src/nhlua.c

index b05e809c3e9513472936327809627049d5201006..41659e4dc724bf17389471aaaa21c3101989704a 100644 (file)
@@ -514,12 +514,7 @@ typedef struct nhl_sandbox_info {
 #define NHL_SB_SAFE        0x80000000
     /* Access to Lua version information. */
 #define NHL_SB_VERSION     0x40000000
-#ifdef notyet
-    /* XXX These need to be replaced. */
-#define NHL_SB_CANREAD     0x20000000
-#define NHL_SB_CANWRITE    0x10000000
-#endif
-    /* Debugging library - highly unsafe. */
+    /* Debugging library - mostly unsafe. */
 #define NHL_SB_DEBUGGING   0x08000000
     /* Use with memlimit/steps/perpcall to get usage. */
 #define NHL_SB_REPORT      0x04000000
@@ -528,24 +523,30 @@ typedef struct nhl_sandbox_info {
 
 /* Low level groups.  If you need these, you probably need to define
  * a new high level group instead. */
-#define NHL_SB_DB          0x00000001
-#define NHL_SB_STRING      0x00000002
-#define NHL_SB_TABLE       0x00000004
-#define NHL_SB_COROUTINE   0x00000008
-#define NHL_SB_MATH        0x00000010
-#define NHL_SB_UTF8        0x00000020
+#define NHL_SB_STRING      0x00000001
+#define NHL_SB_TABLE       0x00000002
+#define NHL_SB_COROUTINE   0x00000004
+#define NHL_SB_MATH        0x00000008
+#define NHL_SB_UTF8        0x00000010
 #ifdef notyet
-#define NHL_SB_PACKAGE     0x00000040
-#define NHL_SB_IO          0x00000080
-#define NHL_SB_OS          0x00000100
+#define NHL_SB_IO          0x00000020
 #endif
+#define NHL_SB_OS          0x00000040
+
+#define NHL_SB_BASEMASK    0x00000f80
+#define NHL_SB_BASE_BASE   0x00000080
+#define NHL_SB_BASE_ERROR  0x00000100
+#define NHL_SB_BASE_META   0x00000200
+#define NHL_SB_BASE_GC     0x00000400
+#define NHL_SB_BASE_UNSAFE 0x00000800
+
+#define NHL_SB_DBMASK      0x00003000
+#define NHL_SB_DB_DB       0x00001000
+#define NHL_SB_DB_SAFE     0x00002000
 
-#define NHL_SB_BASEMASK    0x0001f000
-#define NHL_SB_BASE_BASE   0x00001000
-#define NHL_SB_BASE_ERROR  0x00002000
-#define NHL_SB_BASE_META   0x00004000
-#define NHL_SB_BASE_GC     0x00008000
-#define NHL_SB_BASE_UNSAFE 0x00010000
+#define NHL_SB_OSMASK      0x0000c000
+#define NHL_SB_OS_TIME     0x00004000
+#define NHL_SB_OS_FILES    0x00008000
 
 #define NHL_SB_ALL         0x0000ffff
 
index 631e896ca3cf8b4712383eaa9b7ba9d87a4ee67e..dbb5b7ae8d5cc35aa8988bb802796d396defcff3 100644 (file)
@@ -1754,42 +1754,127 @@ RESTORE_WARNINGS
  ***/
 #ifdef NHL_SANDBOX
 
+enum ewhen {NEVER, IFFLAG, EOT};
+struct e {
+    enum ewhen when;
+    const char *fnname;
+};
+
 /* NHL_BASE_BASE - safe things */
-static const char *ct_base_base[] = {
-    "ipairs", "next", "pairs", "pcall", "rawequal", "rawlen", "select",
-    "tonumber", "tostring", "type", "xpcall", NULL
+static struct e ct_base_base[] = {
+    {IFFLAG, "ipairs"},
+    {IFFLAG, "next"},
+    {IFFLAG, "pairs"},
+    {IFFLAG, "pcall"},
+    {IFFLAG, "select"},
+    {IFFLAG, "tonumber"},
+    {IFFLAG, "tostring"},
+    {IFFLAG, "type"},
+    {IFFLAG, "xpcall"},
+    {EOT, NULL}
 };
 
 /* NHL_BASE_ERROR - not really safe - might not want Lua to kill the process */
-static const char *ct_base_error[] = {
-    "assert",   /* ok, calls error */
-    "error",    /* ok, calls G->panic */
-    /* "print",        not ok - calls lua_writestring/lua_writeline -> stdout*/
-    /* "warn", not ok - calls lua_writestringerror -> stderr */
-    NULL
+static struct e ct_base_error[] = {
+    {IFFLAG, "assert"},   /* ok, calls error */
+    {IFFLAG, "error"},    /* ok, calls G->panic */
+    {NEVER, "print"}, /*not ok - calls lua_writestring/lua_writeline -> stdout*/
+    {NEVER, "warn"}, /*not ok - calls lua_writestringerror -> stderr*/
+    {EOT, NULL}
 };
 
 /* NHL_BASE_META - metatable access */
-static const char *ct_base_meta[] = {
-    "getmetatable", "rawget", "rawset", "setmetatable", NULL
+static struct e ct_base_meta[] = {
+    {IFFLAG, "getmetatable"},
+    {IFFLAG, "rawequal"},
+    {IFFLAG, "rawget"},
+    {IFFLAG, "rawlen"},
+    {IFFLAG, "rawset"},
+    {IFFLAG, "setmetatable"},
+    {EOT, NULL}
 };
 
 /* NHL_BASE_GC - questionable safety */
-static const char *ct_base_iffy[] = {
-    "collectgarbage", NULL
+static struct e ct_base_iffy[] = {
+    {IFFLAG, "collectgarbage"},
+    {EOT, NULL}
 };
 
 /* NHL_BASE_UNSAFE - include only if required */
-static const char *ct_base_unsafe[] = {
-    "dofile", "loadfile", "load", NULL
+static struct e ct_base_unsafe[] = {
+    {IFFLAG, "dofile"},
+    {IFFLAG, "loadfile"},
+    {IFFLAG, "load"},
+    {EOT, NULL}
+};
+
+/* no ct_co_ tables; all fns at same level of concern */
+/* no ct_string_ tables; all fns at same level of concern */
+/* no ct_table_ tables; all fns at same level of concern (but
+   sort can take a lot of time and can't be caught by the step limit */
+/* no ct_utf8_ tables; all fns at same level of concern */
+
+
+/* possible ct_debug tables - likely to need changes */
+static struct e ct_debug_debug[] = {
+    {NEVER,  "debug"},         /* uses normal I/O so needs re-write */
+    {IFFLAG, "getuservalue"},
+    {NEVER,  "gethook"},       /* see sethook */
+    {IFFLAG, "getinfo"},
+    {IFFLAG, "getlocal"},
+    {IFFLAG, "getregistry"},
+    {IFFLAG, "getmetatable"},
+    {IFFLAG, "getupvalue"},
+    {IFFLAG, "upvaluejoin"},
+    {IFFLAG, "upvalueid"},
+    {IFFLAG, "setuservalue"},
+    {NEVER,  "sethook"},       /* used for memory and step limits */
+    {IFFLAG, "setlocal"},
+    {IFFLAG, "setmetatable"},
+    {IFFLAG, "setupvalue"},
+    {IFFLAG, "setcstacklimit"},
+    {EOT, NULL}
+};
+static struct e ct_debug_safe[] = {
+    {IFFLAG, "traceback"},
+    {EOT, NULL}
+};
+
+/* possible ct_os_ tables */
+static struct e ct_os_time[] = {
+    {IFFLAG, "clock"},         /* is this portable? XXX */
+    {IFFLAG, "date"},
+    {IFFLAG, "difftime"},
+    {IFFLAG, "time"},
+    {EOT, NULL}
+};
+
+static struct e ct_os_files[] = {
+    {NEVER, "execute"},                /* not portable */
+    {NEVER, "exit"},
+    {NEVER, "getenv"},
+    {IFFLAG, "remove"},
+    {IFFLAG, "rename"},
+    {NEVER, "setlocale"},
+    {NEVER, "tmpname"},
+    {EOT, NULL}
 };
 
+
+#define DROPIF(flag, lib, ct) \
+    nhl_clearfromtable(L, !!(lflags & flag), lib, ct)
+
 static void
-nhl_clearfromtable(lua_State *L, int tndx, const char **todo)
+nhl_clearfromtable(lua_State *L, int flag, int tndx, struct e *todo)
 {
-    while(*todo){
+    while(todo->when != EOT){
        lua_pushnil(L);
-       lua_setfield(L, tndx, *todo++);
+               /* if we load the library at all, NEVER items must be erased
+                * and IFFLAG items should be erased if !flag */
+       if(todo->when==NEVER || !flag) {
+           lua_setfield(L, tndx, todo->fnname);
+       }
+       todo++;
     }
 }
 #endif
@@ -2014,27 +2099,14 @@ DISABLE_WARNING_CONDEXPR_IS_CONSTANT
 #ifdef NHL_SANDBOX
 static void
 nhlL_openlibs(lua_State *L, uint32_t lflags){
-    uint32_t needbase;
-
        /* translate lflags from user-friendly to internal */
     if (NHL_SB_DEBUGGING & lflags){
-#if 1  /* XXX */
-       lflags |= NHL_SB_DB;
-/* XXX
-Should these be available as safe or as a low level group?
-debug.getinfo
-debug.traceback?
-*/
-#endif
+       lflags |= NHL_SB_DB_SAFE;
     }
        /* only for debugging the sandbox integration */
     if (NHL_SB_ALL & lflags){
        lflags = -1;
-    } else if ((NHL_SB_SAFE
-#ifdef notyet
-|NHL_SB_CANREAD
-#endif
-           ) & lflags){
+    } else if (NHL_SB_SAFE & lflags){
        lflags |= NHL_SB_BASE_BASE;
        lflags |= NHL_SB_COROUTINE;
        lflags |= NHL_SB_TABLE;
@@ -2043,30 +2115,22 @@ debug.traceback?
        lflags |= NHL_SB_UTF8;
     } else if (NHL_SB_VERSION){
        lflags |= NHL_SB_BASE_BASE;
+    }
 #ifdef notyet
-    } else if (NHL_SB_CANREAD & lflags){
-/* QQQ */
-/*
-canread may be wrong.
-How about:
-    - sets of fns (as below, as base)
+/*  Handling I/O is complex, so it's not available yet.  I'll
+finish it if and when we need it. (keni)
     - hooked open; array of tuples of (r/w/rw/a/etc, directory pat, file pat)
 
-XXX
-really don't have anything here
-because IO is too broad?
-we need to split it like BASE - load then delete:
-SAFEIO:
 {"close", io_close},   but with no args closes default output, so needs hook
 {"flush", io_flush},
 {"lines", io_lines},   hook due to filename
-{"open", io_open},  but we need a hooked version:
+{"open", io_open},  hooked version:
     only safe if mode not present or == "r"
        or WRITEIO
     only safe if path has no slashes
        XXX probably need to be: matches port-specific list of paths
        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 fopen/fread/fwrite/feof/ftell (etc?)
        ugh: lauxlib.c uses getc() below luaL_loadfilex
@@ -2084,39 +2148,24 @@ UNSAFEIO:
   {"tmpfile", io_tmpfile},
 */
 #endif
-    }
-
-/*
-multiple levels - io.*, FILE.* - can we hook FILE.*?
-  see liolib.c:{meta, createmeta, luaopen_io}
-// do we need anything else? meta?
-*/
 
-    needbase = lflags & NHL_SB_BASEMASK;
-    if(needbase){
+    if(lflags & NHL_SB_BASEMASK){
+       int baselib;
+           /* load the entire library ... */
        luaL_requiref(L, LUA_GNAME, luaopen_base, 1);
-       int baselib = lua_gettop(L);
 
-           /* now remove everything not requested */
-       uint16_t rejectflags = ~lflags;
-#define DROPIF(flag, x, table) \
-    if(rejectflags & flag){ nhl_clearfromtable(L, x, table); }
+       baselib = lua_gettop(L);
 
+           /* ... and remove anything unsupported or not requested */
        DROPIF(NHL_SB_BASE_BASE, baselib, ct_base_base);
        DROPIF(NHL_SB_BASE_ERROR, baselib, ct_base_error);
        DROPIF(NHL_SB_BASE_META, baselib, ct_base_meta);
        DROPIF(NHL_SB_BASE_GC, baselib, ct_base_iffy);
        DROPIF(NHL_SB_BASE_UNSAFE, baselib, ct_base_unsafe);
-#undef DROPIF
-       lua_pop(L, 1);
-    }
 
-#ifdef notyet
-    if(lflags & NHL_SB_PACKAGE){
-       luaL_requiref(L, LUA_LOADLIBNAME, luaopen_package, 1);
        lua_pop(L, 1);
     }
-#endif
+
     if(lflags & NHL_SB_COROUTINE){
        luaL_requiref(L, LUA_COLIBNAME, luaopen_coroutine, 1);
        lua_pop(L, 1);
@@ -2132,12 +2181,16 @@ multiple levels - io.*, FILE.* - can we hook FILE.*?
        if(!hook_open(L))
            panic("can't hook io.open");
     }
-// maybe ok: time, difftime, getenv clock date
-    if(lflags & NHL_SB_OS){
+#endif
+    if(lflags & NHL_SB_OSMASK){
+       int oslib;
        luaL_requiref(L, LUA_OSLIBNAME, luaopen_os, 1);
+       oslib = lua_gettop(L);
+       DROPIF(NHL_SB_OS_TIME, oslib, ct_os_time);
+       DROPIF(NHL_SB_OS_FILES, oslib, ct_os_files);
        lua_pop(L, 1);
     }
-#endif
+
     if(lflags & NHL_SB_STRING){
        luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
        lua_pop(L, 1);
@@ -2153,8 +2206,12 @@ multiple levels - io.*, FILE.* - can we hook FILE.*?
        luaL_requiref(L, LUA_UTF8LIBNAME, luaopen_utf8, 1);
        lua_pop(L, 1);
     }
-    if(lflags & NHL_SB_DB){
+    if(lflags & NHL_SB_DBMASK){
+       int dblib;
        luaL_requiref(L, LUA_DBLIBNAME, luaopen_debug, 1);
+       dblib = lua_gettop(L);
+       DROPIF(NHL_SB_DB_DB, dblib, ct_debug_debug);
+       DROPIF(NHL_SB_DB_SAFE, dblib, ct_debug_safe);
        lua_pop(L, 1);
     }
 }