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