r94863 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94862‎ | r94863 | r94864 >
Date:04:54, 18 August 2011
Author:tstarling
Status:deferred
Tags:
Comment:
* Documented everything.
* Renamed LuaSandbox::register() to LuaSandbox::registerLibrary(). The book "Programming in Lua" raises the interesting possibility of defining classes in C for object-oriented programming in Lua. If we want to support that, then a family of LuaSandbox::register*() functions makes sense.
* Store the maximum index for stored chunks in the PHP object instead of in the Lua registry, so that when there is an emergency timeout, the LuaSandboxFunction objects will be safely invalidated, instead of calling some other function.
* Introduced a separate exception class for emergency timeouts, since it's essential to know when the LuaSandboxFunction objects are invalidated.
Modified paths:
  • /trunk/php/luasandbox/luasandbox.c (modified) (history)
  • /trunk/php/luasandbox/php_luasandbox.h (modified) (history)

Diff [purge]

Index: trunk/php/luasandbox/luasandbox.c
@@ -56,7 +56,7 @@
5757 * * pcall, xpcall: Changing the protected environment won't work with our
5858 * current timeout method.
5959 * * loadfile: insecure.
60 - * * load, loadstring: Probably creates a protected environment so can't has
 60+ * * load, loadstring: Probably creates a protected environment so has
6161 * the same problem as pcall. Also omitting these makes analysis of the
6262 * code for runtime etc. feasible.
6363 * * print: Not compatible with a sandbox environment
@@ -99,6 +99,7 @@
100100
101101 zend_class_entry *luasandbox_ce;
102102 zend_class_entry *luasandboxerror_ce;
 103+zend_class_entry *luasandboxemergencytimeout_ce;
103104 zend_class_entry *luasandboxplaceholder_ce;
104105 zend_class_entry *luasandboxfunction_ce;
105106
@@ -129,7 +130,7 @@
130131 ZEND_ARG_INFO(0, ...)
131132 ZEND_END_ARG_INFO()
132133
133 -ZEND_BEGIN_ARG_INFO(arginfo_luasandbox_register, 0)
 134+ZEND_BEGIN_ARG_INFO(arginfo_luasandbox_registerLibrary, 0)
134135 ZEND_ARG_INFO(0, libname)
135136 ZEND_ARG_INFO(0, functions)
136137 ZEND_END_ARG_INFO()
@@ -154,7 +155,7 @@
155156 PHP_ME(LuaSandbox, setMemoryLimit, arginfo_luasandbox_setMemoryLimit, 0)
156157 PHP_ME(LuaSandbox, setCPULimit, arginfo_luasandbox_setCPULimit, 0)
157158 PHP_ME(LuaSandbox, callFunction, arginfo_luasandbox_callFunction, 0)
158 - PHP_ME(LuaSandbox, register, arginfo_luasandbox_register, 0)
 159+ PHP_ME(LuaSandbox, registerLibrary, arginfo_luasandbox_registerLibrary, 0)
159160 {NULL, NULL, NULL}
160161 };
161162
@@ -212,6 +213,10 @@
213214 luasandboxerror_ce = zend_register_internal_class_ex(
214215 &ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
215216
 217+ INIT_CLASS_ENTRY(ce, "LuaSandboxEmergencyTimeout", luasandbox_empty_methods);
 218+ luasandboxemergencytimeout_ce = zend_register_internal_class_ex(
 219+ &ce, luasandboxerror_ce, NULL TSRMLS_CC);
 220+
216221 zend_declare_class_constant_long(luasandboxerror_ce,
217222 "RUN", sizeof("RUN"), LUA_ERRRUN);
218223 zend_declare_class_constant_long(luasandboxerror_ce,
@@ -271,6 +276,7 @@
272277 /* }}} */
273278
274279 /** {{{ luasandbox_enter_php
 280+ *
275281 * This function must be called each time a C function is entered from Lua
276282 * and the PHP state needs to be accessed in any way. Before exiting the
277283 * function, luasandbox_leave_php() must be called.
@@ -290,6 +296,9 @@
291297 /* }}} */
292298
293299 /** {{{ luasandbox_leave_php
 300+ *
 301+ * This function must be called after luasandbox_enter_php, before the callback
 302+ * from Lua returns.
294303 */
295304 static inline void luasandbox_leave_php(lua_State * L, php_luasandbox_obj * intern)
296305 {
@@ -297,7 +306,10 @@
298307 }
299308 /* }}} */
300309
301 -/** {{{ luasandbox_new */
 310+/** {{{ luasandbox_new
 311+ *
 312+ * "new" handler for the LuaSandbox class
 313+ */
302314 static zend_object_value luasandbox_new(zend_class_entry *ce TSRMLS_DC)
303315 {
304316 php_luasandbox_obj * intern;
@@ -322,7 +334,11 @@
323335 }
324336 /* }}} */
325337
326 -/** {{{ luasandbox_newstate */
 338+/** {{{ luasandbox_newstate
 339+ *
 340+ * Create a new lua_State which is suitable for running sandboxed scripts in.
 341+ * Initialise libraries and any necessary registry entries.
 342+ */
327343 static lua_State * luasandbox_newstate(php_luasandbox_obj * intern)
328344 {
329345 lua_State * L;
@@ -385,7 +401,10 @@
386402 }
387403 /* }}} */
388404
389 -/** {{{ luasandbox_free_storage */
 405+/** {{{ luasandbox_free_storage
 406+ *
 407+ * "Free storage" handler for LuaSandbox objects.
 408+ */
390409 static void luasandbox_free_storage(void *object TSRMLS_DC)
391410 {
392411 php_luasandbox_obj * intern = (php_luasandbox_obj*)object;
@@ -396,7 +415,13 @@
397416 }
398417 /* }}} */
399418
400 -/** {{{ luasandboxfunction_new */
 419+/** {{{ luasandboxfunction_new
 420+ *
 421+ * "new" handler for the LuaSandboxFunction class.
 422+ *
 423+ * TODO: Make it somehow impossible to construct these objects from user code.
 424+ * Only LuaSandbox methods should be constructing them.
 425+ */
401426 static zend_object_value luasandboxfunction_new(zend_class_entry *ce TSRMLS_CC)
402427 {
403428 php_luasandboxfunction_obj * intern;
@@ -418,7 +443,12 @@
419444 }
420445 /* }}} */
421446
422 -/** {{{ luasandboxfunction_destroy */
 447+/** {{{ luasandboxfunction_destroy
 448+ *
 449+ * Destructor for the LuaSandboxFunction class. Deletes the chunk from the
 450+ * registry and decrements the reference counter for the parent LuaSandbox
 451+ * object.
 452+ */
423453 static void luasandboxfunction_destroy(void *object, zend_object_handle handle TSRMLS_DC)
424454 {
425455 php_luasandboxfunction_obj * func = (php_luasandboxfunction_obj*)object;
@@ -441,7 +471,10 @@
442472 }
443473 /* }}} */
444474
445 -/** {{{ luasandboxfunction_free_storage */
 475+/** {{{ luasandboxfunction_free_storage
 476+ *
 477+ * "Free storage" handler for LuaSandboxFunction objects.
 478+ */
446479 static void luasandboxfunction_free_storage(void *object TSRMLS_DC)
447480 {
448481 php_luasandboxfunction_obj * func = (php_luasandboxfunction_obj*)object;
@@ -451,6 +484,7 @@
452485 /* }}} */
453486
454487 /** {{{ luasandbox_free_zval_userdata
 488+ *
455489 * Free a zval given to Lua by luasandbox_push_zval_userdata.
456490 */
457491 static int luasandbox_free_zval_userdata(lua_State * L)
@@ -467,7 +501,12 @@
468502 }
469503 /* }}} */
470504
471 -/** {{{ luasandbox_alloc */
 505+/** {{{ luasandbox_alloc
 506+ *
 507+ * The Lua allocator function. Use PHP's request-local allocator as a backend.
 508+ * Account for memory usage and deny the allocation request if the amount
 509+ * allocated is above the user-specified limit.
 510+ */
472511 static void *luasandbox_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
473512 {
474513 php_luasandbox_obj * obj = (php_luasandbox_obj*)ud;
@@ -499,7 +538,22 @@
500539 }
501540 /* }}} */
502541
503 -/** {{{ luasandbox_panic */
 542+/** {{{ luasandbox_panic
 543+ *
 544+ * The Lua panic function. It is necessary to raise an E_ERROR, and thus do a
 545+ * longjmp(), since if this function returns, Lua will call exit(), breaking
 546+ * the Apache child.
 547+ *
 548+ * Generally, a panic will happen if the Lua API is used incorrectly in an
 549+ * unprotected environment. Currently this means C code which is called from
 550+ * PHP, not directly or indirectly from lua_pcall(). Sandboxed Lua code is run
 551+ * under lua_pcall() so can't cause a panic.
 552+ *
 553+ * Note that sandboxed Lua code may be executed in an unprotected environment
 554+ * if C code accesses a variable with a metamethod defined by the sandboxed
 555+ * code. For this reason, the "raw" functions such as lua_rawget() should be
 556+ * used where this is a possibility.
 557+ */
504558 static int luasandbox_panic(lua_State * L)
505559 {
506560 php_error_docref(NULL TSRMLS_CC, E_ERROR,
@@ -509,7 +563,11 @@
510564 }
511565 /* }}} */
512566
513 -/** {{{ luasandbox_state_from_zval */
 567+/** {{{ luasandbox_state_from_zval
 568+ *
 569+ * Get a lua state from a zval* containing a LuaSandbox object. If the zval*
 570+ * contains something else, bad things will happen.
 571+ */
514572 static lua_State * luasandbox_state_from_zval(zval * this_ptr TSRMLS_DC)
515573 {
516574 php_luasandbox_obj * intern = (php_luasandbox_obj*)
@@ -518,16 +576,25 @@
519577 }
520578 /* }}} */
521579
522 -/** {{{ luasandbox_load_helper */
 580+/** {{{ luasandbox_load_helper
 581+ *
 582+ * Common code for LuaSandbox::loadString() and LuaSandbox::loadBinary(). The
 583+ * "binary" parameter will be 1 for loadBinary() and 0 for loadString().
 584+ */
523585 static void luasandbox_load_helper(int binary, INTERNAL_FUNCTION_PARAMETERS)
524586 {
525587 char *code, *chunkName = NULL;
526588 int codeLength, chunkNameLength;
527589 int status;
528 - lua_State * L = luasandbox_state_from_zval(getThis() TSRMLS_CC);
 590+ lua_State * L;
529591 size_t index;
530592 php_luasandboxfunction_obj * func_obj;
531593 int have_mark;
 594+ php_luasandbox_obj * sandbox;
 595+
 596+ sandbox = (php_luasandbox_obj*)
 597+ zend_object_store_get_object(this_ptr TSRMLS_CC);
 598+ L = sandbox->state;
532599
533600 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
534601 &code, &codeLength, &chunkName, &chunkNameLength) == FAILURE) {
@@ -564,13 +631,12 @@
565632 lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks");
566633
567634 // Get the next free index
568 - index = lua_objlen(L, -1);
 635+ index = ++(sandbox->function_index);
569636 if (index >= INT_MAX) {
570637 php_error_docref(NULL TSRMLS_CC, E_WARNING,
571638 "too many chunks loaded already");
572639 RETURN_FALSE;
573640 }
574 - index++;
575641
576642 // Parse the string into a function on the stack
577643 status = luaL_loadbuffer(L, code, codeLength, chunkName);
@@ -594,7 +660,15 @@
595661 }
596662 /* }}} */
597663
598 -/** {{{ proto LuaSandboxFunction LuaSandbox::loadString(string code, string chunkName) */
 664+/** {{{ proto LuaSandboxFunction LuaSandbox::loadString(string code, string chunkName)
 665+ *
 666+ * Load a string into the LuaSandbox object. Returns a LuaSandboxFunction object
 667+ * which can be called or dumped.
 668+ *
 669+ * Note that global functions and variables defined in the chunk will not be
 670+ * present in the Lua state until the chunk is executed. Function definitions
 671+ * in Lua are a kind of executable statement.
 672+ */
599673 PHP_METHOD(LuaSandbox, loadString)
600674 {
601675 luasandbox_load_helper(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
@@ -602,7 +676,11 @@
603677
604678 /* }}} */
605679
606 -/** {{{ proto LuaSandboxFunction LuaSandbox::loadBinary(string bin, string chunkName) */
 680+/** {{{ proto LuaSandboxFunction LuaSandbox::loadBinary(string bin, string chunkName)
 681+ * Load a string containing a precompiled binary chunk from
 682+ * LuaSandboxFunction::dump() or the Lua compiler luac. Returns a
 683+ * LuaSandboxFunction object.
 684+ */
607685 PHP_METHOD(LuaSandbox, loadBinary)
608686 {
609687 luasandbox_load_helper(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
@@ -623,7 +701,14 @@
624702 }
625703 /* }}} */
626704
627 -/** {{{ proto void LuaSandbox::setMemoryLimit(int limit) */
 705+/** {{{ proto void LuaSandbox::setMemoryLimit(int limit)
 706+ *
 707+ * Set the memory limit for the Lua state. If the memory limit is exceeded,
 708+ * the allocator will return NULL. When running protected code, this will
 709+ * result in a LuaSandboxError exception being thrown. If this occurs in
 710+ * unprotected code, say due to loading too many functions with loadString(),
 711+ * a panic will be triggered, leading to a PHP fatal error.
 712+ */
628713 PHP_METHOD(LuaSandbox, setMemoryLimit)
629714 {
630715 long limit;
@@ -641,7 +726,23 @@
642727 /* }}} */
643728
644729
645 -/** {{{ proto void LuaSandbox::setCPULimit(mixed normal_limit, mixed emergency_limit = false) */
 730+/** {{{ proto void LuaSandbox::setCPULimit(mixed normal_limit, mixed emergency_limit = false)
 731+ *
 732+ * Set the limit of CPU time (user+system) for LuaSandboxFunction::call()
 733+ * calls. There are two time limits, which are both specified in seconds. Set
 734+ * a time limit to false to disable it.
 735+ *
 736+ * When the "normal" time limit expires, a flag will be set which causes
 737+ * a LuaSandboxError exception to be thrown when the currently-running Lua
 738+ * statement finishes.
 739+ *
 740+ * When the "emergency" time limit expires, execution is terminated immediately.
 741+ * If PHP code was running, this results in the current PHP request being in an
 742+ * undefined state, so a PHP fatal error is raised. If PHP code was not
 743+ * running, the Lua state is destroyed and then recreated with an empty state.
 744+ * Any LuaSandboxFunction objects which referred to the old state will stop
 745+ * working. A LuaSandboxEmergencyTimeout exception is thrown.
 746+ */
646747 PHP_METHOD(LuaSandbox, setCPULimit)
647748 {
648749 zval **zpp_normal = NULL, **zpp_emergency = NULL;
@@ -694,7 +795,10 @@
695796 }
696797 /* }}} */
697798
698 -/** {{{ luasandbox_set_timespec */
 799+/** {{{ luasandbox_set_timespec
 800+ * Initialise a timespec structure with the time in seconds given by the source
 801+ * argument.
 802+ */
699803 static void luasandbox_set_timespec(struct timespec * dest, double source)
700804 {
701805 double fractional, integral;
@@ -714,7 +818,20 @@
715819
716820 /* }}} */
717821
718 -/*** {{{ proto array LuaSandbox::callFunction(string name, ...)
 822+/** {{{ proto array LuaSandbox::callFunction(string name, ...)
 823+ *
 824+ * Call a function in the global variable with the given name. The name may
 825+ * contain "." characters, in which case the function is located via recursive
 826+ * table accesses, as if the name were a Lua expression.
 827+ *
 828+ * If the variable does not exist, or is not a function, false will be returned
 829+ * and a warning issued.
 830+ *
 831+ * Any arguments specified after the name will be passed through as arguments
 832+ * to the function.
 833+ *
 834+ * For more information about calling Lua functions and the return values, see
 835+ * LuaSandboxFunction::call().
719836 */
720837 PHP_METHOD(LuaSandbox, callFunction)
721838 {
@@ -751,6 +868,7 @@
752869 /* }}} */
753870
754871 /** {{{ luasandbox_function_init
 872+ *
755873 * Common initialisation for LuaSandboxFunction methods. Initialise the
756874 * function, state and sandbox pointers, and push the function to the stack.
757875 */
@@ -779,6 +897,19 @@
780898 /* }}} */
781899
782900 /** {{{ proto array LuaSandboxFunction::call(...)
 901+ *
 902+ * Call a LuaSandboxFunction. The arguments to this function are passed through
 903+ * to Lua.
 904+ *
 905+ * Errors considered to be the fault of the PHP code will result in the
 906+ * function returning false and E_WARNING being raised, for example, a
 907+ * resource type being used as an argument. Lua errors will result in a
 908+ * LuaSandboxError exception being thrown.
 909+ *
 910+ * Lua functions inherently return an list of results. So on success, this
 911+ * function returns an array containing all of the values returned by Lua,
 912+ * with integer keys starting from zero. Lua may return no results, in which
 913+ * case an empty array is returned.
783914 */
784915 PHP_METHOD(LuaSandboxFunction, call)
785916 {
@@ -812,6 +943,7 @@
813944 /** }}} */
814945
815946 /** {{{ luasandbox_call_helper
 947+ *
816948 * Call the function at the top of the stack and then pop it. Set return_value
817949 * to an array containing all the results.
818950 */
@@ -866,7 +998,7 @@
867999 lua_close(L);
8681000 L = sandbox->state = luasandbox_newstate(sandbox);
8691001 sandbox->emergency_timed_out = 0;
870 - zend_throw_exception(luasandboxerror_ce,
 1002+ zend_throw_exception(luasandboxemergencytimeout_ce,
8711003 "The maximum execution time was exceeded "
8721004 "and the current Lua statement failed to return, leading to "
8731005 "destruction of the Lua state", LUA_ERRRUN);
@@ -898,6 +1030,7 @@
8991031 /* }}} */
9001032
9011033 /** {{{ luasandbox_find_field
 1034+ *
9021035 * Given a string in the format "a.b.c.d" find the relevant variable in the
9031036 * table at the given stack position. If it is found, 1 is returned
9041037 * and the variable will be pushed to the stack. If not, 0 is returned
@@ -944,6 +1077,7 @@
9451078 /* }}} */
9461079
9471080 /** {{{ luasandbox_push_zval
 1081+ *
9481082 * Convert a zval to an appropriate Lua type and push the resulting value on to
9491083 * the stack.
9501084 */
@@ -986,6 +1120,7 @@
9871121 /* }}} */
9881122
9891123 /** {{{ luasandbox_push_zval_userdata
 1124+ *
9901125 * Push a full userdata on to the stack, which stores a zval* in its block.
9911126 * Increment its reference count and set its metatable so that it will be freed
9921127 * at the appropriate time.
@@ -1002,7 +1137,11 @@
10031138 }
10041139 /* }}} */
10051140
1006 -/** {{{ luasandbox_push_hashtable */
 1141+/** {{{ luasandbox_push_hashtable
 1142+ *
 1143+ * Helper function for luasandbox_push_zval. Create a new table on the top of
 1144+ * the stack and add the zvals in the HashTable to it.
 1145+ */
10071146 static int luasandbox_push_hashtable(lua_State * L, HashTable * ht)
10081147 {
10091148 Bucket * p;
@@ -1143,7 +1282,8 @@
11441283 }
11451284 /* }}} */
11461285
1147 -/** {{{ luasandbox_lua_to_array
 1286+/** {{{ luasandbox_lua_to_array
 1287+ *
11481288 * Append the elements of the table in the specified index to the given HashTable.
11491289 */
11501290 static void luasandbox_lua_to_array(HashTable *ht, lua_State *L, int index,
@@ -1174,6 +1314,7 @@
11751315 /* }}} */
11761316
11771317 /** {{{ luasandbox_get_php_obj
 1318+ *
11781319 * Get the object data for a lua state.
11791320 */
11801321 static php_luasandbox_obj * luasandbox_get_php_obj(lua_State * L)
@@ -1187,9 +1328,24 @@
11881329 }
11891330 /* }}} */
11901331
1191 -/** {{{ proto void LuaSandbox::register(string libname, array functions)
 1332+/** {{{ proto void LuaSandbox::registerLibrary(string libname, array functions)
 1333+ *
 1334+ * Register a set of PHP functions as a Lua library, so that Lua can call the
 1335+ * relevant PHP code.
 1336+ *
 1337+ * The first parameter is the name of the library. In the Lua state, the global
 1338+ * variable of this name will be set to the table of functions.
 1339+ *
 1340+ * The second parameter is an array, where each key is a function name, and
 1341+ * each value is a corresponding PHP callback.
 1342+ *
 1343+ * Both Lua and PHP allow functions to be called with any number of arguments.
 1344+ * The parameters to the Lua function will be passed through to the PHP. A
 1345+ * single value will always be returned to Lua, which is the return value from
 1346+ * the PHP function. If the PHP function does not return any value, Lua will
 1347+ * see a return value of nil.
11921348 */
1193 -PHP_METHOD(LuaSandbox, register)
 1349+PHP_METHOD(LuaSandbox, registerLibrary)
11941350 {
11951351 lua_State * L = luasandbox_state_from_zval(getThis() TSRMLS_CC);
11961352 char * libname = NULL;
@@ -1245,6 +1401,9 @@
12461402 /* }}} */
12471403
12481404 /** {{{ luasandbox_call_php
 1405+ *
 1406+ * The Lua callback for calling PHP functions. See the doc comment on
 1407+ * LuaSandbox::registerLibrary() for information about calling conventions.
12491408 */
12501409 static int luasandbox_call_php(lua_State * L)
12511410 {
@@ -1316,7 +1475,12 @@
13171476 }
13181477 /* }}} */
13191478
1320 -/** {{{ string LuaSandboxFunction::dump() */
 1479+/** {{{ string LuaSandboxFunction::dump()
 1480+ *
 1481+ * Dump the function as a precompiled binary blob. Returns a string which may
 1482+ * later be loaded by LuaSandbox::loadBinary(), in the same or a different
 1483+ * sandbox object.
 1484+ */
13211485 PHP_METHOD(LuaSandboxFunction, dump)
13221486 {
13231487 php_luasandboxfunction_obj * func;
@@ -1345,7 +1509,10 @@
13461510 }
13471511 /* }}} */
13481512
1349 -/** {{{ luasandbox_dump_writer */
 1513+/** {{{ luasandbox_dump_writer
 1514+ *
 1515+ * Writer function for LuaSandboxFunction::dump().
 1516+ */
13501517 static int luasandbox_dump_writer(lua_State * L, const void * p, size_t sz, void * ud)
13511518 {
13521519 smart_str * buf = (smart_str *)ud;
@@ -1355,6 +1522,7 @@
13561523 /* }}} */
13571524
13581525 /** {{{ luasandbox_base_tostring
 1526+ *
13591527 * This is identical to luaB_tostring except that it does not call lua_topointer().
13601528 */
13611529 static int luasandbox_base_tostring(lua_State * L)
Index: trunk/php/luasandbox/php_luasandbox.h
@@ -31,7 +31,7 @@
3232 PHP_METHOD(LuaSandbox, setMemoryLimit);
3333 PHP_METHOD(LuaSandbox, setCPULimit);
3434 PHP_METHOD(LuaSandbox, callFunction);
35 -PHP_METHOD(LuaSandbox, register);
 35+PHP_METHOD(LuaSandbox, registerLibrary);
3636
3737 PHP_METHOD(LuaSandboxFunction, call);
3838 PHP_METHOD(LuaSandboxFunction, dump);
@@ -59,6 +59,7 @@
6060 int is_cpu_limited;
6161 struct timespec cpu_normal_limit;
6262 struct timespec cpu_emergency_limit;
 63+ int function_index;
6364 };
6465 typedef struct _php_luasandbox_obj php_luasandbox_obj;
6566

Status & tagging log