int lua_sandbox_timer_event(lua_sandbox* lsb, long long ns) { if (lsb == NULL || lsb->m_lua == NULL) { return 1; } lua_sethook(lsb->m_lua, instruction_manager, LUA_MASKCOUNT, lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_LIMIT]); lua_getglobal(lsb->m_lua, "timer_event"); if (!lua_isfunction(lsb->m_lua, -1)) { snprintf(lsb->m_error_message, ERROR_SIZE, "timer_event() function was not found"); sandbox_terminate(lsb); return 1; } lua_pushnumber(lsb->m_lua, ns); if (lua_pcall(lsb->m_lua, 1, 0, 0) != 0) { snprintf(lsb->m_error_message, ERROR_SIZE, "timer_event() %s", lua_tostring(lsb->m_lua, -1)); sandbox_terminate(lsb); return 1; } lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] = instruction_usage(lsb); if (lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM]) { lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM] = lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT]; } lua_gc(lsb->m_lua, LUA_GCCOLLECT, 0); return 0; }
int lua_sandbox_init(lua_sandbox* lsb, const char* data_file) { if (lsb == NULL || lsb->m_lua != NULL) { return 0; } if (lsb->m_lua_file == NULL) { snprintf(lsb->m_error_message, ERROR_SIZE, "no Lua script provided"); sandbox_terminate(lsb); return 1; } lsb->m_lua = lua_newstate(memory_manager, lsb); if (lsb->m_lua == NULL) { snprintf(lsb->m_error_message, ERROR_SIZE, "out of memory"); sandbox_terminate(lsb); return 2; } load_library(lsb->m_lua, "", luaopen_base, disable_base_functions); load_library(lsb->m_lua, LUA_MATHLIBNAME, luaopen_math, disable_none); load_library(lsb->m_lua, LUA_OSLIBNAME, luaopen_os, disable_os_functions); load_library(lsb->m_lua, LUA_STRLIBNAME, luaopen_string, disable_none); load_library(lsb->m_lua, LUA_TABLIBNAME, luaopen_table, disable_none); luaopen_circular_buffer(lsb->m_lua); lua_pushlightuserdata(lsb->m_lua, (void*)lsb); lua_pushcclosure(lsb->m_lua, &read_message, 1); lua_setglobal(lsb->m_lua, "read_message"); lua_pushlightuserdata(lsb->m_lua, (void*)lsb); lua_pushcclosure(lsb->m_lua, &output, 1); lua_setglobal(lsb->m_lua, "output"); lua_pushlightuserdata(lsb->m_lua, (void*)lsb); lua_pushcclosure(lsb->m_lua, &inject_message, 1); lua_setglobal(lsb->m_lua, "inject_message"); lua_sethook(lsb->m_lua, instruction_manager, LUA_MASKCOUNT, lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_LIMIT]); if (luaL_dofile(lsb->m_lua, lsb->m_lua_file) != 0) { snprintf(lsb->m_error_message, ERROR_SIZE, "%s", lua_tostring(lsb->m_lua, -1)); sandbox_terminate(lsb); return 3; } else { lua_gc(lsb->m_lua, LUA_GCCOLLECT, 0); lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] = instruction_usage(lsb); if (lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM]) { lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM] = lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT]; } lsb->m_status = STATUS_RUNNING; if (data_file != NULL && strlen(data_file) > 0) { return restore_global_data(lsb, data_file); } } return 0; }
int lua_sandbox_process_message(lua_sandbox* lsb) { if (lsb == NULL || lsb->m_lua == NULL) { return 1; } lua_sethook(lsb->m_lua, instruction_manager, LUA_MASKCOUNT, lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_LIMIT]); lua_getglobal(lsb->m_lua, "process_message"); if (!lua_isfunction(lsb->m_lua, -1)) { snprintf(lsb->m_error_message, ERROR_SIZE, "process_message() function was not found"); sandbox_terminate(lsb); return 1; } if (lua_pcall(lsb->m_lua, 0, 1, 0) != 0) { snprintf(lsb->m_error_message, ERROR_SIZE, "process_message() %s", lua_tostring(lsb->m_lua, -1)); sandbox_terminate(lsb); return 1; } if (!lua_isnumber(lsb->m_lua, 1)) { snprintf(lsb->m_error_message, ERROR_SIZE, "process_message() must return a single numeric value"); sandbox_terminate(lsb); return 1; } int status = (int)lua_tointeger(lsb->m_lua, 1); lua_pop(lsb->m_lua, 1); lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] = instruction_usage(lsb); if (lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM]) { lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_MAXIMUM] = lsb->m_usage[USAGE_TYPE_INSTRUCTION][USAGE_STAT_CURRENT]; } return status; }
char* lua_sandbox_destroy(lua_sandbox* lsb, const char* data_file) { char* err = NULL; if (lsb == NULL) return err; if (lsb->m_lua != NULL && data_file != NULL && strnlen(data_file, 1) > 0) { if (preserve_global_data(lsb, data_file) != 0) { size_t len = strnlen(lsb->m_error_message, ERROR_SIZE); err = malloc(len + 1); if (err != NULL) { strcpy(err, lsb->m_error_message); } } } sandbox_terminate(lsb); free(lsb->m_output.m_data); free(lsb->m_lua_file); free(lsb); return err; }
int restore_global_data(lua_sandbox* lsb, const char* data_file) { unsigned configured_memory = lsb->m_usage[USAGE_TYPE_MEMORY][USAGE_STAT_LIMIT]; // Increase the sandbox limits during restoration. lsb->m_usage[USAGE_TYPE_MEMORY][USAGE_STAT_LIMIT] = MAX_MEMORY * 2; // Clear the sandbox instruction limit hook. lua_sethook(lsb->m_lua, instruction_manager, 0, 0); if (luaL_dofile(lsb->m_lua, data_file) != 0) { snprintf(lsb->m_error_message, ERROR_SIZE, "restore_global_data %s", lua_tostring(lsb->m_lua, -1)); sandbox_terminate(lsb); return 2; } else { lua_gc(lsb->m_lua, LUA_GCCOLLECT, 0); lsb->m_usage[USAGE_TYPE_MEMORY][USAGE_STAT_LIMIT] = configured_memory; lsb->m_usage[USAGE_TYPE_MEMORY][USAGE_STAT_MAXIMUM] = lsb->m_usage[USAGE_TYPE_MEMORY][USAGE_STAT_CURRENT]; } return 0; }