From: Kirill Shcherbatov <kshcherbatov@tarantool.org> To: tarantool-patches@freelists.org, vdavydov.dev@gmail.com Cc: Kirill Shcherbatov <kshcherbatov@tarantool.org> Subject: [PATCH v1 5/8] netbox: call persistent functions in netbox Date: Thu, 30 May 2019 13:45:32 +0300 [thread overview] Message-ID: <d1fa62b92e67ad0cf4ac09b661d7fc3e07df3334.1559212747.git.kshcherbatov@tarantool.org> (raw) In-Reply-To: <cover.1559212747.git.kshcherbatov@tarantool.org> This patch makes persistent Lua functions are available via net.box.connect() :call method. Example: lua_code = [[function(a, b) return a + b end]] box.schema.func.create('sum', {body = lua_code, opts = {is_deterministic = true}}) conn:call("sum", {1, 3}) Part of #4182 Needed for #1260 --- src/box/call.c | 2 +- src/box/lua/call.c | 36 ++++++++++++- src/box/lua/call.h | 3 +- test/box/persistent_func.result | 84 +++++++++++++++++++++++++++++++ test/box/persistent_func.test.lua | 36 +++++++++++++ 5 files changed, 157 insertions(+), 4 deletions(-) diff --git a/src/box/call.c b/src/box/call.c index 56da53fb3..773b914b1 100644 --- a/src/box/call.c +++ b/src/box/call.c @@ -202,7 +202,7 @@ box_process_call(struct call_request *request, struct port *port) if (func && func->def->language == FUNC_LANGUAGE_C) { rc = box_c_call(func, request, port); } else { - rc = box_lua_call(request, port); + rc = box_lua_call(func, request, port); } /* Restore the original user */ if (orig_credentials) diff --git a/src/box/lua/call.c b/src/box/lua/call.c index c729778c4..2cd982ba8 100644 --- a/src/box/lua/call.c +++ b/src/box/lua/call.c @@ -32,6 +32,8 @@ #include "box/call.h" #include "box/error.h" #include "fiber.h" +#include "box/func.h" +#include "box/schema.h" #include "lua/utils.h" #include "lua/msgpack.h" @@ -253,6 +255,31 @@ execute_lua_call(lua_State *L) return lua_gettop(L); } +static int +execute_persistent_function(lua_State *L) +{ + struct call_request *request = (struct call_request *) + lua_topointer(L, 1); + lua_settop(L, 0); + + const char *name = request->name; + uint32_t name_len = mp_decode_strl(&name); + struct func *func = func_by_name(name, name_len); + assert(func != NULL); + assert(func->lua_func_ref != LUA_REFNIL); + lua_rawgeti(L, LUA_REGISTRYINDEX, func->lua_func_ref); + + /* Push the rest of args (a tuple). */ + const char *args = request->args; + uint32_t arg_count = mp_decode_array(&args); + luaL_checkstack(L, arg_count, "lua_func: out of stack"); + for (uint32_t i = 0; i < arg_count; i++) + luamp_decode(L, luaL_msgpack_default, &args); + + lua_call(L, arg_count, LUA_MULTRET); + return lua_gettop(L); +} + static int execute_lua_eval(lua_State *L) { @@ -396,9 +423,14 @@ box_process_lua(struct call_request *request, struct port *base, } int -box_lua_call(struct call_request *request, struct port *port) +box_lua_call(struct func *func, struct call_request *request, struct port *port) { - return box_process_lua(request, port, execute_lua_call); + if (func != NULL && func_def_is_persistent(func->def)) { + return box_process_lua(request, port, + execute_persistent_function); + } else { + return box_process_lua(request, port, execute_lua_call); + } } int diff --git a/src/box/lua/call.h b/src/box/lua/call.h index 0542123da..06bcfe77e 100644 --- a/src/box/lua/call.h +++ b/src/box/lua/call.h @@ -42,13 +42,14 @@ box_lua_call_init(struct lua_State *L); struct port; struct call_request; +struct func; /** * Invoke a Lua stored procedure from the binary protocol * (implementation of 'CALL' command code). */ int -box_lua_call(struct call_request *request, struct port *port); +box_lua_call(struct func *func, struct call_request *request, struct port *port); int box_lua_eval(struct call_request *request, struct port *port); diff --git a/test/box/persistent_func.result b/test/box/persistent_func.result index 0644de7fe..1b3eaa8b2 100644 --- a/test/box/persistent_func.result +++ b/test/box/persistent_func.result @@ -7,6 +7,15 @@ test_run = env.new() -- -- gh-4182: Add persistent LUA functions. -- +box.schema.user.grant('guest', 'execute', 'universe') +--- +... +net = require('net.box') +--- +... +conn = net.connect(box.cfg.listen) +--- +... -- Test valid function. test_run:cmd("setopt delimiter ';'") --- @@ -34,9 +43,58 @@ box.schema.func.exists('test') --- - true ... +conn:call("test", {{address = "Moscow Dolgoprudny"}}) +--- +- [['moscow'], ['dolgoprudny']] +... box.schema.func.create('test2', {body = body, is_deterministic = true}) --- ... +-- Test that monkey-patch attack is not possible. +test_run:cmd("setopt delimiter ';'") +--- +- true +... +body_monkey = [[function(tuple) + math.abs = math.log + return tuple +end +]] +test_run:cmd("setopt delimiter ''"); +--- +... +box.schema.func.create('body_monkey', {body = body_monkey}) +--- +... +conn:call("body_monkey", {{address = "Moscow Dolgoprudny"}}) +--- +- {'address': 'Moscow Dolgoprudny'} +... +math.abs(-666.666) +--- +- 666.666 +... +-- Test taht 'require' is forbidden. +test_run:cmd("setopt delimiter ';'") +--- +- true +... +body_bad1 = [[function(tuple) + local json = require('json') + return json.encode(tuple) +end +]] +test_run:cmd("setopt delimiter ''"); +--- +... +box.schema.func.create('json_serializer', {body = body_bad1}) +--- +... +conn:call("json_serializer", {{address = "Moscow Dolgoprudny"}}) +--- +- error: '[string "return function(tuple) ..."]:1: attempt to call global ''require'' + (a nil value)' +... -- Test function with spell error - case 1. test_run:cmd("setopt delimiter ';'") --- @@ -71,6 +129,13 @@ box.schema.func.create('body_bad3', {body = body_bad3}) - error: "Failed to dynamically load function 'body_bad3': func(tuple) \treturn tuple end " ... +conn:call("body_bad3", {{address = "Moscow Dolgoprudny"}}) +--- +- error: Procedure 'body_bad3' is not defined +... +conn:close() +--- +... -- Restart server. test_run:cmd("restart server default") net = require('net.box') @@ -79,6 +144,16 @@ net = require('net.box') test_run = require('test_run').new() --- ... +conn = net.connect(box.cfg.listen) +--- +... +conn:call("test", {{address = "Moscow Dolgoprudny"}}) +--- +- [['moscow'], ['dolgoprudny']] +... +conn:close() +--- +... box.schema.func.exists('test') --- - true @@ -90,6 +165,15 @@ box.schema.func.exists('test') --- - false ... +box.schema.func.drop('body_monkey') +--- +... +box.schema.func.drop('json_serializer') +--- +... box.schema.func.drop('test2') --- ... +box.schema.user.revoke('guest', 'execute', 'universe') +--- +... diff --git a/test/box/persistent_func.test.lua b/test/box/persistent_func.test.lua index 37a761d32..363d687ce 100644 --- a/test/box/persistent_func.test.lua +++ b/test/box/persistent_func.test.lua @@ -4,6 +4,10 @@ test_run = env.new() -- -- gh-4182: Add persistent LUA functions. -- +box.schema.user.grant('guest', 'execute', 'universe') +net = require('net.box') +conn = net.connect(box.cfg.listen) + -- Test valid function. test_run:cmd("setopt delimiter ';'") body = [[function(tuple) @@ -17,8 +21,32 @@ test_run:cmd("setopt delimiter ''"); box.schema.func.create('test', {body = body, language = "C"}) box.schema.func.create('test', {body = body}) box.schema.func.exists('test') +conn:call("test", {{address = "Moscow Dolgoprudny"}}) box.schema.func.create('test2', {body = body, is_deterministic = true}) +-- Test that monkey-patch attack is not possible. +test_run:cmd("setopt delimiter ';'") +body_monkey = [[function(tuple) + math.abs = math.log + return tuple +end +]] +test_run:cmd("setopt delimiter ''"); +box.schema.func.create('body_monkey', {body = body_monkey}) +conn:call("body_monkey", {{address = "Moscow Dolgoprudny"}}) +math.abs(-666.666) + +-- Test taht 'require' is forbidden. +test_run:cmd("setopt delimiter ';'") +body_bad1 = [[function(tuple) + local json = require('json') + return json.encode(tuple) +end +]] +test_run:cmd("setopt delimiter ''"); +box.schema.func.create('json_serializer', {body = body_bad1}) +conn:call("json_serializer", {{address = "Moscow Dolgoprudny"}}) + -- Test function with spell error - case 1. test_run:cmd("setopt delimiter ';'") body_bad2 = [[function(tuple) @@ -36,12 +64,20 @@ end ]] test_run:cmd("setopt delimiter ''"); box.schema.func.create('body_bad3', {body = body_bad3}) +conn:call("body_bad3", {{address = "Moscow Dolgoprudny"}}) +conn:close() -- Restart server. test_run:cmd("restart server default") net = require('net.box') test_run = require('test_run').new() +conn = net.connect(box.cfg.listen) +conn:call("test", {{address = "Moscow Dolgoprudny"}}) +conn:close() box.schema.func.exists('test') box.schema.func.drop('test') box.schema.func.exists('test') +box.schema.func.drop('body_monkey') +box.schema.func.drop('json_serializer') box.schema.func.drop('test2') +box.schema.user.revoke('guest', 'execute', 'universe') -- 2.21.0
next prev parent reply other threads:[~2019-05-30 10:45 UTC|newest] Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-05-30 10:45 [PATCH v1 0/8] box: functional indexes Kirill Shcherbatov 2019-05-30 10:45 ` [PATCH v1 1/8] box: refactor box_lua_find helper Kirill Shcherbatov 2019-05-30 10:45 ` [PATCH v1 2/8] box: rework func cache update machinery Kirill Shcherbatov 2019-05-30 10:45 ` [PATCH v1 3/8] schema: rework _func system space format Kirill Shcherbatov 2019-05-30 12:06 ` [tarantool-patches] " Konstantin Osipov 2019-06-03 16:14 ` Vladimir Davydov 2019-05-30 13:10 ` Vladislav Shpilevoy 2019-05-30 10:45 ` [PATCH v1 4/8] box: load persistent Lua functions on creation Kirill Shcherbatov 2019-05-31 8:16 ` [tarantool-patches] " Konstantin Osipov 2019-06-03 8:26 ` [tarantool-patches] " Kirill Shcherbatov 2019-05-30 10:45 ` Kirill Shcherbatov [this message] 2019-05-30 10:45 ` [PATCH v1 6/8] box: export _func functions with box.func folder Kirill Shcherbatov 2019-06-03 16:22 ` Vladimir Davydov 2019-06-03 16:24 ` Vladimir Davydov 2019-05-30 10:45 ` [PATCH v1 7/8] box: introduce memtx_slab_alloc helper Kirill Shcherbatov 2019-05-30 10:45 ` [PATCH v1 8/8] box: introduce functional indexes in memtx Kirill Shcherbatov 2019-05-30 11:18 ` [tarantool-patches] [PATCH v1 0/8] box: functional indexes Vladislav Shpilevoy 2019-05-30 11:43 ` [tarantool-patches] " Kirill Shcherbatov 2019-05-30 11:47 ` [tarantool-patches] " Konstantin Osipov 2019-06-03 15:55 ` Vladimir Davydov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=d1fa62b92e67ad0cf4ac09b661d7fc3e07df3334.1559212747.git.kshcherbatov@tarantool.org \ --to=kshcherbatov@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=vdavydov.dev@gmail.com \ --subject='Re: [PATCH v1 5/8] netbox: call persistent functions in netbox' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox