Lua sandbox
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.
This commit is contained in:
@@ -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 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_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_OSMASK 0x0000c000
|
||||
#define NHL_SB_OS_TIME 0x00004000
|
||||
#define NHL_SB_OS_FILES 0x00008000
|
||||
|
||||
#define NHL_SB_ALL 0x0000ffff
|
||||
|
||||
|
||||
199
src/nhlua.c
199
src/nhlua.c
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user