Unverified Commit ed29d634 authored by Madelyn Olson's avatar Madelyn Olson Committed by GitHub
Browse files

Add readonly flag to EVAL_RO, EVALSHA_RO and FCALL_RO (#10728)

* Add readonly flag to EVAL_RO, EVALSHA_RO and FCALL_RO
* Require users to explicitly declare @scripting to get access to lua scripting.
parent 7a550c8b
...@@ -7279,10 +7279,10 @@ struct redisCommand redisCommandTable[] = { ...@@ -7279,10 +7279,10 @@ struct redisCommand redisCommandTable[] = {
/* scripting */ /* scripting */
{"eval","Execute a Lua script server side","Depends on the script that is executed.","2.6.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVAL_History,EVAL_tips,evalCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RW and UPDATE",CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVAL_Args}, {"eval","Execute a Lua script server side","Depends on the script that is executed.","2.6.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVAL_History,EVAL_tips,evalCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RW and UPDATE",CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVAL_Args},
{"evalsha","Execute a Lua script server side","Depends on the script that is executed.","2.6.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVALSHA_History,EVALSHA_tips,evalShaCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{NULL,CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVALSHA_Args}, {"evalsha","Execute a Lua script server side","Depends on the script that is executed.","2.6.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVALSHA_History,EVALSHA_tips,evalShaCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{NULL,CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVALSHA_Args},
{"evalsha_ro","Execute a read-only Lua script server side","Depends on the script that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVALSHA_RO_History,EVALSHA_RO_tips,evalShaRoCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVALSHA_RO_Args}, {"evalsha_ro","Execute a read-only Lua script server side","Depends on the script that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVALSHA_RO_History,EVALSHA_RO_tips,evalShaRoCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_NO_MANDATORY_KEYS|CMD_STALE|CMD_READONLY,ACL_CATEGORY_SCRIPTING,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVALSHA_RO_Args},
{"eval_ro","Execute a read-only Lua script server side","Depends on the script that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVAL_RO_History,EVAL_RO_tips,evalRoCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RO and ACCESS",CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVAL_RO_Args}, {"eval_ro","Execute a read-only Lua script server side","Depends on the script that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,EVAL_RO_History,EVAL_RO_tips,evalRoCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_NO_MANDATORY_KEYS|CMD_STALE|CMD_READONLY,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RO and ACCESS",CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},evalGetKeys,.args=EVAL_RO_Args},
{"fcall","Invoke a function","Depends on the function that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,FCALL_History,FCALL_tips,fcallCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RW and UPDATE",CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},functionGetKeys,.args=FCALL_Args}, {"fcall","Invoke a function","Depends on the function that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,FCALL_History,FCALL_tips,fcallCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_MAY_REPLICATE|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RW and UPDATE",CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},functionGetKeys,.args=FCALL_Args},
{"fcall_ro","Invoke a read-only function","Depends on the function that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,FCALL_RO_History,FCALL_RO_tips,fcallroCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_NO_MANDATORY_KEYS|CMD_STALE,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RO and ACCESS",CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},functionGetKeys,.args=FCALL_RO_Args}, {"fcall_ro","Invoke a read-only function","Depends on the function that is executed.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,FCALL_RO_History,FCALL_RO_tips,fcallroCommand,-3,CMD_NOSCRIPT|CMD_SKIP_MONITOR|CMD_NO_MANDATORY_KEYS|CMD_STALE|CMD_READONLY,ACL_CATEGORY_SCRIPTING,{{"We cannot tell how the keys will be used so we assume the worst, RO and ACCESS",CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}},functionGetKeys,.args=FCALL_RO_Args},
{"function","A container for function commands","Depends on subcommand.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,FUNCTION_History,FUNCTION_tips,NULL,-2,0,0,.subcommands=FUNCTION_Subcommands}, {"function","A container for function commands","Depends on subcommand.","7.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,FUNCTION_History,FUNCTION_tips,NULL,-2,0,0,.subcommands=FUNCTION_Subcommands},
{"script","A container for Lua scripts management commands","Depends on subcommand.","2.6.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,SCRIPT_History,SCRIPT_tips,NULL,-2,0,0,.subcommands=SCRIPT_Subcommands}, {"script","A container for Lua scripts management commands","Depends on subcommand.","2.6.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SCRIPTING,SCRIPT_History,SCRIPT_tips,NULL,-2,0,0,.subcommands=SCRIPT_Subcommands},
/* sentinel */ /* sentinel */
......
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
"NOSCRIPT", "NOSCRIPT",
"SKIP_MONITOR", "SKIP_MONITOR",
"NO_MANDATORY_KEYS", "NO_MANDATORY_KEYS",
"STALE" "STALE",
"READONLY"
], ],
"acl_categories": [ "acl_categories": [
"SCRIPTING" "SCRIPTING"
......
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
"NOSCRIPT", "NOSCRIPT",
"SKIP_MONITOR", "SKIP_MONITOR",
"NO_MANDATORY_KEYS", "NO_MANDATORY_KEYS",
"STALE" "STALE",
"READONLY"
], ],
"acl_categories": [ "acl_categories": [
"SCRIPTING" "SCRIPTING"
......
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
"NOSCRIPT", "NOSCRIPT",
"SKIP_MONITOR", "SKIP_MONITOR",
"NO_MANDATORY_KEYS", "NO_MANDATORY_KEYS",
"STALE" "STALE",
"READONLY"
], ],
"acl_categories": [ "acl_categories": [
"SCRIPTING" "SCRIPTING"
......
...@@ -2716,7 +2716,8 @@ void commandAddSubcommand(struct redisCommand *parent, struct redisCommand *subc ...@@ -2716,7 +2716,8 @@ void commandAddSubcommand(struct redisCommand *parent, struct redisCommand *subc
void setImplicitACLCategories(struct redisCommand *c) { void setImplicitACLCategories(struct redisCommand *c) {
if (c->flags & CMD_WRITE) if (c->flags & CMD_WRITE)
c->acl_categories |= ACL_CATEGORY_WRITE; c->acl_categories |= ACL_CATEGORY_WRITE;
if (c->flags & CMD_READONLY) /* Exclude scripting commands from the RO category. */
if (c->flags & CMD_READONLY && !(c->acl_categories & ACL_CATEGORY_SCRIPTING))
c->acl_categories |= ACL_CATEGORY_READ; c->acl_categories |= ACL_CATEGORY_READ;
if (c->flags & CMD_ADMIN) if (c->flags & CMD_ADMIN)
c->acl_categories |= ACL_CATEGORY_ADMIN|ACL_CATEGORY_DANGEROUS; c->acl_categories |= ACL_CATEGORY_ADMIN|ACL_CATEGORY_DANGEROUS;
...@@ -3392,8 +3393,12 @@ void call(client *c, int flags) { ...@@ -3392,8 +3393,12 @@ void call(client *c, int flags) {
(CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP); (CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP);
/* If the client has keys tracking enabled for client side caching, /* If the client has keys tracking enabled for client side caching,
* make sure to remember the keys it fetched via this command. */ * make sure to remember the keys it fetched via this command. Scripting
if (c->cmd->flags & CMD_READONLY) { * works a bit differently, where if the scripts executes any read command, it
* remembers all of the declared keys from the script. */
if ((c->cmd->flags & CMD_READONLY) && (c->cmd->proc != evalRoCommand)
&& (c->cmd->proc != evalShaRoCommand) && (c->cmd->proc != fcallroCommand))
{
client *caller = (c->flags & CLIENT_SCRIPT && server.script_caller) ? client *caller = (c->flags & CLIENT_SCRIPT && server.script_caller) ?
server.script_caller : c; server.script_caller : c;
if (caller->flags & CLIENT_TRACKING && if (caller->flags & CLIENT_TRACKING &&
......
...@@ -529,6 +529,13 @@ start_server {tags {"acl external:skip"}} { ...@@ -529,6 +529,13 @@ start_server {tags {"acl external:skip"}} {
assert_equal [lsearch [r acl cat stream] "get"] -1 assert_equal [lsearch [r acl cat stream] "get"] -1
} }
test "ACL requires explicit permission for scripting for EVAL_RO, EVALSHA_RO and FCALL_RO" {
r ACL SETUSER scripter on nopass +readonly
assert_equal "This user has no permissions to run the 'eval_ro' command" [r ACL DRYRUN scripter EVAL_RO "" 0]
assert_equal "This user has no permissions to run the 'evalsha_ro' command" [r ACL DRYRUN scripter EVALSHA_RO "" 0]
assert_equal "This user has no permissions to run the 'fcall_ro' command" [r ACL DRYRUN scripter FCALL_RO "" 0]
}
test {ACL #5998 regression: memory leaks adding / removing subcommands} { test {ACL #5998 regression: memory leaks adding / removing subcommands} {
r AUTH default "" r AUTH default ""
r ACL setuser newuser reset -debug +debug|a +debug|b +debug|c r ACL setuser newuser reset -debug +debug|a +debug|b +debug|c
......
...@@ -208,6 +208,33 @@ start_server {tags {"tracking network"}} { ...@@ -208,6 +208,33 @@ start_server {tags {"tracking network"}} {
assert {$res eq {key1}} assert {$res eq {key1}}
} }
test {Tracking only occurs for scripts when a command calls a read-only command} {
r CLIENT TRACKING off
r CLIENT TRACKING on
$rd_sg MSET key2{t} 1 key2{t} 1
# If a script doesn't call any read command, don't track any keys
r EVAL "redis.call('set', 'key3{t}', 'bar')" 2 key1{t} key2{t}
$rd_sg MSET key2{t} 2 key1{t} 2
# If a script calls a read command, track all declared keys
r EVAL "redis.call('get', 'key3{t}')" 2 key1{t} key2{t}
$rd_sg MSET key2{t} 2 key1{t} 2
assert_equal {invalidate key2{t}} [r read]
assert_equal {invalidate key1{t}} [r read]
# RO variants work like the normal variants
r EVAL_RO "redis.call('ping')" 2 key1{t} key2{t}
$rd_sg MSET key2{t} 2 key1{t} 2
r EVAL_RO "redis.call('get', 'key1{t}')" 2 key1{t} key2{t}
$rd_sg MSET key2{t} 3 key1{t} 3
assert_equal {invalidate key2{t}} [r read]
assert_equal {invalidate key1{t}} [r read]
assert_equal "PONG" [r ping]
}
test {RESP3 Client gets tracking-redir-broken push message after cached key changed when rediretion client is terminated} { test {RESP3 Client gets tracking-redir-broken push message after cached key changed when rediretion client is terminated} {
r CLIENT TRACKING on REDIRECT $redir_id r CLIENT TRACKING on REDIRECT $redir_id
$rd_sg SET key1 1 $rd_sg SET key1 1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment