Index: trunk/php/luasandbox/luasandbox.c |
— | — | @@ -1,22 +1,3 @@ |
2 | | - |
3 | | -/* |
4 | | - * To do: |
5 | | - * * Provide a LuaSandbox::doString() as a convenience wrapper for |
6 | | - * LuaSandbox::loadString()->call(), analogous to luaL_dostring(). |
7 | | - * |
8 | | - * * Add a PHP method for registering callback functions individually. |
9 | | - * |
10 | | - * * Provide a wrapper around the base library, which allows only a whitelist |
11 | | - * of functions, not including e.g. loadfile(). This is slightly tricky |
12 | | - * because the functions are not exported from the shared library. It's |
13 | | - * necessary to call luaopen_base() on a separate lua_State, and then to |
14 | | - * copy each function pointer to the destination lua_State using |
15 | | - * lua_tocfunction(). |
16 | | - * |
17 | | - * * Support lua_dump() |
18 | | - * * Protect LuaSandbox->loadString() against malicious binaries |
19 | | - */ |
20 | | - |
21 | 2 | #ifdef HAVE_CONFIG_H |
22 | 3 | #include "config.h" |
23 | 4 | #endif |
— | — | @@ -36,6 +17,7 @@ |
37 | 18 | #include "zend_exceptions.h" |
38 | 19 | #include "php_luasandbox.h" |
39 | 20 | #include "luasandbox_timer.h" |
| 21 | +#include "ext/standard/php_smart_str.h" |
40 | 22 | |
41 | 23 | static zend_object_value luasandbox_new(zend_class_entry *ce TSRMLS_DC); |
42 | 24 | static lua_State * luasandbox_newstate(php_luasandbox_obj * intern); |
— | — | @@ -47,9 +29,12 @@ |
48 | 30 | static void *luasandbox_alloc(void *ud, void *ptr, size_t osize, size_t nsize); |
49 | 31 | static int luasandbox_panic(lua_State * L); |
50 | 32 | static lua_State * luasandbox_state_from_zval(zval * this_ptr TSRMLS_DC); |
| 33 | +static void luasandbox_load_helper(int binary, INTERNAL_FUNCTION_PARAMETERS); |
51 | 34 | static int luasandbox_find_field(lua_State * L, int index, |
52 | 35 | char * spec, int specLength); |
53 | 36 | static void luasandbox_set_timespec(struct timespec * dest, double source); |
| 37 | +static int luasandbox_function_init(zval * this_ptr, php_luasandboxfunction_obj ** pfunc, |
| 38 | + lua_State ** pstate, php_luasandbox_obj ** psandbox TSRMLS_DC); |
54 | 39 | static void luasandbox_call_helper(lua_State * L, php_luasandbox_obj * sandbox, |
55 | 40 | zval *** args, zend_uint numArgs, zval * return_value TSRMLS_DC); |
56 | 41 | static int luasandbox_push_zval(lua_State * L, zval * z); |
— | — | @@ -61,9 +46,57 @@ |
62 | 47 | static void luasandbox_handle_error(lua_State * L, int status); |
63 | 48 | static int luasandbox_push_hashtable(lua_State * L, HashTable * ht); |
64 | 49 | static int luasandbox_call_php(lua_State * L); |
| 50 | +static int luasandbox_dump_writer(lua_State * L, const void * p, size_t sz, void * ud); |
| 51 | +static int luasandbox_base_tostring(lua_State * L); |
65 | 52 | |
66 | 53 | char luasandbox_timeout_message[] = "The maximum execution time for this script was exceeded"; |
67 | 54 | |
| 55 | +/** |
| 56 | + * Allowed global variables. Omissions are: |
| 57 | + * * pcall, xpcall: Changing the protected environment won't work with our |
| 58 | + * current timeout method. |
| 59 | + * * loadfile: insecure. |
| 60 | + * * load, loadstring: Probably creates a protected environment so can't has |
| 61 | + * the same problem as pcall. Also omitting these makes analysis of the |
| 62 | + * code for runtime etc. feasible. |
| 63 | + * * print: Not compatible with a sandbox environment |
| 64 | + * * tostring: Provides addresses of tables and functions, which provides an |
| 65 | + * easy ASLR workaround or heap address discovery mechanism for a memory |
| 66 | + * corruption exploit. |
| 67 | + * * Any new or undocumented functions like newproxy. |
| 68 | + * * package: cpath, loadlib etc. are insecure. |
| 69 | + * * coroutine: Not useful for our application so unreviewed at present. |
| 70 | + * * io, file, os: insecure |
| 71 | + * * debug: Provides various ways to break the sandbox, such as setupvalue() |
| 72 | + * and getregistry(). |
| 73 | + */ |
| 74 | +char * luasandbox_allowed_globals[] = { |
| 75 | + // base |
| 76 | + "assert", |
| 77 | + "error", |
| 78 | + "getmetatable", |
| 79 | + "getfenv", |
| 80 | + "getmetatable", |
| 81 | + "ipairs", |
| 82 | + "next", |
| 83 | + "pairs", |
| 84 | + "rawequal", |
| 85 | + "rawget", |
| 86 | + "rawset", |
| 87 | + "select", |
| 88 | + "setmetatable", |
| 89 | + "tonumber", |
| 90 | + "type", |
| 91 | + "unpack", |
| 92 | + "_G", |
| 93 | + "_VERSION", |
| 94 | + // libs |
| 95 | + "string", |
| 96 | + "table", |
| 97 | + "math" |
| 98 | +}; |
| 99 | +#define LUASANDBOX_NUM_ALLOWED_GLOBALS (sizeof(luasandbox_allowed_globals) / sizeof(char*)) |
| 100 | + |
68 | 101 | zend_class_entry *luasandbox_ce; |
69 | 102 | zend_class_entry *luasandboxerror_ce; |
70 | 103 | zend_class_entry *luasandboxplaceholder_ce; |
— | — | @@ -77,6 +110,11 @@ |
78 | 111 | ZEND_ARG_INFO(0, chunkName) |
79 | 112 | ZEND_END_ARG_INFO() |
80 | 113 | |
| 114 | +ZEND_BEGIN_ARG_INFO(arginfo_luasandbox_loadBinary, 0) |
| 115 | + ZEND_ARG_INFO(0, code) |
| 116 | + ZEND_ARG_INFO(0, chunkName) |
| 117 | +ZEND_END_ARG_INFO() |
| 118 | + |
81 | 119 | ZEND_BEGIN_ARG_INFO(arginfo_luasandbox_setMemoryLimit, 0) |
82 | 120 | ZEND_ARG_INFO(0, limit) |
83 | 121 | ZEND_END_ARG_INFO() |
— | — | @@ -99,6 +137,10 @@ |
100 | 138 | ZEND_BEGIN_ARG_INFO(arginfo_luasandboxfunction_call, 0) |
101 | 139 | ZEND_ARG_INFO(0, ...) |
102 | 140 | ZEND_END_ARG_INFO() |
| 141 | + |
| 142 | +ZEND_BEGIN_ARG_INFO(arginfo_luasandboxfunction_dump, 0) |
| 143 | +ZEND_END_ARG_INFO() |
| 144 | + |
103 | 145 | /* }}} */ |
104 | 146 | |
105 | 147 | /** {{{ function entries */ |
— | — | @@ -108,6 +150,7 @@ |
109 | 151 | |
110 | 152 | const zend_function_entry luasandbox_methods[] = { |
111 | 153 | PHP_ME(LuaSandbox, loadString, arginfo_luasandbox_loadString, 0) |
| 154 | + PHP_ME(LuaSandbox, loadBinary, arginfo_luasandbox_loadBinary, 0) |
112 | 155 | PHP_ME(LuaSandbox, setMemoryLimit, arginfo_luasandbox_setMemoryLimit, 0) |
113 | 156 | PHP_ME(LuaSandbox, setCPULimit, arginfo_luasandbox_setCPULimit, 0) |
114 | 157 | PHP_ME(LuaSandbox, callFunction, arginfo_luasandbox_callFunction, 0) |
— | — | @@ -117,6 +160,7 @@ |
118 | 161 | |
119 | 162 | const zend_function_entry luasandboxfunction_methods[] = { |
120 | 163 | PHP_ME(LuaSandboxFunction, call, arginfo_luasandboxfunction_call, 0) |
| 164 | + PHP_ME(LuaSandboxFunction, dump, arginfo_luasandboxfunction_dump, 0) |
121 | 165 | {NULL, NULL, NULL} |
122 | 166 | }; |
123 | 167 | |
— | — | @@ -154,6 +198,7 @@ |
155 | 199 | */ |
156 | 200 | PHP_MINIT_FUNCTION(luasandbox) |
157 | 201 | { |
| 202 | + int i; |
158 | 203 | /* If you have INI entries, uncomment these lines |
159 | 204 | REGISTER_INI_ENTRIES(); |
160 | 205 | */ |
— | — | @@ -183,6 +228,14 @@ |
184 | 229 | luasandboxfunction_ce = zend_register_internal_class(&ce TSRMLS_CC); |
185 | 230 | luasandboxfunction_ce->create_object = luasandboxfunction_new; |
186 | 231 | |
| 232 | + // Initialise LUASANDBOX_G(allowed_globals) |
| 233 | + LUASANDBOX_G(allowed_globals) = pemalloc(sizeof(HashTable), 1); |
| 234 | + zend_hash_init(LUASANDBOX_G(allowed_globals), LUASANDBOX_NUM_ALLOWED_GLOBALS, NULL, NULL, 1); |
| 235 | + for (i = 0; i < LUASANDBOX_NUM_ALLOWED_GLOBALS; i++) { |
| 236 | + zend_hash_update(LUASANDBOX_G(allowed_globals), |
| 237 | + luasandbox_allowed_globals[i], strlen(luasandbox_allowed_globals[i]) + 1, |
| 238 | + "", 1, NULL); |
| 239 | + } |
187 | 240 | return SUCCESS; |
188 | 241 | } |
189 | 242 | /* }}} */ |
— | — | @@ -191,6 +244,8 @@ |
192 | 245 | */ |
193 | 246 | PHP_MSHUTDOWN_FUNCTION(luasandbox) |
194 | 247 | { |
| 248 | + zend_hash_destroy(LUASANDBOX_G(allowed_globals)); |
| 249 | + pefree(LUASANDBOX_G(allowed_globals), 1); |
195 | 250 | return SUCCESS; |
196 | 251 | } |
197 | 252 | /* }}} */ |
— | — | @@ -276,10 +331,42 @@ |
277 | 332 | lua_atpanic(L, luasandbox_panic); |
278 | 333 | |
279 | 334 | // Load some relatively safe standard libraries |
| 335 | + luaopen_base(L); |
280 | 336 | luaopen_string(L); |
281 | 337 | luaopen_table(L); |
282 | 338 | luaopen_math(L); |
283 | 339 | |
| 340 | + // Remove any globals that aren't in a whitelist. This is mostly to remove |
| 341 | + // unsafe functions from the base library. |
| 342 | + lua_pushnil(L); |
| 343 | + while (lua_next(L, LUA_GLOBALSINDEX) != 0) { |
| 344 | + const char * key; |
| 345 | + size_t key_len; |
| 346 | + void * data; |
| 347 | + lua_pop(L, 1); |
| 348 | + if (lua_type(L, -1) != LUA_TSTRING) { |
| 349 | + continue; |
| 350 | + } |
| 351 | + key = lua_tolstring(L, -1, &key_len); |
| 352 | + if (zend_hash_find(LUASANDBOX_G(allowed_globals), |
| 353 | + (char*)key, key_len + 1, &data) == FAILURE) |
| 354 | + { |
| 355 | + // Not allowed, delete it |
| 356 | + lua_pushnil(L); |
| 357 | + lua_setglobal(L, key); |
| 358 | + } |
| 359 | + } |
| 360 | + |
| 361 | + // Install our own version of tostring |
| 362 | + lua_pushcfunction(L, luasandbox_base_tostring); |
| 363 | + lua_setglobal(L, "tostring"); |
| 364 | + |
| 365 | + // Remove string.dump: may expose private data |
| 366 | + lua_getglobal(L, "string"); |
| 367 | + lua_pushnil(L); |
| 368 | + lua_setfield(L, -2, "dump"); |
| 369 | + lua_pop(L, 1); |
| 370 | + |
284 | 371 | // Create a table for storing chunks |
285 | 372 | lua_newtable(L); |
286 | 373 | lua_setfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks"); |
— | — | @@ -431,8 +518,8 @@ |
432 | 519 | } |
433 | 520 | /* }}} */ |
434 | 521 | |
435 | | -/** {{{ proto int LuaSandbox::loadString(string code, string chunkName) */ |
436 | | -PHP_METHOD(LuaSandbox, loadString) |
| 522 | +/** {{{ luasandbox_load_helper */ |
| 523 | +static void luasandbox_load_helper(int binary, INTERNAL_FUNCTION_PARAMETERS) |
437 | 524 | { |
438 | 525 | char *code, *chunkName = NULL; |
439 | 526 | int codeLength, chunkNameLength; |
— | — | @@ -440,6 +527,7 @@ |
441 | 528 | lua_State * L = luasandbox_state_from_zval(getThis() TSRMLS_CC); |
442 | 529 | size_t index; |
443 | 530 | php_luasandboxfunction_obj * func_obj; |
| 531 | + int have_mark; |
444 | 532 | |
445 | 533 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", |
446 | 534 | &code, &codeLength, &chunkName, &chunkNameLength) == FAILURE) { |
— | — | @@ -457,6 +545,21 @@ |
458 | 546 | } |
459 | 547 | } |
460 | 548 | |
| 549 | + // Check to see if the code is binary (with precompiled data mark) if this |
| 550 | + // was called as loadBinary(), and plain code (without mark) if this was |
| 551 | + // called as loadString() |
| 552 | + have_mark = (php_memnstr(code, LUA_SIGNATURE, |
| 553 | + sizeof(LUA_SIGNATURE) - 1, code + codeLength) != NULL); |
| 554 | + if (binary && !have_mark) { |
| 555 | + php_error_docref(NULL TSRMLS_CC, E_WARNING, |
| 556 | + "the string does not appear to be a valid binary chunk"); |
| 557 | + RETURN_FALSE; |
| 558 | + } else if (!binary && have_mark) { |
| 559 | + php_error_docref(NULL TSRMLS_CC, E_WARNING, |
| 560 | + "cannot load code with a Lua binary chunk marker escape sequence in it"); |
| 561 | + RETURN_FALSE; |
| 562 | + } |
| 563 | + |
461 | 564 | // Get the chunks table |
462 | 565 | lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks"); |
463 | 566 | |
— | — | @@ -489,9 +592,23 @@ |
490 | 593 | // Balance the stack |
491 | 594 | lua_pop(L, 1); |
492 | 595 | } |
| 596 | +/* }}} */ |
493 | 597 | |
| 598 | +/** {{{ proto LuaSandboxFunction LuaSandbox::loadString(string code, string chunkName) */ |
| 599 | +PHP_METHOD(LuaSandbox, loadString) |
| 600 | +{ |
| 601 | + luasandbox_load_helper(0, INTERNAL_FUNCTION_PARAM_PASSTHRU); |
| 602 | +} |
| 603 | + |
494 | 604 | /* }}} */ |
495 | 605 | |
| 606 | +/** {{{ proto LuaSandboxFunction LuaSandbox::loadBinary(string bin, string chunkName) */ |
| 607 | +PHP_METHOD(LuaSandbox, loadBinary) |
| 608 | +{ |
| 609 | + luasandbox_load_helper(1, INTERNAL_FUNCTION_PARAM_PASSTHRU); |
| 610 | +} |
| 611 | +/* }}} */ |
| 612 | + |
496 | 613 | /** {{{ luasandbox_handle_error |
497 | 614 | * |
498 | 615 | * Handles the error return situation from lua_pcall() and lua_load(), where a |
— | — | @@ -633,39 +750,58 @@ |
634 | 751 | } |
635 | 752 | /* }}} */ |
636 | 753 | |
637 | | -/*** {{{ proto array LuaSandboxFunction::call(...) |
| 754 | +/** {{{ luasandbox_function_init |
| 755 | + * Common initialisation for LuaSandboxFunction methods. Initialise the |
| 756 | + * function, state and sandbox pointers, and push the function to the stack. |
638 | 757 | */ |
| 758 | +static int luasandbox_function_init(zval * this_ptr, php_luasandboxfunction_obj ** pfunc, |
| 759 | + lua_State ** pstate, php_luasandbox_obj ** psandbox TSRMLS_DC) |
| 760 | +{ |
| 761 | + *pfunc = (php_luasandboxfunction_obj *) |
| 762 | + zend_object_store_get_object(this_ptr TSRMLS_CC); |
| 763 | + if (!*pfunc || !(*pfunc)->sandbox || !(*pfunc)->index) { |
| 764 | + return 0; |
| 765 | + } |
| 766 | + |
| 767 | + *psandbox = (php_luasandbox_obj*) |
| 768 | + zend_object_store_get_object((*pfunc)->sandbox TSRMLS_CC); |
| 769 | + *pstate = (*psandbox)->state; |
| 770 | + |
| 771 | + // Find the function |
| 772 | + lua_getfield(*pstate, LUA_REGISTRYINDEX, "php_luasandbox_chunks"); |
| 773 | + lua_rawgeti(*pstate, -1, (*pfunc)->index); |
| 774 | + |
| 775 | + // Remove the table from the stack |
| 776 | + lua_remove(*pstate, -2); |
| 777 | + |
| 778 | + return 1; |
| 779 | +} |
| 780 | +/* }}} */ |
| 781 | + |
| 782 | +/** {{{ proto array LuaSandboxFunction::call(...) |
| 783 | + */ |
639 | 784 | PHP_METHOD(LuaSandboxFunction, call) |
640 | 785 | { |
641 | 786 | zend_uint numArgs = 0; |
642 | 787 | zval *** args = NULL; |
643 | 788 | |
644 | | - php_luasandboxfunction_obj * func = (php_luasandboxfunction_obj *) |
645 | | - zend_object_store_get_object(getThis() TSRMLS_CC); |
| 789 | + php_luasandboxfunction_obj * func; |
646 | 790 | lua_State * L; |
647 | 791 | php_luasandbox_obj * sandbox; |
648 | 792 | |
649 | | - if (!func || !func->sandbox || !func->index) { |
| 793 | + if (!luasandbox_function_init(getThis(), &func, &L, &sandbox TSRMLS_CC)) { |
650 | 794 | php_error_docref(NULL TSRMLS_CC, E_WARNING, |
651 | 795 | "attempt to call uninitialized LuaSandboxFunction object" ); |
652 | 796 | RETURN_FALSE; |
653 | 797 | } |
654 | 798 | |
655 | | - sandbox = (php_luasandbox_obj*) |
656 | | - zend_object_store_get_object(func->sandbox TSRMLS_CC); |
657 | | - L = sandbox->state; |
658 | | - |
659 | 799 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", |
660 | 800 | &args, &numArgs) == FAILURE) |
661 | 801 | { |
662 | 802 | RETURN_FALSE; |
663 | 803 | } |
664 | 804 | |
665 | | - // Find the function |
666 | | - lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks"); |
667 | | - lua_rawgeti(L, -1, func->index); |
668 | | - |
669 | | - // Call it |
| 805 | + // Call the function |
670 | 806 | luasandbox_call_helper(L, sandbox, args, numArgs, return_value TSRMLS_CC); |
671 | 807 | |
672 | 808 | // Delete varargs |
— | — | @@ -983,7 +1119,7 @@ |
984 | 1120 | |
985 | 1121 | // Add the current table to the recursion guard hashtable |
986 | 1122 | // Use the pointer as the key, zero-length data |
987 | | - zend_hash_update(recursionGuard, (char*)&ptr, sizeof(void*), &data, 0, NULL); |
| 1123 | + zend_hash_update(recursionGuard, (char*)&ptr, sizeof(void*), "", 1, NULL); |
988 | 1124 | |
989 | 1125 | // Process the array |
990 | 1126 | array_init(z); |
— | — | @@ -1180,7 +1316,72 @@ |
1181 | 1317 | } |
1182 | 1318 | /* }}} */ |
1183 | 1319 | |
| 1320 | +/** {{{ string LuaSandboxFunction::dump() */ |
| 1321 | +PHP_METHOD(LuaSandboxFunction, dump) |
| 1322 | +{ |
| 1323 | + php_luasandboxfunction_obj * func; |
| 1324 | + lua_State * L; |
| 1325 | + php_luasandbox_obj * sandbox; |
| 1326 | + smart_str buf = {0}; |
| 1327 | + |
| 1328 | + if (!luasandbox_function_init(getThis(), &func, &L, &sandbox TSRMLS_CC)) { |
| 1329 | + php_error_docref(NULL TSRMLS_CC, E_WARNING, |
| 1330 | + "attempt to call uninitialized LuaSandboxFunction object" ); |
| 1331 | + RETURN_FALSE; |
| 1332 | + } |
| 1333 | + |
| 1334 | + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { |
| 1335 | + return; |
| 1336 | + } |
| 1337 | + |
| 1338 | + lua_dump(L, luasandbox_dump_writer, (void*)&buf); |
| 1339 | + smart_str_0(&buf); |
| 1340 | + if (buf.len) { |
| 1341 | + RETURN_STRINGL(buf.c, buf.len, 0); |
| 1342 | + } else { |
| 1343 | + smart_str_free(&buf); |
| 1344 | + RETURN_EMPTY_STRING(); |
| 1345 | + } |
| 1346 | +} |
1184 | 1347 | /* }}} */ |
| 1348 | + |
| 1349 | +/** {{{ luasandbox_dump_writer */ |
| 1350 | +static int luasandbox_dump_writer(lua_State * L, const void * p, size_t sz, void * ud) |
| 1351 | +{ |
| 1352 | + smart_str * buf = (smart_str *)ud; |
| 1353 | + smart_str_appendl(buf, p, sz); |
| 1354 | + return 0; |
| 1355 | +} |
| 1356 | +/* }}} */ |
| 1357 | + |
| 1358 | +/** {{{ luasandbox_base_tostring |
| 1359 | + * This is identical to luaB_tostring except that it does not call lua_topointer(). |
| 1360 | + */ |
| 1361 | +static int luasandbox_base_tostring(lua_State * L) |
| 1362 | +{ |
| 1363 | + luaL_checkany(L, 1); |
| 1364 | + if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ |
| 1365 | + return 1; /* use its value */ |
| 1366 | + switch (lua_type(L, 1)) { |
| 1367 | + case LUA_TNUMBER: |
| 1368 | + lua_pushstring(L, lua_tostring(L, 1)); |
| 1369 | + break; |
| 1370 | + case LUA_TSTRING: |
| 1371 | + lua_pushvalue(L, 1); |
| 1372 | + break; |
| 1373 | + case LUA_TBOOLEAN: |
| 1374 | + lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); |
| 1375 | + break; |
| 1376 | + case LUA_TNIL: |
| 1377 | + lua_pushliteral(L, "nil"); |
| 1378 | + break; |
| 1379 | + default: |
| 1380 | + lua_pushfstring(L, "%s", luaL_typename(L, 1)); |
| 1381 | + break; |
| 1382 | + } |
| 1383 | + return 1; |
| 1384 | +} |
| 1385 | +/* }}} */ |
1185 | 1386 | /* |
1186 | 1387 | * Local variables: |
1187 | 1388 | * tab-width: 4 |
Index: trunk/php/luasandbox/php_luasandbox.h |
— | — | @@ -27,17 +27,19 @@ |
28 | 28 | PHP_MINFO_FUNCTION(luasandbox); |
29 | 29 | |
30 | 30 | PHP_METHOD(LuaSandbox, loadString); |
31 | | -PHP_METHOD(LuaSandbox, doString); |
| 31 | +PHP_METHOD(LuaSandbox, loadBinary); |
32 | 32 | PHP_METHOD(LuaSandbox, setMemoryLimit); |
33 | 33 | PHP_METHOD(LuaSandbox, setCPULimit); |
34 | 34 | PHP_METHOD(LuaSandbox, callFunction); |
35 | 35 | PHP_METHOD(LuaSandbox, register); |
36 | 36 | |
37 | 37 | PHP_METHOD(LuaSandboxFunction, call); |
| 38 | +PHP_METHOD(LuaSandboxFunction, dump); |
38 | 39 | |
39 | 40 | ZEND_BEGIN_MODULE_GLOBALS(luasandbox) |
40 | 41 | int signal_handler_installed; |
41 | 42 | struct sigaction old_handler; |
| 43 | + HashTable * allowed_globals; |
42 | 44 | ZEND_END_MODULE_GLOBALS(luasandbox) |
43 | 45 | |
44 | 46 | #ifdef ZTS |