1/*
2 * Copyright (c) 2009-2021, Redis Ltd.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Redis nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "script_lua.h"
31
32#include "server.h"
33#include "sha1.h"
34#include "rand.h"
35#include "cluster.h"
36#include "monotonic.h"
37#include "resp_parser.h"
38#include "version.h"
39#include <lauxlib.h>
40#include <lualib.h>
41#include <ctype.h>
42#include <math.h>
43
44/* Globals that are added by the Lua libraries */
45static char *libraries_allow_list[] = {
46 "string",
47 "cjson",
48 "bit",
49 "cmsgpack",
50 "math",
51 "table",
52 "struct",
53 NULL,
54};
55
56/* Redis Lua API globals */
57static char *redis_api_allow_list[] = {
58 "redis",
59 "__redis__err__handler", /* error handler for eval, currently located on globals.
60 Should move to registry. */
61 NULL,
62};
63
64/* Lua builtins */
65static char *lua_builtins_allow_list[] = {
66 "xpcall",
67 "tostring",
68 "getfenv",
69 "setmetatable",
70 "next",
71 "assert",
72 "tonumber",
73 "rawequal",
74 "collectgarbage",
75 "getmetatable",
76 "rawset",
77 "pcall",
78 "coroutine",
79 "type",
80 "_G",
81 "select",
82 "unpack",
83 "gcinfo",
84 "pairs",
85 "rawget",
86 "loadstring",
87 "ipairs",
88 "_VERSION",
89 "setfenv",
90 "load",
91 "error",
92 NULL,
93};
94
95/* Lua builtins which are not documented on the Lua documentation */
96static char *lua_builtins_not_documented_allow_list[] = {
97 "newproxy",
98 NULL,
99};
100
101/* Lua builtins which are allowed on initialization but will be removed right after */
102static char *lua_builtins_removed_after_initialization_allow_list[] = {
103 "debug", /* debug will be set to nil after the error handler will be created */
104 NULL,
105};
106
107/* Those allow lists was created from the globals that was
108 * available to the user when the allow lists was first introduce.
109 * Because we do not want to break backward compatibility we keep
110 * all the globals. The allow lists will prevent us from accidentally
111 * creating unwanted globals in the future.
112 *
113 * Also notice that the allow list is only checked on start time,
114 * after that the global table is locked so not need to check anything.*/
115static char **allow_lists[] = {
116 libraries_allow_list,
117 redis_api_allow_list,
118 lua_builtins_allow_list,
119 lua_builtins_not_documented_allow_list,
120 lua_builtins_removed_after_initialization_allow_list,
121 NULL,
122};
123
124/* Deny list contains elements which we know we do not want to add to globals
125 * and there is no need to print a warning message form them. We will print a
126 * log message only if an element was added to the globals and the element is
127 * not on the allow list nor on the back list. */
128static char *deny_list[] = {
129 "dofile",
130 "loadfile",
131 "print",
132 NULL,
133};
134
135static int redis_math_random (lua_State *L);
136static int redis_math_randomseed (lua_State *L);
137static void redisProtocolToLuaType_Int(void *ctx, long long val, const char *proto, size_t proto_len);
138static void redisProtocolToLuaType_BulkString(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len);
139static void redisProtocolToLuaType_NullBulkString(void *ctx, const char *proto, size_t proto_len);
140static void redisProtocolToLuaType_NullArray(void *ctx, const char *proto, size_t proto_len);
141static void redisProtocolToLuaType_Status(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len);
142static void redisProtocolToLuaType_Error(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len);
143static void redisProtocolToLuaType_Array(struct ReplyParser *parser, void *ctx, size_t len, const char *proto);
144static void redisProtocolToLuaType_Map(struct ReplyParser *parser, void *ctx, size_t len, const char *proto);
145static void redisProtocolToLuaType_Set(struct ReplyParser *parser, void *ctx, size_t len, const char *proto);
146static void redisProtocolToLuaType_Null(void *ctx, const char *proto, size_t proto_len);
147static void redisProtocolToLuaType_Bool(void *ctx, int val, const char *proto, size_t proto_len);
148static void redisProtocolToLuaType_Double(void *ctx, double d, const char *proto, size_t proto_len);
149static void redisProtocolToLuaType_BigNumber(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len);
150static void redisProtocolToLuaType_VerbatimString(void *ctx, const char *format, const char *str, size_t len, const char *proto, size_t proto_len);
151static void redisProtocolToLuaType_Attribute(struct ReplyParser *parser, void *ctx, size_t len, const char *proto);
152static void luaReplyToRedisReply(client *c, client* script_client, lua_State *lua);
153
154/*
155 * Save the give pointer on Lua registry, used to save the Lua context and
156 * function context so we can retrieve them from lua_State.
157 */
158void luaSaveOnRegistry(lua_State* lua, const char* name, void* ptr) {
159 lua_pushstring(lua, name);
160 if (ptr) {
161 lua_pushlightuserdata(lua, ptr);
162 } else {
163 lua_pushnil(lua);
164 }
165 lua_settable(lua, LUA_REGISTRYINDEX);
166}
167
168/*
169 * Get a saved pointer from registry
170 */
171void* luaGetFromRegistry(lua_State* lua, const char* name) {
172 lua_pushstring(lua, name);
173 lua_gettable(lua, LUA_REGISTRYINDEX);
174
175 if (lua_isnil(lua, -1)) {
176 return NULL;
177 }
178 /* must be light user data */
179 serverAssert(lua_islightuserdata(lua, -1));
180
181 void* ptr = (void*) lua_topointer(lua, -1);
182 serverAssert(ptr);
183
184 /* pops the value */
185 lua_pop(lua, 1);
186
187 return ptr;
188}
189
190/* ---------------------------------------------------------------------------
191 * Redis reply to Lua type conversion functions.
192 * ------------------------------------------------------------------------- */
193
194/* Take a Redis reply in the Redis protocol format and convert it into a
195 * Lua type. Thanks to this function, and the introduction of not connected
196 * clients, it is trivial to implement the redis() lua function.
197 *
198 * Basically we take the arguments, execute the Redis command in the context
199 * of a non connected client, then take the generated reply and convert it
200 * into a suitable Lua type. With this trick the scripting feature does not
201 * need the introduction of a full Redis internals API. The script
202 * is like a normal client that bypasses all the slow I/O paths.
203 *
204 * Note: in this function we do not do any sanity check as the reply is
205 * generated by Redis directly. This allows us to go faster.
206 *
207 * Errors are returned as a table with a single 'err' field set to the
208 * error string.
209 */
210
211static const ReplyParserCallbacks DefaultLuaTypeParserCallbacks = {
212 .null_array_callback = redisProtocolToLuaType_NullArray,
213 .bulk_string_callback = redisProtocolToLuaType_BulkString,
214 .null_bulk_string_callback = redisProtocolToLuaType_NullBulkString,
215 .error_callback = redisProtocolToLuaType_Error,
216 .simple_str_callback = redisProtocolToLuaType_Status,
217 .long_callback = redisProtocolToLuaType_Int,
218 .array_callback = redisProtocolToLuaType_Array,
219 .set_callback = redisProtocolToLuaType_Set,
220 .map_callback = redisProtocolToLuaType_Map,
221 .bool_callback = redisProtocolToLuaType_Bool,
222 .double_callback = redisProtocolToLuaType_Double,
223 .null_callback = redisProtocolToLuaType_Null,
224 .big_number_callback = redisProtocolToLuaType_BigNumber,
225 .verbatim_string_callback = redisProtocolToLuaType_VerbatimString,
226 .attribute_callback = redisProtocolToLuaType_Attribute,
227 .error = NULL,
228};
229
230static void redisProtocolToLuaType(lua_State *lua, char* reply) {
231 ReplyParser parser = {.curr_location = reply, .callbacks = DefaultLuaTypeParserCallbacks};
232
233 parseReply(&parser, lua);
234}
235
236static void redisProtocolToLuaType_Int(void *ctx, long long val, const char *proto, size_t proto_len) {
237 UNUSED(proto);
238 UNUSED(proto_len);
239 if (!ctx) {
240 return;
241 }
242
243 lua_State *lua = ctx;
244 if (!lua_checkstack(lua, 1)) {
245 /* Increase the Lua stack if needed, to make sure there is enough room
246 * to push elements to the stack. On failure, exit with panic. */
247 serverPanic("lua stack limit reach when parsing redis.call reply");
248 }
249 lua_pushnumber(lua,(lua_Number)val);
250}
251
252static void redisProtocolToLuaType_NullBulkString(void *ctx, const char *proto, size_t proto_len) {
253 UNUSED(proto);
254 UNUSED(proto_len);
255 if (!ctx) {
256 return;
257 }
258
259 lua_State *lua = ctx;
260 if (!lua_checkstack(lua, 1)) {
261 /* Increase the Lua stack if needed, to make sure there is enough room
262 * to push elements to the stack. On failure, exit with panic. */
263 serverPanic("lua stack limit reach when parsing redis.call reply");
264 }
265 lua_pushboolean(lua,0);
266}
267
268static void redisProtocolToLuaType_NullArray(void *ctx, const char *proto, size_t proto_len) {
269 UNUSED(proto);
270 UNUSED(proto_len);
271 if (!ctx) {
272 return;
273 }
274 lua_State *lua = ctx;
275 if (!lua_checkstack(lua, 1)) {
276 /* Increase the Lua stack if needed, to make sure there is enough room
277 * to push elements to the stack. On failure, exit with panic. */
278 serverPanic("lua stack limit reach when parsing redis.call reply");
279 }
280 lua_pushboolean(lua,0);
281}
282
283
284static void redisProtocolToLuaType_BulkString(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
285 UNUSED(proto);
286 UNUSED(proto_len);
287 if (!ctx) {
288 return;
289 }
290
291 lua_State *lua = ctx;
292 if (!lua_checkstack(lua, 1)) {
293 /* Increase the Lua stack if needed, to make sure there is enough room
294 * to push elements to the stack. On failure, exit with panic. */
295 serverPanic("lua stack limit reach when parsing redis.call reply");
296 }
297 lua_pushlstring(lua,str,len);
298}
299
300static void redisProtocolToLuaType_Status(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
301 UNUSED(proto);
302 UNUSED(proto_len);
303 if (!ctx) {
304 return;
305 }
306
307 lua_State *lua = ctx;
308 if (!lua_checkstack(lua, 3)) {
309 /* Increase the Lua stack if needed, to make sure there is enough room
310 * to push elements to the stack. On failure, exit with panic. */
311 serverPanic("lua stack limit reach when parsing redis.call reply");
312 }
313 lua_newtable(lua);
314 lua_pushstring(lua,"ok");
315 lua_pushlstring(lua,str,len);
316 lua_settable(lua,-3);
317}
318
319static void redisProtocolToLuaType_Error(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
320 UNUSED(proto);
321 UNUSED(proto_len);
322 if (!ctx) {
323 return;
324 }
325
326 lua_State *lua = ctx;
327 if (!lua_checkstack(lua, 3)) {
328 /* Increase the Lua stack if needed, to make sure there is enough room
329 * to push elements to the stack. On failure, exit with panic. */
330 serverPanic("lua stack limit reach when parsing redis.call reply");
331 }
332 sds err_msg = sdscatlen(sdsnew("-"), str, len);
333 luaPushErrorBuff(lua,err_msg);
334 /* push a field indicate to ignore updating the stats on this error
335 * because it was already updated when executing the command. */
336 lua_pushstring(lua,"ignore_error_stats_update");
337 lua_pushboolean(lua, 1);
338 lua_settable(lua,-3);
339}
340
341static void redisProtocolToLuaType_Map(struct ReplyParser *parser, void *ctx, size_t len, const char *proto) {
342 UNUSED(proto);
343 lua_State *lua = ctx;
344 if (lua) {
345 if (!lua_checkstack(lua, 3)) {
346 /* Increase the Lua stack if needed, to make sure there is enough room
347 * to push elements to the stack. On failure, exit with panic. */
348 serverPanic("lua stack limit reach when parsing redis.call reply");
349 }
350 lua_newtable(lua);
351 lua_pushstring(lua, "map");
352 lua_newtable(lua);
353 }
354 for (size_t j = 0; j < len; j++) {
355 parseReply(parser,lua);
356 parseReply(parser,lua);
357 if (lua) lua_settable(lua,-3);
358 }
359 if (lua) lua_settable(lua,-3);
360}
361
362static void redisProtocolToLuaType_Set(struct ReplyParser *parser, void *ctx, size_t len, const char *proto) {
363 UNUSED(proto);
364
365 lua_State *lua = ctx;
366 if (lua) {
367 if (!lua_checkstack(lua, 3)) {
368 /* Increase the Lua stack if needed, to make sure there is enough room
369 * to push elements to the stack. On failure, exit with panic. */
370 serverPanic("lua stack limit reach when parsing redis.call reply");
371 }
372 lua_newtable(lua);
373 lua_pushstring(lua, "set");
374 lua_newtable(lua);
375 }
376 for (size_t j = 0; j < len; j++) {
377 parseReply(parser,lua);
378 if (lua) {
379 if (!lua_checkstack(lua, 1)) {
380 /* Increase the Lua stack if needed, to make sure there is enough room
381 * to push elements to the stack. On failure, exit with panic.
382 * Notice that here we need to check the stack again because the recursive
383 * call to redisProtocolToLuaType might have use the room allocated in the stack*/
384 serverPanic("lua stack limit reach when parsing redis.call reply");
385 }
386 lua_pushboolean(lua,1);
387 lua_settable(lua,-3);
388 }
389 }
390 if (lua) lua_settable(lua,-3);
391}
392
393static void redisProtocolToLuaType_Array(struct ReplyParser *parser, void *ctx, size_t len, const char *proto) {
394 UNUSED(proto);
395
396 lua_State *lua = ctx;
397 if (lua){
398 if (!lua_checkstack(lua, 2)) {
399 /* Increase the Lua stack if needed, to make sure there is enough room
400 * to push elements to the stack. On failure, exit with panic. */
401 serverPanic("lua stack limit reach when parsing redis.call reply");
402 }
403 lua_newtable(lua);
404 }
405 for (size_t j = 0; j < len; j++) {
406 if (lua) lua_pushnumber(lua,j+1);
407 parseReply(parser,lua);
408 if (lua) lua_settable(lua,-3);
409 }
410}
411
412static void redisProtocolToLuaType_Attribute(struct ReplyParser *parser, void *ctx, size_t len, const char *proto) {
413 UNUSED(proto);
414
415 /* Parse the attribute reply.
416 * Currently, we do not expose the attribute to the Lua script so
417 * we just need to continue parsing and ignore it (the NULL ensures that the
418 * reply will be ignored). */
419 for (size_t j = 0; j < len; j++) {
420 parseReply(parser,NULL);
421 parseReply(parser,NULL);
422 }
423
424 /* Parse the reply itself. */
425 parseReply(parser,ctx);
426}
427
428static void redisProtocolToLuaType_VerbatimString(void *ctx, const char *format, const char *str, size_t len, const char *proto, size_t proto_len) {
429 UNUSED(proto);
430 UNUSED(proto_len);
431 if (!ctx) {
432 return;
433 }
434
435 lua_State *lua = ctx;
436 if (!lua_checkstack(lua, 5)) {
437 /* Increase the Lua stack if needed, to make sure there is enough room
438 * to push elements to the stack. On failure, exit with panic. */
439 serverPanic("lua stack limit reach when parsing redis.call reply");
440 }
441 lua_newtable(lua);
442 lua_pushstring(lua,"verbatim_string");
443 lua_newtable(lua);
444 lua_pushstring(lua,"string");
445 lua_pushlstring(lua,str,len);
446 lua_settable(lua,-3);
447 lua_pushstring(lua,"format");
448 lua_pushlstring(lua,format,3);
449 lua_settable(lua,-3);
450 lua_settable(lua,-3);
451}
452
453static void redisProtocolToLuaType_BigNumber(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
454 UNUSED(proto);
455 UNUSED(proto_len);
456 if (!ctx) {
457 return;
458 }
459
460 lua_State *lua = ctx;
461 if (!lua_checkstack(lua, 3)) {
462 /* Increase the Lua stack if needed, to make sure there is enough room
463 * to push elements to the stack. On failure, exit with panic. */
464 serverPanic("lua stack limit reach when parsing redis.call reply");
465 }
466 lua_newtable(lua);
467 lua_pushstring(lua,"big_number");
468 lua_pushlstring(lua,str,len);
469 lua_settable(lua,-3);
470}
471
472static void redisProtocolToLuaType_Null(void *ctx, const char *proto, size_t proto_len) {
473 UNUSED(proto);
474 UNUSED(proto_len);
475 if (!ctx) {
476 return;
477 }
478
479 lua_State *lua = ctx;
480 if (!lua_checkstack(lua, 1)) {
481 /* Increase the Lua stack if needed, to make sure there is enough room
482 * to push elements to the stack. On failure, exit with panic. */
483 serverPanic("lua stack limit reach when parsing redis.call reply");
484 }
485 lua_pushnil(lua);
486}
487
488static void redisProtocolToLuaType_Bool(void *ctx, int val, const char *proto, size_t proto_len) {
489 UNUSED(proto);
490 UNUSED(proto_len);
491 if (!ctx) {
492 return;
493 }
494
495 lua_State *lua = ctx;
496 if (!lua_checkstack(lua, 1)) {
497 /* Increase the Lua stack if needed, to make sure there is enough room
498 * to push elements to the stack. On failure, exit with panic. */
499 serverPanic("lua stack limit reach when parsing redis.call reply");
500 }
501 lua_pushboolean(lua,val);
502}
503
504static void redisProtocolToLuaType_Double(void *ctx, double d, const char *proto, size_t proto_len) {
505 UNUSED(proto);
506 UNUSED(proto_len);
507 if (!ctx) {
508 return;
509 }
510
511 lua_State *lua = ctx;
512 if (!lua_checkstack(lua, 3)) {
513 /* Increase the Lua stack if needed, to make sure there is enough room
514 * to push elements to the stack. On failure, exit with panic. */
515 serverPanic("lua stack limit reach when parsing redis.call reply");
516 }
517 lua_newtable(lua);
518 lua_pushstring(lua,"double");
519 lua_pushnumber(lua,d);
520 lua_settable(lua,-3);
521}
522
523/* This function is used in order to push an error on the Lua stack in the
524 * format used by redis.pcall to return errors, which is a lua table
525 * with an "err" field set to the error string including the error code.
526 * Note that this table is never a valid reply by proper commands,
527 * since the returned tables are otherwise always indexed by integers, never by strings.
528 *
529 * The function takes ownership on the given err_buffer. */
530void luaPushErrorBuff(lua_State *lua, sds err_buffer) {
531 sds msg;
532 sds error_code;
533
534 /* If debugging is active and in step mode, log errors resulting from
535 * Redis commands. */
536 if (ldbIsEnabled()) {
537 ldbLog(sdscatprintf(sdsempty(),"<error> %s",err_buffer));
538 }
539
540 /* There are two possible formats for the received `error` string:
541 * 1) "-CODE msg": in this case we remove the leading '-' since we don't store it as part of the lua error format.
542 * 2) "msg": in this case we prepend a generic 'ERR' code since all error statuses need some error code.
543 * We support format (1) so this function can reuse the error messages used in other places in redis.
544 * We support format (2) so it'll be easy to pass descriptive errors to this function without worrying about format.
545 */
546 if (err_buffer[0] == '-') {
547 /* derive error code from the message */
548 char *err_msg = strstr(err_buffer, " ");
549 if (!err_msg) {
550 msg = sdsnew(err_buffer+1);
551 error_code = sdsnew("ERR");
552 } else {
553 *err_msg = '\0';
554 msg = sdsnew(err_msg+1);
555 error_code = sdsnew(err_buffer + 1);
556 }
557 sdsfree(err_buffer);
558 } else {
559 msg = err_buffer;
560 error_code = sdsnew("ERR");
561 }
562 /* Trim newline at end of string. If we reuse the ready-made Redis error objects (case 1 above) then we might
563 * have a newline that needs to be trimmed. In any case the lua Redis error table shouldn't end with a newline. */
564 msg = sdstrim(msg, "\r\n");
565 sds final_msg = sdscatfmt(error_code, " %s", msg);
566
567 lua_newtable(lua);
568 lua_pushstring(lua,"err");
569 lua_pushstring(lua, final_msg);
570 lua_settable(lua,-3);
571
572 sdsfree(msg);
573 sdsfree(final_msg);
574}
575
576void luaPushError(lua_State *lua, const char *error) {
577 luaPushErrorBuff(lua, sdsnew(error));
578}
579
580/* In case the error set into the Lua stack by luaPushError() was generated
581 * by the non-error-trapping version of redis.pcall(), which is redis.call(),
582 * this function will raise the Lua error so that the execution of the
583 * script will be halted. */
584int luaError(lua_State *lua) {
585 return lua_error(lua);
586}
587
588
589/* ---------------------------------------------------------------------------
590 * Lua reply to Redis reply conversion functions.
591 * ------------------------------------------------------------------------- */
592
593/* Reply to client 'c' converting the top element in the Lua stack to a
594 * Redis reply. As a side effect the element is consumed from the stack. */
595static void luaReplyToRedisReply(client *c, client* script_client, lua_State *lua) {
596 int t = lua_type(lua,-1);
597
598 if (!lua_checkstack(lua, 4)) {
599 /* Increase the Lua stack if needed to make sure there is enough room
600 * to push 4 elements to the stack. On failure, return error.
601 * Notice that we need, in the worst case, 4 elements because returning a map might
602 * require push 4 elements to the Lua stack.*/
603 addReplyErrorFormat(c, "reached lua stack limit");
604 lua_pop(lua,1); /* pop the element from the stack */
605 return;
606 }
607
608 switch(t) {
609 case LUA_TSTRING:
610 addReplyBulkCBuffer(c,(char*)lua_tostring(lua,-1),lua_strlen(lua,-1));
611 break;
612 case LUA_TBOOLEAN:
613 if (script_client->resp == 2)
614 addReply(c,lua_toboolean(lua,-1) ? shared.cone :
615 shared.null[c->resp]);
616 else
617 addReplyBool(c,lua_toboolean(lua,-1));
618 break;
619 case LUA_TNUMBER:
620 addReplyLongLong(c,(long long)lua_tonumber(lua,-1));
621 break;
622 case LUA_TTABLE:
623 /* We need to check if it is an array, an error, or a status reply.
624 * Error are returned as a single element table with 'err' field.
625 * Status replies are returned as single element table with 'ok'
626 * field. */
627
628 /* Handle error reply. */
629 /* we took care of the stack size on function start */
630 lua_pushstring(lua,"err");
631 lua_gettable(lua,-2);
632 t = lua_type(lua,-1);
633 if (t == LUA_TSTRING) {
634 lua_pop(lua, 1); /* pop the error message, we will use luaExtractErrorInformation to get error information */
635 errorInfo err_info = {0};
636 luaExtractErrorInformation(lua, &err_info);
637 addReplyErrorFormatEx(c,
638 err_info.ignore_err_stats_update? ERR_REPLY_FLAG_NO_STATS_UPDATE: 0,
639 "-%s",
640 err_info.msg);
641 luaErrorInformationDiscard(&err_info);
642 lua_pop(lua,1); /* pop the result table */
643 return;
644 }
645 lua_pop(lua,1); /* Discard field name pushed before. */
646
647 /* Handle status reply. */
648 lua_pushstring(lua,"ok");
649 lua_gettable(lua,-2);
650 t = lua_type(lua,-1);
651 if (t == LUA_TSTRING) {
652 sds ok = sdsnew(lua_tostring(lua,-1));
653 sdsmapchars(ok,"\r\n"," ",2);
654 addReplySds(c,sdscatprintf(sdsempty(),"+%s\r\n",ok));
655 sdsfree(ok);
656 lua_pop(lua,2);
657 return;
658 }
659 lua_pop(lua,1); /* Discard field name pushed before. */
660
661 /* Handle double reply. */
662 lua_pushstring(lua,"double");
663 lua_gettable(lua,-2);
664 t = lua_type(lua,-1);
665 if (t == LUA_TNUMBER) {
666 addReplyDouble(c,lua_tonumber(lua,-1));
667 lua_pop(lua,2);
668 return;
669 }
670 lua_pop(lua,1); /* Discard field name pushed before. */
671
672 /* Handle big number reply. */
673 lua_pushstring(lua,"big_number");
674 lua_gettable(lua,-2);
675 t = lua_type(lua,-1);
676 if (t == LUA_TSTRING) {
677 sds big_num = sdsnewlen(lua_tostring(lua,-1), lua_strlen(lua,-1));
678 sdsmapchars(big_num,"\r\n"," ",2);
679 addReplyBigNum(c,big_num,sdslen(big_num));
680 sdsfree(big_num);
681 lua_pop(lua,2);
682 return;
683 }
684 lua_pop(lua,1); /* Discard field name pushed before. */
685
686 /* Handle verbatim reply. */
687 lua_pushstring(lua,"verbatim_string");
688 lua_gettable(lua,-2);
689 t = lua_type(lua,-1);
690 if (t == LUA_TTABLE) {
691 lua_pushstring(lua,"format");
692 lua_gettable(lua,-2);
693 t = lua_type(lua,-1);
694 if (t == LUA_TSTRING){
695 char* format = (char*)lua_tostring(lua,-1);
696 lua_pushstring(lua,"string");
697 lua_gettable(lua,-3);
698 t = lua_type(lua,-1);
699 if (t == LUA_TSTRING){
700 size_t len;
701 char* str = (char*)lua_tolstring(lua,-1,&len);
702 addReplyVerbatim(c, str, len, format);
703 lua_pop(lua,4);
704 return;
705 }
706 lua_pop(lua,1);
707 }
708 lua_pop(lua,1);
709 }
710 lua_pop(lua,1); /* Discard field name pushed before. */
711
712 /* Handle map reply. */
713 lua_pushstring(lua,"map");
714 lua_gettable(lua,-2);
715 t = lua_type(lua,-1);
716 if (t == LUA_TTABLE) {
717 int maplen = 0;
718 void *replylen = addReplyDeferredLen(c);
719 /* we took care of the stack size on function start */
720 lua_pushnil(lua); /* Use nil to start iteration. */
721 while (lua_next(lua,-2)) {
722 /* Stack now: table, key, value */
723 lua_pushvalue(lua,-2); /* Dup key before consuming. */
724 luaReplyToRedisReply(c, script_client, lua); /* Return key. */
725 luaReplyToRedisReply(c, script_client, lua); /* Return value. */
726 /* Stack now: table, key. */
727 maplen++;
728 }
729 setDeferredMapLen(c,replylen,maplen);
730 lua_pop(lua,2);
731 return;
732 }
733 lua_pop(lua,1); /* Discard field name pushed before. */
734
735 /* Handle set reply. */
736 lua_pushstring(lua,"set");
737 lua_gettable(lua,-2);
738 t = lua_type(lua,-1);
739 if (t == LUA_TTABLE) {
740 int setlen = 0;
741 void *replylen = addReplyDeferredLen(c);
742 /* we took care of the stack size on function start */
743 lua_pushnil(lua); /* Use nil to start iteration. */
744 while (lua_next(lua,-2)) {
745 /* Stack now: table, key, true */
746 lua_pop(lua,1); /* Discard the boolean value. */
747 lua_pushvalue(lua,-1); /* Dup key before consuming. */
748 luaReplyToRedisReply(c, script_client, lua); /* Return key. */
749 /* Stack now: table, key. */
750 setlen++;
751 }
752 setDeferredSetLen(c,replylen,setlen);
753 lua_pop(lua,2);
754 return;
755 }
756 lua_pop(lua,1); /* Discard field name pushed before. */
757
758 /* Handle the array reply. */
759 void *replylen = addReplyDeferredLen(c);
760 int j = 1, mbulklen = 0;
761 while(1) {
762 /* we took care of the stack size on function start */
763 lua_pushnumber(lua,j++);
764 lua_gettable(lua,-2);
765 t = lua_type(lua,-1);
766 if (t == LUA_TNIL) {
767 lua_pop(lua,1);
768 break;
769 }
770 luaReplyToRedisReply(c, script_client, lua);
771 mbulklen++;
772 }
773 setDeferredArrayLen(c,replylen,mbulklen);
774 break;
775 default:
776 addReplyNull(c);
777 }
778 lua_pop(lua,1);
779}
780
781/* ---------------------------------------------------------------------------
782 * Lua redis.* functions implementations.
783 * ------------------------------------------------------------------------- */
784
785static robj **luaArgsToRedisArgv(lua_State *lua, int *argc) {
786 int j;
787 /* Require at least one argument */
788 *argc = lua_gettop(lua);
789 if (*argc == 0) {
790 luaPushError(lua, "Please specify at least one argument for this redis lib call");
791 return NULL;
792 }
793
794 /* Build the arguments vector */
795 robj **argv = zcalloc(sizeof(robj*) * *argc);
796
797 for (j = 0; j < *argc; j++) {
798 char *obj_s;
799 size_t obj_len;
800 char dbuf[64];
801
802 if (lua_type(lua,j+1) == LUA_TNUMBER) {
803 /* We can't use lua_tolstring() for number -> string conversion
804 * since Lua uses a format specifier that loses precision. */
805 lua_Number num = lua_tonumber(lua,j+1);
806
807 obj_len = snprintf(dbuf,sizeof(dbuf),"%.17g",(double)num);
808 obj_s = dbuf;
809 } else {
810 obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
811 if (obj_s == NULL) break; /* Not a string. */
812 }
813
814 argv[j] = createStringObject(obj_s, obj_len);
815 }
816
817 /* Pop all arguments from the stack, we do not need them anymore
818 * and this way we guaranty we will have room on the stack for the result. */
819 lua_pop(lua, *argc);
820
821 /* Check if one of the arguments passed by the Lua script
822 * is not a string or an integer (lua_isstring() return true for
823 * integers as well). */
824 if (j != *argc) {
825 j--;
826 while (j >= 0) {
827 decrRefCount(argv[j]);
828 j--;
829 }
830 zfree(argv);
831 luaPushError(lua, "Lua redis lib command arguments must be strings or integers");
832 return NULL;
833 }
834
835 return argv;
836}
837
838static int luaRedisGenericCommand(lua_State *lua, int raise_error) {
839 int j;
840 scriptRunCtx* rctx = luaGetFromRegistry(lua, REGISTRY_RUN_CTX_NAME);
841 if (!rctx) {
842 luaPushError(lua, "redis.call/pcall can only be called inside a script invocation");
843 return luaError(lua);
844 }
845 sds err = NULL;
846 client* c = rctx->c;
847 sds reply;
848
849 int argc;
850 robj **argv = luaArgsToRedisArgv(lua, &argc);
851 if (argv == NULL) {
852 return raise_error ? luaError(lua) : 1;
853 }
854
855 static int inuse = 0; /* Recursive calls detection. */
856
857 /* By using Lua debug hooks it is possible to trigger a recursive call
858 * to luaRedisGenericCommand(), which normally should never happen.
859 * To make this function reentrant is futile and makes it slower, but
860 * we should at least detect such a misuse, and abort. */
861 if (inuse) {
862 char *recursion_warning =
863 "luaRedisGenericCommand() recursive call detected. "
864 "Are you doing funny stuff with Lua debug hooks?";
865 serverLog(LL_WARNING,"%s",recursion_warning);
866 luaPushError(lua,recursion_warning);
867 return 1;
868 }
869 inuse++;
870
871 /* Log the command if debugging is active. */
872 if (ldbIsEnabled()) {
873 sds cmdlog = sdsnew("<redis>");
874 for (j = 0; j < c->argc; j++) {
875 if (j == 10) {
876 cmdlog = sdscatprintf(cmdlog," ... (%d more)",
877 c->argc-j-1);
878 break;
879 } else {
880 cmdlog = sdscatlen(cmdlog," ",1);
881 cmdlog = sdscatsds(cmdlog,c->argv[j]->ptr);
882 }
883 }
884 ldbLog(cmdlog);
885 }
886
887 scriptCall(rctx, argv, argc, &err);
888 if (err) {
889 luaPushError(lua, err);
890 sdsfree(err);
891 /* push a field indicate to ignore updating the stats on this error
892 * because it was already updated when executing the command. */
893 lua_pushstring(lua,"ignore_error_stats_update");
894 lua_pushboolean(lua, 1);
895 lua_settable(lua,-3);
896 goto cleanup;
897 }
898
899 /* Convert the result of the Redis command into a suitable Lua type.
900 * The first thing we need is to create a single string from the client
901 * output buffers. */
902 if (listLength(c->reply) == 0 && (size_t)c->bufpos < c->buf_usable_size) {
903 /* This is a fast path for the common case of a reply inside the
904 * client static buffer. Don't create an SDS string but just use
905 * the client buffer directly. */
906 c->buf[c->bufpos] = '\0';
907 reply = c->buf;
908 c->bufpos = 0;
909 } else {
910 reply = sdsnewlen(c->buf,c->bufpos);
911 c->bufpos = 0;
912 while(listLength(c->reply)) {
913 clientReplyBlock *o = listNodeValue(listFirst(c->reply));
914
915 reply = sdscatlen(reply,o->buf,o->used);
916 listDelNode(c->reply,listFirst(c->reply));
917 }
918 }
919 if (raise_error && reply[0] != '-') raise_error = 0;
920 redisProtocolToLuaType(lua,reply);
921
922 /* If the debugger is active, log the reply from Redis. */
923 if (ldbIsEnabled())
924 ldbLogRedisReply(reply);
925
926 if (reply != c->buf) sdsfree(reply);
927 c->reply_bytes = 0;
928
929cleanup:
930 /* Clean up. Command code may have changed argv/argc so we use the
931 * argv/argc of the client instead of the local variables. */
932 freeClientArgv(c);
933 c->user = NULL;
934 inuse--;
935
936 if (raise_error) {
937 /* If we are here we should have an error in the stack, in the
938 * form of a table with an "err" field. Extract the string to
939 * return the plain error. */
940 return luaError(lua);
941 }
942 return 1;
943}
944
945/* Our implementation to lua pcall.
946 * We need this implementation for backward
947 * comparability with older Redis versions.
948 *
949 * On Redis 7, the error object is a table,
950 * compare to older version where the error
951 * object is a string. To keep backward
952 * comparability we catch the table object
953 * and just return the error message. */
954static int luaRedisPcall(lua_State *lua) {
955 int argc = lua_gettop(lua);
956 lua_pushboolean(lua, 1); /* result place holder */
957 lua_insert(lua, 1);
958 if (lua_pcall(lua, argc - 1, LUA_MULTRET, 0)) {
959 /* Error */
960 lua_remove(lua, 1); /* remove the result place holder, now we have room for at least one element */
961 if (lua_istable(lua, -1)) {
962 lua_getfield(lua, -1, "err");
963 if (lua_isstring(lua, -1)) {
964 lua_replace(lua, -2); /* replace the error message with the table */
965 }
966 }
967 lua_pushboolean(lua, 0); /* push result */
968 lua_insert(lua, 1);
969 }
970 return lua_gettop(lua);
971
972}
973
974/* redis.call() */
975static int luaRedisCallCommand(lua_State *lua) {
976 return luaRedisGenericCommand(lua,1);
977}
978
979/* redis.pcall() */
980static int luaRedisPCallCommand(lua_State *lua) {
981 return luaRedisGenericCommand(lua,0);
982}
983
984/* This adds redis.sha1hex(string) to Lua scripts using the same hashing
985 * function used for sha1ing lua scripts. */
986static int luaRedisSha1hexCommand(lua_State *lua) {
987 int argc = lua_gettop(lua);
988 char digest[41];
989 size_t len;
990 char *s;
991
992 if (argc != 1) {
993 luaPushError(lua, "wrong number of arguments");
994 return luaError(lua);
995 }
996
997 s = (char*)lua_tolstring(lua,1,&len);
998 sha1hex(digest,s,len);
999 lua_pushstring(lua,digest);
1000 return 1;
1001}
1002
1003/* Returns a table with a single field 'field' set to the string value
1004 * passed as argument. This helper function is handy when returning
1005 * a Redis Protocol error or status reply from Lua:
1006 *
1007 * return redis.error_reply("ERR Some Error")
1008 * return redis.status_reply("ERR Some Error")
1009 */
1010static int luaRedisReturnSingleFieldTable(lua_State *lua, char *field) {
1011 if (lua_gettop(lua) != 1 || lua_type(lua,-1) != LUA_TSTRING) {
1012 luaPushError(lua, "wrong number or type of arguments");
1013 return 1;
1014 }
1015
1016 lua_newtable(lua);
1017 lua_pushstring(lua, field);
1018 lua_pushvalue(lua, -3);
1019 lua_settable(lua, -3);
1020 return 1;
1021}
1022
1023/* redis.error_reply() */
1024static int luaRedisErrorReplyCommand(lua_State *lua) {
1025 if (lua_gettop(lua) != 1 || lua_type(lua,-1) != LUA_TSTRING) {
1026 luaPushError(lua, "wrong number or type of arguments");
1027 return 1;
1028 }
1029
1030 /* add '-' if not exists */
1031 const char *err = lua_tostring(lua, -1);
1032 sds err_buff = NULL;
1033 if (err[0] != '-') {
1034 err_buff = sdscatfmt(sdsempty(), "-%s", err);
1035 } else {
1036 err_buff = sdsnew(err);
1037 }
1038 luaPushErrorBuff(lua, err_buff);
1039 return 1;
1040}
1041
1042/* redis.status_reply() */
1043static int luaRedisStatusReplyCommand(lua_State *lua) {
1044 return luaRedisReturnSingleFieldTable(lua,"ok");
1045}
1046
1047/* redis.set_repl()
1048 *
1049 * Set the propagation of write commands executed in the context of the
1050 * script to on/off for AOF and slaves. */
1051static int luaRedisSetReplCommand(lua_State *lua) {
1052 int flags, argc = lua_gettop(lua);
1053
1054 scriptRunCtx* rctx = luaGetFromRegistry(lua, REGISTRY_RUN_CTX_NAME);
1055 if (!rctx) {
1056 luaPushError(lua, "redis.set_repl can only be called inside a script invocation");
1057 return luaError(lua);
1058 }
1059
1060 if (argc != 1) {
1061 luaPushError(lua, "redis.set_repl() requires two arguments.");
1062 return luaError(lua);
1063 }
1064
1065 flags = lua_tonumber(lua,-1);
1066 if ((flags & ~(PROPAGATE_AOF|PROPAGATE_REPL)) != 0) {
1067 luaPushError(lua, "Invalid replication flags. Use REPL_AOF, REPL_REPLICA, REPL_ALL or REPL_NONE.");
1068 return luaError(lua);
1069 }
1070
1071 scriptSetRepl(rctx, flags);
1072 return 0;
1073}
1074
1075/* redis.acl_check_cmd()
1076 *
1077 * Checks ACL permissions for given command for the current user. */
1078static int luaRedisAclCheckCmdPermissionsCommand(lua_State *lua) {
1079 scriptRunCtx* rctx = luaGetFromRegistry(lua, REGISTRY_RUN_CTX_NAME);
1080 if (!rctx) {
1081 luaPushError(lua, "redis.acl_check_cmd can only be called inside a script invocation");
1082 return luaError(lua);
1083 }
1084 int raise_error = 0;
1085
1086 int argc;
1087 robj **argv = luaArgsToRedisArgv(lua, &argc);
1088
1089 /* Require at least one argument */
1090 if (argv == NULL) return luaError(lua);
1091
1092 /* Find command */
1093 struct redisCommand *cmd;
1094 if ((cmd = lookupCommand(argv, argc)) == NULL) {
1095 luaPushError(lua, "Invalid command passed to redis.acl_check_cmd()");
1096 raise_error = 1;
1097 } else {
1098 int keyidxptr;
1099 if (ACLCheckAllUserCommandPerm(rctx->original_client->user, cmd, argv, argc, &keyidxptr) != ACL_OK) {
1100 lua_pushboolean(lua, 0);
1101 } else {
1102 lua_pushboolean(lua, 1);
1103 }
1104 }
1105
1106 while (argc--) decrRefCount(argv[argc]);
1107 zfree(argv);
1108 if (raise_error)
1109 return luaError(lua);
1110 else
1111 return 1;
1112}
1113
1114
1115/* redis.log() */
1116static int luaLogCommand(lua_State *lua) {
1117 int j, argc = lua_gettop(lua);
1118 int level;
1119 sds log;
1120
1121 if (argc < 2) {
1122 luaPushError(lua, "redis.log() requires two arguments or more.");
1123 return luaError(lua);
1124 } else if (!lua_isnumber(lua,-argc)) {
1125 luaPushError(lua, "First argument must be a number (log level).");
1126 return luaError(lua);
1127 }
1128 level = lua_tonumber(lua,-argc);
1129 if (level < LL_DEBUG || level > LL_WARNING) {
1130 luaPushError(lua, "Invalid debug level.");
1131 return luaError(lua);
1132 }
1133 if (level < server.verbosity) return 0;
1134
1135 /* Glue together all the arguments */
1136 log = sdsempty();
1137 for (j = 1; j < argc; j++) {
1138 size_t len;
1139 char *s;
1140
1141 s = (char*)lua_tolstring(lua,(-argc)+j,&len);
1142 if (s) {
1143 if (j != 1) log = sdscatlen(log," ",1);
1144 log = sdscatlen(log,s,len);
1145 }
1146 }
1147 serverLogRaw(level,log);
1148 sdsfree(log);
1149 return 0;
1150}
1151
1152/* redis.setresp() */
1153static int luaSetResp(lua_State *lua) {
1154 scriptRunCtx* rctx = luaGetFromRegistry(lua, REGISTRY_RUN_CTX_NAME);
1155 if (!rctx) {
1156 luaPushError(lua, "redis.setresp can only be called inside a script invocation");
1157 return luaError(lua);
1158 }
1159 int argc = lua_gettop(lua);
1160
1161 if (argc != 1) {
1162 luaPushError(lua, "redis.setresp() requires one argument.");
1163 return luaError(lua);
1164 }
1165
1166 int resp = lua_tonumber(lua,-argc);
1167 if (resp != 2 && resp != 3) {
1168 luaPushError(lua, "RESP version must be 2 or 3.");
1169 return luaError(lua);
1170 }
1171 scriptSetResp(rctx, resp);
1172 return 0;
1173}
1174
1175/* ---------------------------------------------------------------------------
1176 * Lua engine initialization and reset.
1177 * ------------------------------------------------------------------------- */
1178
1179static void luaLoadLib(lua_State *lua, const char *libname, lua_CFunction luafunc) {
1180 lua_pushcfunction(lua, luafunc);
1181 lua_pushstring(lua, libname);
1182 lua_call(lua, 1, 0);
1183}
1184
1185LUALIB_API int (luaopen_cjson) (lua_State *L);
1186LUALIB_API int (luaopen_struct) (lua_State *L);
1187LUALIB_API int (luaopen_cmsgpack) (lua_State *L);
1188LUALIB_API int (luaopen_bit) (lua_State *L);
1189
1190static void luaLoadLibraries(lua_State *lua) {
1191 luaLoadLib(lua, "", luaopen_base);
1192 luaLoadLib(lua, LUA_TABLIBNAME, luaopen_table);
1193 luaLoadLib(lua, LUA_STRLIBNAME, luaopen_string);
1194 luaLoadLib(lua, LUA_MATHLIBNAME, luaopen_math);
1195 luaLoadLib(lua, LUA_DBLIBNAME, luaopen_debug);
1196 luaLoadLib(lua, "cjson", luaopen_cjson);
1197 luaLoadLib(lua, "struct", luaopen_struct);
1198 luaLoadLib(lua, "cmsgpack", luaopen_cmsgpack);
1199 luaLoadLib(lua, "bit", luaopen_bit);
1200
1201#if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
1202 luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package);
1203 luaLoadLib(lua, LUA_OSLIBNAME, luaopen_os);
1204#endif
1205}
1206
1207/* Return sds of the string value located on stack at the given index.
1208 * Return NULL if the value is not a string. */
1209sds luaGetStringSds(lua_State *lua, int index) {
1210 if (!lua_isstring(lua, index)) {
1211 return NULL;
1212 }
1213
1214 size_t len;
1215 const char *str = lua_tolstring(lua, index, &len);
1216 sds str_sds = sdsnewlen(str, len);
1217 return str_sds;
1218}
1219
1220static int luaProtectedTableError(lua_State *lua) {
1221 int argc = lua_gettop(lua);
1222 if (argc != 2) {
1223 serverLog(LL_WARNING, "malicious code trying to call luaProtectedTableError with wrong arguments");
1224 luaL_error(lua, "Wrong number of arguments to luaProtectedTableError");
1225 }
1226 if (!lua_isstring(lua, -1) && !lua_isnumber(lua, -1)) {
1227 luaL_error(lua, "Second argument to luaProtectedTableError must be a string or number");
1228 }
1229 const char *variable_name = lua_tostring(lua, -1);
1230 luaL_error(lua, "Script attempted to access nonexistent global variable '%s'", variable_name);
1231 return 0;
1232}
1233
1234/* Set a special metatable on the table on the top of the stack.
1235 * The metatable will raise an error if the user tries to fetch
1236 * an un-existing value.
1237 *
1238 * The function assumes the Lua stack have a least enough
1239 * space to push 2 element, its up to the caller to verify
1240 * this before calling this function. */
1241void luaSetErrorMetatable(lua_State *lua) {
1242 lua_newtable(lua); /* push metatable */
1243 lua_pushcfunction(lua, luaProtectedTableError); /* push get error handler */
1244 lua_setfield(lua, -2, "__index");
1245 lua_setmetatable(lua, -2);
1246}
1247
1248static int luaNewIndexAllowList(lua_State *lua) {
1249 int argc = lua_gettop(lua);
1250 if (argc != 3) {
1251 serverLog(LL_WARNING, "malicious code trying to call luaProtectedTableError with wrong arguments");
1252 luaL_error(lua, "Wrong number of arguments to luaNewIndexAllowList");
1253 }
1254 if (!lua_istable(lua, -3)) {
1255 luaL_error(lua, "first argument to luaNewIndexAllowList must be a table");
1256 }
1257 if (!lua_isstring(lua, -2) && !lua_isnumber(lua, -2)) {
1258 luaL_error(lua, "Second argument to luaNewIndexAllowList must be a string or number");
1259 }
1260 const char *variable_name = lua_tostring(lua, -2);
1261 /* check if the key is in our allow list */
1262
1263 char ***allow_l = allow_lists;
1264 for (; *allow_l ; ++allow_l){
1265 char **c = *allow_l;
1266 for (; *c ; ++c) {
1267 if (strcmp(*c, variable_name) == 0) {
1268 break;
1269 }
1270 }
1271 if (*c) {
1272 break;
1273 }
1274 }
1275 if (!*allow_l) {
1276 /* Search the value on the back list, if its there we know that it was removed
1277 * on purpose and there is no need to print a warning. */
1278 char **c = deny_list;
1279 for ( ; *c ; ++c) {
1280 if (strcmp(*c, variable_name) == 0) {
1281 break;
1282 }
1283 }
1284 if (!*c) {
1285 serverLog(LL_WARNING, "A key '%s' was added to Lua globals which is not on the globals allow list nor listed on the deny list.", variable_name);
1286 }
1287 } else {
1288 lua_rawset(lua, -3);
1289 }
1290 return 0;
1291}
1292
1293/* Set a metatable with '__newindex' function that verify that
1294 * the new index appears on our globals while list.
1295 *
1296 * The metatable is set on the table which located on the top
1297 * of the stack.
1298 */
1299void luaSetAllowListProtection(lua_State *lua) {
1300 lua_newtable(lua); /* push metatable */
1301 lua_pushcfunction(lua, luaNewIndexAllowList); /* push get error handler */
1302 lua_setfield(lua, -2, "__newindex");
1303 lua_setmetatable(lua, -2);
1304}
1305
1306/* Set the readonly flag on the table located on the top of the stack
1307 * and recursively call this function on each table located on the original
1308 * table. Also, recursively call this function on the metatables.*/
1309void luaSetTableProtectionRecursively(lua_State *lua) {
1310 /* This protect us from a loop in case we already visited the table
1311 * For example, globals has '_G' key which is pointing back to globals. */
1312 if (lua_isreadonlytable(lua, -1)) {
1313 return;
1314 }
1315
1316 /* protect the current table */
1317 lua_enablereadonlytable(lua, -1, 1);
1318
1319 lua_checkstack(lua, 2);
1320 lua_pushnil(lua); /* Use nil to start iteration. */
1321 while (lua_next(lua,-2)) {
1322 /* Stack now: table, key, value */
1323 if (lua_istable(lua, -1)) {
1324 luaSetTableProtectionRecursively(lua);
1325 }
1326 lua_pop(lua, 1);
1327 }
1328
1329 /* protect the metatable if exists */
1330 if (lua_getmetatable(lua, -1)) {
1331 luaSetTableProtectionRecursively(lua);
1332 lua_pop(lua, 1); /* pop the metatable */
1333 }
1334}
1335
1336void luaRegisterVersion(lua_State* lua) {
1337 lua_pushstring(lua,"REDIS_VERSION_NUM");
1338 lua_pushnumber(lua,REDIS_VERSION_NUM);
1339 lua_settable(lua,-3);
1340
1341 lua_pushstring(lua,"REDIS_VERSION");
1342 lua_pushstring(lua,REDIS_VERSION);
1343 lua_settable(lua,-3);
1344}
1345
1346void luaRegisterLogFunction(lua_State* lua) {
1347 /* redis.log and log levels. */
1348 lua_pushstring(lua,"log");
1349 lua_pushcfunction(lua,luaLogCommand);
1350 lua_settable(lua,-3);
1351
1352 lua_pushstring(lua,"LOG_DEBUG");
1353 lua_pushnumber(lua,LL_DEBUG);
1354 lua_settable(lua,-3);
1355
1356 lua_pushstring(lua,"LOG_VERBOSE");
1357 lua_pushnumber(lua,LL_VERBOSE);
1358 lua_settable(lua,-3);
1359
1360 lua_pushstring(lua,"LOG_NOTICE");
1361 lua_pushnumber(lua,LL_NOTICE);
1362 lua_settable(lua,-3);
1363
1364 lua_pushstring(lua,"LOG_WARNING");
1365 lua_pushnumber(lua,LL_WARNING);
1366 lua_settable(lua,-3);
1367}
1368
1369void luaRegisterRedisAPI(lua_State* lua) {
1370 lua_pushvalue(lua, LUA_GLOBALSINDEX);
1371 luaSetAllowListProtection(lua);
1372 lua_pop(lua, 1);
1373
1374 luaLoadLibraries(lua);
1375
1376 lua_pushcfunction(lua,luaRedisPcall);
1377 lua_setglobal(lua, "pcall");
1378
1379 /* Register the redis commands table and fields */
1380 lua_newtable(lua);
1381
1382 /* redis.call */
1383 lua_pushstring(lua,"call");
1384 lua_pushcfunction(lua,luaRedisCallCommand);
1385 lua_settable(lua,-3);
1386
1387 /* redis.pcall */
1388 lua_pushstring(lua,"pcall");
1389 lua_pushcfunction(lua,luaRedisPCallCommand);
1390 lua_settable(lua,-3);
1391
1392 luaRegisterLogFunction(lua);
1393
1394 luaRegisterVersion(lua);
1395
1396 /* redis.setresp */
1397 lua_pushstring(lua,"setresp");
1398 lua_pushcfunction(lua,luaSetResp);
1399 lua_settable(lua,-3);
1400
1401 /* redis.sha1hex */
1402 lua_pushstring(lua, "sha1hex");
1403 lua_pushcfunction(lua, luaRedisSha1hexCommand);
1404 lua_settable(lua, -3);
1405
1406 /* redis.error_reply and redis.status_reply */
1407 lua_pushstring(lua, "error_reply");
1408 lua_pushcfunction(lua, luaRedisErrorReplyCommand);
1409 lua_settable(lua, -3);
1410 lua_pushstring(lua, "status_reply");
1411 lua_pushcfunction(lua, luaRedisStatusReplyCommand);
1412 lua_settable(lua, -3);
1413
1414 /* redis.set_repl and associated flags. */
1415 lua_pushstring(lua,"set_repl");
1416 lua_pushcfunction(lua,luaRedisSetReplCommand);
1417 lua_settable(lua,-3);
1418
1419 lua_pushstring(lua,"REPL_NONE");
1420 lua_pushnumber(lua,PROPAGATE_NONE);
1421 lua_settable(lua,-3);
1422
1423 lua_pushstring(lua,"REPL_AOF");
1424 lua_pushnumber(lua,PROPAGATE_AOF);
1425 lua_settable(lua,-3);
1426
1427 lua_pushstring(lua,"REPL_SLAVE");
1428 lua_pushnumber(lua,PROPAGATE_REPL);
1429 lua_settable(lua,-3);
1430
1431 lua_pushstring(lua,"REPL_REPLICA");
1432 lua_pushnumber(lua,PROPAGATE_REPL);
1433 lua_settable(lua,-3);
1434
1435 lua_pushstring(lua,"REPL_ALL");
1436 lua_pushnumber(lua,PROPAGATE_AOF|PROPAGATE_REPL);
1437 lua_settable(lua,-3);
1438
1439 /* redis.acl_check_cmd */
1440 lua_pushstring(lua,"acl_check_cmd");
1441 lua_pushcfunction(lua,luaRedisAclCheckCmdPermissionsCommand);
1442 lua_settable(lua,-3);
1443
1444 /* Finally set the table as 'redis' global var. */
1445 lua_setglobal(lua,REDIS_API_NAME);
1446
1447 /* Replace math.random and math.randomseed with our implementations. */
1448 lua_getglobal(lua,"math");
1449
1450 lua_pushstring(lua,"random");
1451 lua_pushcfunction(lua,redis_math_random);
1452 lua_settable(lua,-3);
1453
1454 lua_pushstring(lua,"randomseed");
1455 lua_pushcfunction(lua,redis_math_randomseed);
1456 lua_settable(lua,-3);
1457
1458 lua_setglobal(lua,"math");
1459}
1460
1461/* Set an array of Redis String Objects as a Lua array (table) stored into a
1462 * global variable. */
1463static void luaCreateArray(lua_State *lua, robj **elev, int elec) {
1464 int j;
1465
1466 lua_newtable(lua);
1467 for (j = 0; j < elec; j++) {
1468 lua_pushlstring(lua,(char*)elev[j]->ptr,sdslen(elev[j]->ptr));
1469 lua_rawseti(lua,-2,j+1);
1470 }
1471}
1472
1473/* ---------------------------------------------------------------------------
1474 * Redis provided math.random
1475 * ------------------------------------------------------------------------- */
1476
1477/* We replace math.random() with our implementation that is not affected
1478 * by specific libc random() implementations and will output the same sequence
1479 * (for the same seed) in every arch. */
1480
1481/* The following implementation is the one shipped with Lua itself but with
1482 * rand() replaced by redisLrand48(). */
1483static int redis_math_random (lua_State *L) {
1484 scriptRunCtx* rctx = luaGetFromRegistry(L, REGISTRY_RUN_CTX_NAME);
1485 if (!rctx) {
1486 return luaL_error(L, "math.random can only be called inside a script invocation");
1487 }
1488
1489 /* the `%' avoids the (rare) case of r==1, and is needed also because on
1490 some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
1491 lua_Number r = (lua_Number)(redisLrand48()%REDIS_LRAND48_MAX) /
1492 (lua_Number)REDIS_LRAND48_MAX;
1493 switch (lua_gettop(L)) { /* check number of arguments */
1494 case 0: { /* no arguments */
1495 lua_pushnumber(L, r); /* Number between 0 and 1 */
1496 break;
1497 }
1498 case 1: { /* only upper limit */
1499 int u = luaL_checkint(L, 1);
1500 luaL_argcheck(L, 1<=u, 1, "interval is empty");
1501 lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */
1502 break;
1503 }
1504 case 2: { /* lower and upper limits */
1505 int l = luaL_checkint(L, 1);
1506 int u = luaL_checkint(L, 2);
1507 luaL_argcheck(L, l<=u, 2, "interval is empty");
1508 lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */
1509 break;
1510 }
1511 default: return luaL_error(L, "wrong number of arguments");
1512 }
1513 return 1;
1514}
1515
1516static int redis_math_randomseed (lua_State *L) {
1517 scriptRunCtx* rctx = luaGetFromRegistry(L, REGISTRY_RUN_CTX_NAME);
1518 if (!rctx) {
1519 return luaL_error(L, "math.randomseed can only be called inside a script invocation");
1520 }
1521 redisSrand48(luaL_checkint(L, 1));
1522 return 0;
1523}
1524
1525/* This is the Lua script "count" hook that we use to detect scripts timeout. */
1526static void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
1527 UNUSED(ar);
1528 scriptRunCtx* rctx = luaGetFromRegistry(lua, REGISTRY_RUN_CTX_NAME);
1529 if (scriptInterrupt(rctx) == SCRIPT_KILL) {
1530 serverLog(LL_WARNING,"Lua script killed by user with SCRIPT KILL.");
1531
1532 /*
1533 * Set the hook to invoke all the time so the user
1534         * will not be able to catch the error with pcall and invoke
1535         * pcall again which will prevent the script from ever been killed
1536 */
1537 lua_sethook(lua, luaMaskCountHook, LUA_MASKLINE, 0);
1538
1539 luaPushError(lua,"Script killed by user with SCRIPT KILL...");
1540 luaError(lua);
1541 }
1542}
1543
1544void luaErrorInformationDiscard(errorInfo *err_info) {
1545 if (err_info->msg) sdsfree(err_info->msg);
1546 if (err_info->source) sdsfree(err_info->source);
1547 if (err_info->line) sdsfree(err_info->line);
1548}
1549
1550void luaExtractErrorInformation(lua_State *lua, errorInfo *err_info) {
1551 if (lua_isstring(lua, -1)) {
1552 err_info->msg = sdscatfmt(sdsempty(), "ERR %s", lua_tostring(lua, -1));
1553 err_info->line = NULL;
1554 err_info->source = NULL;
1555 err_info->ignore_err_stats_update = 0;
1556 }
1557
1558 lua_getfield(lua, -1, "err");
1559 if (lua_isstring(lua, -1)) {
1560 err_info->msg = sdsnew(lua_tostring(lua, -1));
1561 }
1562 lua_pop(lua, 1);
1563
1564 lua_getfield(lua, -1, "source");
1565 if (lua_isstring(lua, -1)) {
1566 err_info->source = sdsnew(lua_tostring(lua, -1));
1567 }
1568 lua_pop(lua, 1);
1569
1570 lua_getfield(lua, -1, "line");
1571 if (lua_isstring(lua, -1)) {
1572 err_info->line = sdsnew(lua_tostring(lua, -1));
1573 }
1574 lua_pop(lua, 1);
1575
1576 lua_getfield(lua, -1, "ignore_error_stats_update");
1577 if (lua_isboolean(lua, -1)) {
1578 err_info->ignore_err_stats_update = lua_toboolean(lua, -1);
1579 }
1580 lua_pop(lua, 1);
1581}
1582
1583void luaCallFunction(scriptRunCtx* run_ctx, lua_State *lua, robj** keys, size_t nkeys, robj** args, size_t nargs, int debug_enabled) {
1584 client* c = run_ctx->original_client;
1585 int delhook = 0;
1586
1587 /* We must set it before we set the Lua hook, theoretically the
1588 * Lua hook might be called wheneven we run any Lua instruction
1589 * such as 'luaSetGlobalArray' and we want the run_ctx to be available
1590 * each time the Lua hook is invoked. */
1591 luaSaveOnRegistry(lua, REGISTRY_RUN_CTX_NAME, run_ctx);
1592
1593 if (server.busy_reply_threshold > 0 && !debug_enabled) {
1594 lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
1595 delhook = 1;
1596 } else if (debug_enabled) {
1597 lua_sethook(lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
1598 delhook = 1;
1599 }
1600
1601 /* Populate the argv and keys table accordingly to the arguments that
1602 * EVAL received. */
1603 luaCreateArray(lua,keys,nkeys);
1604 /* On eval, keys and arguments are globals. */
1605 if (run_ctx->flags & SCRIPT_EVAL_MODE){
1606 /* open global protection to set KEYS */
1607 lua_enablereadonlytable(lua, LUA_GLOBALSINDEX, 0);
1608 lua_setglobal(lua,"KEYS");
1609 lua_enablereadonlytable(lua, LUA_GLOBALSINDEX, 1);
1610 }
1611 luaCreateArray(lua,args,nargs);
1612 if (run_ctx->flags & SCRIPT_EVAL_MODE){
1613 /* open global protection to set ARGV */
1614 lua_enablereadonlytable(lua, LUA_GLOBALSINDEX, 0);
1615 lua_setglobal(lua,"ARGV");
1616 lua_enablereadonlytable(lua, LUA_GLOBALSINDEX, 1);
1617 }
1618
1619 /* At this point whether this script was never seen before or if it was
1620 * already defined, we can call it.
1621 * On eval mode, we have zero arguments and expect a single return value.
1622 * In addition the error handler is located on position -2 on the Lua stack.
1623 * On function mode, we pass 2 arguments (the keys and args tables),
1624 * and the error handler is located on position -4 (stack: error_handler, callback, keys, args) */
1625 int err;
1626 if (run_ctx->flags & SCRIPT_EVAL_MODE) {
1627 err = lua_pcall(lua,0,1,-2);
1628 } else {
1629 err = lua_pcall(lua,2,1,-4);
1630 }
1631
1632 /* Call the Lua garbage collector from time to time to avoid a
1633 * full cycle performed by Lua, which adds too latency.
1634 *
1635 * The call is performed every LUA_GC_CYCLE_PERIOD executed commands
1636 * (and for LUA_GC_CYCLE_PERIOD collection steps) because calling it
1637 * for every command uses too much CPU. */
1638 #define LUA_GC_CYCLE_PERIOD 50
1639 {
1640 static long gc_count = 0;
1641
1642 gc_count++;
1643 if (gc_count == LUA_GC_CYCLE_PERIOD) {
1644 lua_gc(lua,LUA_GCSTEP,LUA_GC_CYCLE_PERIOD);
1645 gc_count = 0;
1646 }
1647 }
1648
1649 if (err) {
1650 /* Error object is a table of the following format:
1651 * {err='<error msg>', source='<source file>', line=<line>}
1652 * We can construct the error message from this information */
1653 if (!lua_istable(lua, -1)) {
1654 const char *msg = "execution failure";
1655 if (lua_isstring(lua, -1)) {
1656 msg = lua_tostring(lua, -1);
1657 }
1658 addReplyErrorFormat(c,"Error running script %s, %.100s\n", run_ctx->funcname, msg);
1659 } else {
1660 errorInfo err_info = {0};
1661 sds final_msg = sdsempty();
1662 luaExtractErrorInformation(lua, &err_info);
1663 final_msg = sdscatfmt(final_msg, "-%s",
1664 err_info.msg);
1665 if (err_info.line && err_info.source) {
1666 final_msg = sdscatfmt(final_msg, " script: %s, on %s:%s.",
1667 run_ctx->funcname,
1668 err_info.source,
1669 err_info.line);
1670 }
1671 addReplyErrorSdsEx(c, final_msg, err_info.ignore_err_stats_update? ERR_REPLY_FLAG_NO_STATS_UPDATE : 0);
1672 luaErrorInformationDiscard(&err_info);
1673 }
1674 lua_pop(lua,1); /* Consume the Lua error */
1675 } else {
1676 /* On success convert the Lua return value into Redis protocol, and
1677 * send it to * the client. */
1678 luaReplyToRedisReply(c, run_ctx->c, lua); /* Convert and consume the reply. */
1679 }
1680
1681 /* Perform some cleanup that we need to do both on error and success. */
1682 if (delhook) lua_sethook(lua,NULL,0,0); /* Disable hook */
1683
1684 /* remove run_ctx from registry, its only applicable for the current script. */
1685 luaSaveOnRegistry(lua, REGISTRY_RUN_CTX_NAME, NULL);
1686}
1687
1688unsigned long luaMemory(lua_State *lua) {
1689 return lua_gc(lua, LUA_GCCOUNT, 0) * 1024LL;
1690}
1691