AP_Scripting: add require with sandbox inheritence

This commit is contained in:
bugobliterator 2023-03-09 15:47:50 +11:00 committed by Andrew Tridgell
parent 350f718745
commit 306b14d8dc
8 changed files with 114 additions and 51 deletions

View File

@ -94,6 +94,8 @@ public:
// PWMSource storage
uint8_t num_pwm_source;
AP_HAL::PWMSource *_pwm_source[SCRIPTING_MAX_NUM_PWM_SOURCE];
int get_current_ref() { return current_ref; }
void set_current_ref(int ref) { current_ref = ref; }
private:
@ -116,7 +118,7 @@ private:
bool _stop; // true if scripts should be stopped
static AP_Scripting *_singleton;
int current_ref;
};
namespace AP {

View File

@ -501,6 +501,13 @@ LUAMOD_API int luaopen_base (lua_State *L) {
LUAMOD_API int luaopen_base_sandbox(lua_State *L) {
luaL_setfuncs(L, base_funcs, 0);
// for debugging what has been loaded
// lua_pushvalue(L, -1);
// lua_setfield(L, -2, "_Sandbox");
// lua_pushglobaltable(L);
// lua_pushvalue(L, -1);
// lua_setfield(L, -3, "_G");
// lua_pop(L, 1);
return 1;
}

View File

@ -74,7 +74,9 @@ static const int CLIBS = 0;
/*
** unload library 'lib'
*/
#if !defined(ARDUPILOT_BUILD)
static void lsys_unloadlib (void *lib);
#endif
/*
** load C library in file 'path'. If 'seeglb', load with all names in
@ -227,10 +229,11 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#define DLMSG "dynamic libraries not enabled; check your Lua installation"
#if !defined(ARDUPILOT_BUILD)
static void lsys_unloadlib (void *lib) {
(void)(lib); /* not used */
}
#endif
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
@ -342,6 +345,7 @@ static void addtoclib (lua_State *L, const char *path, void *plib) {
** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib
** handles in list CLIBS
*/
#if !defined(ARDUPILOT_BUILD)
static int gctm (lua_State *L) {
lua_Integer n = luaL_len(L, 1);
for (; n >= 1; n--) { /* for each handle, in reverse order */
@ -351,6 +355,7 @@ static int gctm (lua_State *L) {
}
return 0;
}
#endif
@ -509,6 +514,7 @@ static int searcher_Lua (lua_State *L) {
** fails, it also tries "luaopen_Y".) If there is no ignore mark,
** look for a function named "luaopen_modname".
*/
#if !defined(ARDUPILOT_BUILD)
static int loadfunc (lua_State *L, const char *filename, const char *modname) {
const char *openfunc;
const char *mark;
@ -564,12 +570,30 @@ static int searcher_preload (lua_State *L) {
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1;
}
#endif
static void findloader (lua_State *L, const char *name) {
int i;
luaL_Buffer msg; /* to build error message */
luaL_buffinit(L, &msg);
lua_pushstring(L, name);
#if defined(ARDUPILOT_BUILD)
// since we only use lua modules there's no point
// in searching for C or other types of modules
// so we just call the lua searcher
searcher_Lua(L);
if (lua_isfunction(L, -2)) { /* module loader found? */
return; /* module loader already on stack */
} else if (lua_isstring(L, -2)) { /* searcher returned error message? */
lua_pop(L, 1); /* remove extra return */
luaL_addvalue(&msg); /* concatenate error message */
} else {
lua_pop(L, 2); /* remove both returns */
}
// module not found
lua_pop(L, 1); /* remove nil */
luaL_pushresult(&msg); /* create error message */
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
#else
/* push 'package.searchers' to index 3 in the stack */
if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE)
luaL_error(L, "'package.searchers' must be a table");
@ -591,28 +615,33 @@ static void findloader (lua_State *L, const char *name) {
else
lua_pop(L, 2); /* remove both returns */
}
#endif
}
static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
lua_settop(L, 1); /* LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, 2, name); /* LOADED[name] */
lua_settop(L, 1);
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_get_current_ref()); /* get the current script */
lua_getupvalue(L, 2, 1); /* get the environment of the script */
lua_getfield(L, 3, LUA_LOADED_TABLE); /* get _LOADED */
lua_getfield(L, 4, name); /* LOADED[name] */
if (lua_toboolean(L, -1)) /* is it there? */
return 1; /* package is already loaded */
/* else must load package */
lua_pop(L, 1); /* remove 'getfield' result */
findloader(L, name);
lua_pushvalue(L, 3); /* push current script's environment */
lua_setupvalue(L, -3, 1); /* set the environment of the module */
lua_pushstring(L, name); /* pass name as argument to module loader */
lua_insert(L, -2); /* name is 1st argument (before search data) */
lua_call(L, 2, 1); /* run loader to load module */
if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* LOADED[name] = returned value */
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
lua_setfield(L, 4, name); /* LOADED[name] = returned value */
if (lua_getfield(L, 4, name) == LUA_TNIL) { /* module set no value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* LOADED[name] = true */
lua_setfield(L, 4, name); /* LOADED[name] = true */
}
return 1;
}
@ -713,9 +742,9 @@ static const luaL_Reg pk_funcs[] = {
#endif
/* placeholders */
{"preload", NULL},
{"cpath", NULL},
// {"cpath", NULL},
{"path", NULL},
{"searchers", NULL},
// {"searchers", NULL},
{"loaded", NULL},
{NULL, NULL}
};
@ -729,7 +758,7 @@ static const luaL_Reg ll_funcs[] = {
{NULL, NULL}
};
#if !defined(ARDUPILOT_BUILD)
static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] =
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
@ -762,29 +791,31 @@ static void createclibstable (lua_State *L) {
lua_setmetatable(L, -2);
lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */
}
#endif
LUAMOD_API int luaopen_package (lua_State *L) {
createclibstable(L);
// createclibstable(L);
luaL_newlib(L, pk_funcs); /* create 'package' table */
createsearcherstable(L);
// createsearcherstable(L);
/* set paths */
setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
// setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
lua_setfield(L, -2, "config");
/* set field 'loaded' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
luaL_getsubtable(L, -3, LUA_LOADED_TABLE);
lua_setfield(L, -2, "loaded");
/* set field 'preload' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
luaL_getsubtable(L, -3, LUA_PRELOAD_TABLE);
lua_setfield(L, -2, "preload");
lua_pushglobaltable(L);
lua_pushvalue(L, -3);
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */
lua_pop(L, 1); /* pop global table */
lua_pop(L, 1);
return 1; /* return 'package' table */
}

View File

@ -17,6 +17,7 @@
#ifndef LUA_SUPPORT_LOAD_BINARY
#define LUA_SUPPORT_LOAD_BINARY 0
#endif
#include <AP_Scripting/lua_common_defs.h>
/*
** ===================================================================
@ -207,11 +208,10 @@
#else /* }{ */
#define LUA_ROOT "/usr/local/"
#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
#define LUA_LDIR SCRIPTING_DIRECTORY "/modules/"
#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
"./?.lua;" "./?/init.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"

View File

@ -572,3 +572,9 @@ int lua_get_PWMSource(lua_State *L) {
return 1;
}
int lua_get_current_ref()
{
auto *scripting = AP::scripting();
return scripting->get_current_ref();
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <AP_HAL/AP_HAL_Boards.h>
#ifndef REPL_DIRECTORY
#if HAL_OS_FATFS_IO
#define REPL_DIRECTORY "/APM/repl"
#else
#define REPL_DIRECTORY "./repl"
#endif //HAL_OS_FATFS_IO
#endif // REPL_DIRECTORY
#ifndef SCRIPTING_DIRECTORY
#if HAL_OS_FATFS_IO
#define SCRIPTING_DIRECTORY "/APM/scripts"
#else
#define SCRIPTING_DIRECTORY "./scripts"
#endif //HAL_OS_FATFS_IO
#endif // SCRIPTING_DIRECTORY
#ifndef REPL_IN
#define REPL_IN REPL_DIRECTORY "/in"
#endif // REPL_IN
#ifndef REPL_OUT
#define REPL_OUT REPL_DIRECTORY "/out"
#endif // REPL_OUT
int lua_get_current_ref();

View File

@ -23,6 +23,7 @@
#define DISABLE_INTERRUPTS_FOR_SCRIPT_RUN 0
extern const AP_HAL::HAL& hal;
#define ENABLE_DEBUG_MODULE 0
bool lua_scripts::overtime;
jmp_buf lua_scripts::panic_jmp;
@ -198,6 +199,12 @@ lua_scripts::script_info *lua_scripts::load_script(lua_State *L, char *filename)
void lua_scripts::create_sandbox(lua_State *L) {
lua_newtable(L);
luaopen_base_sandbox(L);
#if ENABLE_DEBUG_MODULE
lua_pushstring(L, "debug");
luaopen_debug(L);
lua_settable(L, -3);
#endif
lua_pushstring(L, "math");
luaopen_math(L);
lua_settable(L, -3);
@ -213,8 +220,11 @@ void lua_scripts::create_sandbox(lua_State *L) {
lua_pushstring(L, "utf8");
luaopen_utf8(L);
lua_settable(L, -3);
load_generated_sandbox(L);
lua_pushstring(L, "package");
luaopen_package(L);
lua_settable(L, -3);
load_generated_sandbox(L);
}
void lua_scripts::load_all_scripts_in_dir(lua_State *L, const char *dirname) {
@ -294,6 +304,7 @@ void lua_scripts::run_next_script(lua_State *L) {
// pop the function to the top of the stack
lua_rawgeti(L, LUA_REGISTRYINDEX, script->lua_ref);
AP::scripting()->set_current_ref(script->lua_ref);
if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
if (overtime) {

View File

@ -23,33 +23,10 @@
#include <GCS_MAVLink/GCS_MAVLink.h>
#include <AP_HAL/Semaphores.h>
#include <AP_Common/MultiHeap.h>
#include "lua_common_defs.h"
#include "lua/src/lua.hpp"
#ifndef REPL_DIRECTORY
#if HAL_OS_FATFS_IO
#define REPL_DIRECTORY "/APM/repl"
#else
#define REPL_DIRECTORY "./repl"
#endif //HAL_OS_FATFS_IO
#endif // REPL_DIRECTORY
#ifndef SCRIPTING_DIRECTORY
#if HAL_OS_FATFS_IO
#define SCRIPTING_DIRECTORY "/APM/scripts"
#else
#define SCRIPTING_DIRECTORY "./scripts"
#endif //HAL_OS_FATFS_IO
#endif // SCRIPTING_DIRECTORY
#ifndef REPL_IN
#define REPL_IN REPL_DIRECTORY "/in"
#endif // REPL_IN
#ifndef REPL_OUT
#define REPL_OUT REPL_DIRECTORY "/out"
#endif // REPL_OUT
class lua_scripts
{
public:
@ -78,7 +55,6 @@ public:
private:
void create_sandbox(lua_State *L);
void repl_cleanup(void);
typedef struct script_info {
@ -143,6 +119,7 @@ private:
static HAL_Semaphore error_msg_buf_sem;
static uint8_t print_error_count;
static uint32_t last_print_ms;
int current_ref;
public:
// must be static for use in atpanic, public to allow bindings to issue none fatal warnings