From 4b88d5fd9833b1c236572e7c557646909ec415eb Mon Sep 17 00:00:00 2001 From: Vladimir Davydov <vdavydov@tarantool.org> Date: Tue, 14 Nov 2023 13:51:45 +0300 Subject: [PATCH] box: allow lua_call priv owners to call registered Lua functions Currently, the lua_call privilege simply doesn't work for registered functions. This patch fixes this issue: now, it grants access to any registered function that is written in Lua unless it's a built-in function, such as dostring, or a persistent function. Note, this patch renames access_check_call to access_check_lua_call to avoid confusion because this function is now global. It also renames access_check_eval to access_check_lua_eval for consistency. Closes #9363 NO_DOC=updated doc ticket manually NO_CHANGELOG=feature has not been released yet --- src/box/call.c | 11 +++++------ src/box/call.h | 4 ++++ src/box/func.c | 5 +++++ test/box-luatest/gh_8803_exec_priv_test.lua | 11 +++++++---- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/box/call.c b/src/box/call.c index c0bee2ba99..477e690710 100644 --- a/src/box/call.c +++ b/src/box/call.c @@ -160,9 +160,8 @@ box_run_on_call(enum iproto_type type, const char *expr, int expr_len, trigger_run(&box_on_call, &ctx); } -/** Checks if the current user may execute any global Lua function. */ -static int -access_check_call(const char *name, uint32_t name_len) +int +access_check_lua_call(const char *name, uint32_t name_len) { struct credentials *cr = effective_user(); user_access_t access = PRIV_X | PRIV_U; @@ -182,7 +181,7 @@ access_check_call(const char *name, uint32_t name_len) /** Checks if the current user may execute an arbitrary Lua expression. */ static int -access_check_eval(void) +access_check_lua_eval(void) { struct credentials *cr = effective_user(); user_access_t access = PRIV_X | PRIV_U; @@ -229,7 +228,7 @@ box_process_call(struct call_request *request, struct port *port) goto cleanup; } } else { - if (access_check_call(name, name_len) != 0) { + if (access_check_lua_call(name, name_len) != 0) { rc = -1; goto cleanup; } @@ -249,7 +248,7 @@ box_process_eval(struct call_request *request, struct port *port) { rmean_collect(rmean_box, IPROTO_EVAL, 1); /* Check permissions */ - if (access_check_eval() != 0) + if (access_check_lua_eval() != 0) return -1; struct mp_box_ctx ctx; if (mp_box_ctx_create(&ctx, NULL, request->tuple_formats) != 0) diff --git a/src/box/call.h b/src/box/call.h index 0f8e31842c..911616772b 100644 --- a/src/box/call.h +++ b/src/box/call.h @@ -76,6 +76,10 @@ box_process_call(struct call_request *request, struct port *port); int box_process_eval(struct call_request *request, struct port *port); +/** Checks if the current user may execute a global Lua function. */ +int +access_check_lua_call(const char *name, uint32_t name_len); + #if defined(__cplusplus) } /* extern "C" */ #endif /* defined(__cplusplus) */ diff --git a/src/box/func.c b/src/box/func.c index ae3f89c75f..0dfea46254 100644 --- a/src/box/func.c +++ b/src/box/func.c @@ -31,6 +31,7 @@ #include "func.h" #include "fiber.h" #include "assoc.h" +#include "call.h" #include "lua/call.h" #include "diag.h" #include "port.h" @@ -567,6 +568,10 @@ func_access_check(struct func *func) if ((func_access & PRIV_U) != 0 || (func->def->uid != credentials->uid && func_access & ~func->access[credentials->auth_token].effective)) { + if (func->def->language == FUNC_LANGUAGE_LUA && + func->def->body == NULL) + return access_check_lua_call(func->def->name, + func->def->name_len); /* Access violation, report error. */ struct user *user = user_find(credentials->uid); if (user != NULL) { diff --git a/test/box-luatest/gh_8803_exec_priv_test.lua b/test/box-luatest/gh_8803_exec_priv_test.lua index 02e1399d1c..fbb9a60674 100644 --- a/test/box-luatest/gh_8803_exec_priv_test.lua +++ b/test/box-luatest/gh_8803_exec_priv_test.lua @@ -133,6 +133,7 @@ g.before_test('test_lua_call_func', function(cg) language = 'LUA', body = [[function() return true end]], }) + box.schema.func.create('dostring', {language = 'LUA'}) end) end) @@ -141,19 +142,21 @@ g.after_test('test_lua_call_func', function(cg) box.schema.func.drop('c_func') box.schema.func.drop('lua_func') box.schema.func.drop('stored_lua_func') + box.schema.func.drop('dostring') end) end) --- Checks that execute privilege granted on lua_call does not grant access to --- Lua functions from _func. +-- Checks that execute privilege granted on lua_call grants access to +-- Lua functions registered in _func except for built-ins and persistent +-- functions. g.test_lua_call_func = function(cg) local c = cg.conn local errfmt = "Execute access to function '%s' is denied for user 'test'" - local func_list = {'c_func', 'lua_func', 'stored_lua_func'} cg.grant('test', 'execute', 'lua_call') - for _, func in ipairs(func_list) do + for _, func in ipairs({'c_func', 'stored_lua_func', 'dostring'}) do t.assert_error_msg_equals(errfmt:format(func), c.call, c, func) end + t.assert(c:call('lua_func')) end -- Checks that execute privilege granted on lua_call does not grant access -- GitLab