diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-07-21 16:32:07 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-07-21 16:32:07 +0100 |
commit | b5460017f1e88baf283ebfaad341cd094f5041ff (patch) | |
tree | 445386ab7dbce5dbd3e97078225bb9be3e939960 /lib | |
parent | b4d2d633cd88308487aa6e2b689a4328ce6023c1 (diff) | |
download | supple-b5460017f1e88baf283ebfaad341cd094f5041ff.tar.gz |
Lots of stuff
Diffstat (limited to 'lib')
-rw-r--r-- | lib/supple.lua | 4 | ||||
-rw-r--r-- | lib/supple/capi.c | 143 | ||||
-rw-r--r-- | lib/supple/objects.lua | 111 | ||||
-rw-r--r-- | lib/supple/request.lua | 37 |
4 files changed, 295 insertions, 0 deletions
diff --git a/lib/supple.lua b/lib/supple.lua index 5fc405b..0d87d20 100644 --- a/lib/supple.lua +++ b/lib/supple.lua @@ -8,6 +8,8 @@ -- local capi = require 'supple.capi' +local request = require 'supple.request' +local objects = require 'supple.objects' local _VERSION = 1 local _ABI = 1 @@ -16,6 +18,8 @@ local VERSION = "Supple Version " .. tostring(_VERSION) return { capi = capi, + request = request, + objects = objects, _VERSION = _VERSION, VERSION = VERSION, _ABI = _ABI, diff --git a/lib/supple/capi.c b/lib/supple/capi.c index 139cfe6..c413c20 100644 --- a/lib/supple/capi.c +++ b/lib/supple/capi.c @@ -13,13 +13,156 @@ #include <lua.h> #include <lauxlib.h> +#include <string.h> + /* The API exposed, increment on backward-compatible changes */ #define CAPI_API 1 /* The ABI exposed, increment on backward-incompatible changes */ #define CAPI_ABI 1 +static int +supple_capi_explain(lua_State *L) +{ + int one_type; + if (lua_gettop(L) != 2) { + return luaL_error(L, "Expected 2 args got %d", lua_gettop(L)); + } + one_type = lua_type(L, 1); + if ((one_type != LUA_TTABLE) && + (one_type != LUA_TFUNCTION) && + (one_type != LUA_TUSERDATA)) { + return luaL_error(L, + "Expected one of table, function or userdata. " \ + "Got %s instead", + lua_typename(L, one_type)); + } + if (lua_type(L, 2) != LUA_TSTRING) { + return luaL_error(L, "Expected string, got %s instead", + lua_typename(L, lua_type(L, 2))); + } + lua_newtable(L); + lua_pushvalue(L, 2); + lua_setfield(L, -2, "tag"); + lua_pushstring(L, lua_typename(L, one_type)); + lua_setfield(L, -2, "type"); + if (one_type != LUA_TFUNCTION) { + /* Get the metatable */ + if (lua_getmetatable(L, 1) != 0) { + int idx = 1; + /* Prepare a methods table */ + lua_newtable(L); + lua_pushnil(L); /* For iterating */ + while (lua_next(L, -3) != 0) { /* Iterate the metatable */ + lua_pop(L, 1); /* Don't need the value */ + if (lua_type(L, -1) != LUA_TSTRING) { + /* Not a string key */ + } else if (strcmp(lua_tostring(L, -1), + "__mode") == 0) { + /* mode key is ignored */ + } else { + /* dup */ + lua_pushvalue(L, -1); + /* And copy into methods */ + lua_rawseti(L, -3, idx++); + } + /* Key is left ready for lua_next() */ + } + /* Stuff the methods table into the return */ + lua_setfield(L, -3, "methods"); + /* And pop the metatable */ + lua_pop(L, 1); + } + } + /* And return the new table */ + return 1; +} + +static int +supple_capi_proxy_tostring(lua_State *L) +{ + /* arg 1 is the object, upvalue 1 is the original type */ + const char *orig_type = lua_tostring(L, lua_upvalueindex(1)); + lua_pushfstring(L, "%s: %p", orig_type, lua_touserdata(L, 1)); + return 1; +} + +static int +supple_capi_proxy_type(lua_State *L) +{ + /* arg 1 is the object, upvalue 1 is the original type */ + lua_pushvalue(L, lua_upvalueindex(1)); + return 1; +} + +static int +supple_capi_new_proxy(lua_State *L) +{ + void *proxy_ptr; + /* Input is a type string */ + if (lua_type(L, 1) != LUA_TSTRING) { + return luaL_error(L, "Expected type string, got %s", + lua_typename(L, lua_type(L, 1))); + } + proxy_ptr = lua_newuserdata(L, 1); + if (proxy_ptr == NULL) { + return 0; + } + lua_newtable(L); + /* typestr, proxyobj, metatable */ + /* First job is the tostring metamethod, we always add that */ + lua_pushvalue(L, 1); + lua_pushcclosure(L, supple_capi_proxy_tostring, 1); + lua_setfield(L, -2, "__tostring"); + /* next the __type metamethod for the lua level type call */ + lua_pushvalue(L, 1); + lua_pushcclosure(L, supple_capi_proxy_type, 1); + lua_setfield(L, -2, "__type"); + /* And now prevent anything poking in us later */ + lua_pushboolean(L, 1); + lua_setfield(L, -2, "__metatable"); + + /* Finally set the metatable and return proxy, metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -3); + + return 2; +} + +/* Replacement for lbaselib.c's type method, honouring __type */ +static int +supple_capi_type(lua_State *L) +{ + lua_settop(L, 1); + if (lua_getmetatable(L, 1) != 0) { + /* There is a metatable, try and find __type */ + lua_getfield(L, 2, "__type"); + if (lua_isfunction(L, 3)) { + lua_pushvalue(L, 1); + lua_call(L, 1, 1); + return 1; + } + } + + lua_pushstring(L, lua_typename(L, lua_type(L, 1))); + + return 1; +} + +/* Reimplementation of base type in case it's not available */ +static int +supple_capi_rawtype(lua_State *L) +{ + lua_settop(L, 1); + lua_pushstring(L, lua_typename(L, lua_type(L, 1))); + return 1; +} + static const struct luaL_Reg supple_capi_functions[] = { + { "explain", supple_capi_explain }, + { "new_proxy", supple_capi_new_proxy }, + { "type", supple_capi_type }, + { "rawtype", supple_capi_rawtype }, { NULL, NULL } }; diff --git a/lib/supple/objects.lua b/lib/supple/objects.lua new file mode 100644 index 0000000..67cb71b --- /dev/null +++ b/lib/supple/objects.lua @@ -0,0 +1,111 @@ +-- lib/supple/request.lua +-- +-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine +-- +-- Contextual object storage and identification. Wrapping and unwrapping. +-- +-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org> +-- +-- For licence terms, see COPYING +-- + +local capi = require 'supple.capi' + +local my_objects_by_obj = {} +local my_objects_by_tag = {} +local my_name = "UNSET" +local my_counter = 0 +local their_objects_by_tag = setmetatable({}, { __mode="v" }) +local their_objects_by_obj = setmetatable({}, { __mode="k" }) +local proc_call = nil + +local type = capi.rawtype + +local function set_name(newname) + my_name = newname +end + +local function set_proc_call(pc) + proc_call = pc +end + +local integral = { + ["nil"] = true, + boolean = true, + string = true, + number = true, +} + +local function give(obj) + -- If the object is integral, return it directly + if integral[type(obj)] then + return obj + end + -- If the passed object is one of their objects then "unwrap" it by + -- returning their tag. + local tag = their_objects_by_obj[obj]; + if tag then + return { tag = tag } + end + -- If it's one of our objects which has already been wrapped, return our + -- tag + local tag = my_objects_by_obj[obj] + if tag then + return { tag = tag } + end + -- otherwise wrap it freshly for us and return that. + local tag = ("%s:%d"):format(my_name, my_counter) + local expn = capi.explain(obj, tag) + my_objects_by_obj[obj] = tag + my_objects_by_tag[tag] = obj + return expn +end + +local function receive(obj) + -- If the object is integral, return it directly + if integral[type(obj)] then + return obj + end + -- It's not integral, so it must be a tagged object + assert(type(obj) == "table") + assert(type(obj.tag) == "string") + local tag = obj.tag + -- First up, is it one of our objects? + local ret = my_objects_by_tag[tag] + if ret then + return ret + end + -- Now is it a known one of their objects? + ret = their_objects_by_tag[tag] + if ret then + return ret + end + -- Okay, prepare a proxy? + assert(type(obj.type) == "string") + local proxy, mt = capi.new_proxy(obj.type) + their_objects_by_tag[tag] = proxy + their_objects_by_obj[proxy] = tag + -- Fill out the metatable + obj.methods = obj.methods or {} + obj.methods[#obj.methods+1] = "__gc" + if obj.type == "function" then + obj.methods[#obj.methods+1] = "__call" + end + if obj.type == "table" then + obj.methods[#obj.methods+1] = "__index" + obj.methods[#obj.methods+1] = "__newindex" + end + for _, name in ipairs(obj.methods or {}) do + mt[name] = function(...) + proc_call(tag, name, ...) + end + end + -- And return the proxy object + return proxy +end + +return { + set_name = set_name, + set_proc_call = set_proc_call, + give = give, +} diff --git a/lib/supple/request.lua b/lib/supple/request.lua new file mode 100644 index 0000000..7f01e99 --- /dev/null +++ b/lib/supple/request.lua @@ -0,0 +1,37 @@ +-- lib/supple/request.lua +-- +-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine +-- +-- Request/response serialisation/deserialisation including contextual object +-- management and organisation. +-- +-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org> +-- +-- For licence terms, see COPYING +-- + +local tconcat = table.concat + +local function serialise_error(errstr, traceback) + return tconcat { + "error=true,", + ("message=%q,"):format(errstr), + ("traceback=%q"):format(traceback) + } +end + +local function serialise_request(obj, method, ...) +end + +local function serialise_response(...) +end + +local function deserialise_entity(entity) +end + +return { + error = serialise_error, + request = serialise_request, + response = serialise_response, + deserialise = deserialise_entity, +} |