r95459 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r95458‎ | r95459 | r95460 >
Date:05:39, 25 August 2011
Author:tstarling
Status:deferred
Tags:
Comment:
* Fixed memory limits. Since I'm harping on about how awesome they are to the WMF developers, I figured I'd better make them actually work. Memory limiting for LuaJIT in 64-bit mode is simple enough, but unfortunately it's not possible to use emalloc() in that case.
* Actually followed the instructions in the manual regarding luaopen_base() etc., and called them via lua_call().
* Added method LuaSandbox::getMemoryUsage()
* When setting the timeout hook, set the number of lines to 1 instead of 0, since 0 is counted as "never".
Modified paths:
  • /trunk/php/luasandbox/luasandbox.c (modified) (history)
  • /trunk/php/luasandbox/php_luasandbox.h (modified) (history)
  • /trunk/php/luasandbox/timer.c (modified) (history)

Diff [purge]

Index: trunk/php/luasandbox/php_luasandbox.h
@@ -29,6 +29,7 @@
3030 PHP_METHOD(LuaSandbox, loadString);
3131 PHP_METHOD(LuaSandbox, loadBinary);
3232 PHP_METHOD(LuaSandbox, setMemoryLimit);
 33+PHP_METHOD(LuaSandbox, getMemoryUsage);
3334 PHP_METHOD(LuaSandbox, setCPULimit);
3435 PHP_METHOD(LuaSandbox, callFunction);
3536 PHP_METHOD(LuaSandbox, registerLibrary);
@@ -53,6 +54,8 @@
5455 lua_State * state;
5556 size_t memory_limit;
5657 size_t memory_usage;
 58+ lua_Alloc old_alloc;
 59+ void * old_alloc_ud;
5760 int in_php;
5861 volatile int timed_out;
5962 volatile int emergency_timed_out;
Index: trunk/php/luasandbox/luasandbox.c
@@ -19,6 +19,10 @@
2020 #include "luasandbox_timer.h"
2121 #include "ext/standard/php_smart_str.h"
2222
 23+#if defined(LUA_JITLIBNAME) && (SSIZE_MAX >> 32) > 0
 24+#define LUASANDBOX_LJ_64
 25+#endif
 26+
2327 static zend_object_value luasandbox_new(zend_class_entry *ce TSRMLS_DC);
2428 static lua_State * luasandbox_newstate(php_luasandbox_obj * intern);
2529 static void luasandbox_free_storage(void *object TSRMLS_DC);
@@ -26,7 +30,10 @@
2731 static void luasandboxfunction_free_storage(void *object TSRMLS_DC);
2832 static void luasandboxfunction_destroy(void *object, zend_object_handle handle TSRMLS_DC);
2933 static int luasandbox_free_zval_userdata(lua_State * L);
30 -static void *luasandbox_alloc(void *ud, void *ptr, size_t osize, size_t nsize);
 34+static inline int luasandbox_update_memory_accounting(php_luasandbox_obj* obj,
 35+ size_t osize, size_t nsize);
 36+static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize);
 37+static void *luasandbox_passthru_alloc(void *ud, void *ptr, size_t osize, size_t nsize);
3138 static int luasandbox_panic(lua_State * L);
3239 static lua_State * luasandbox_state_from_zval(zval * this_ptr TSRMLS_DC);
3340 static void luasandbox_load_helper(int binary, INTERNAL_FUNCTION_PARAMETERS);
@@ -120,6 +127,9 @@
121128 ZEND_ARG_INFO(0, limit)
122129 ZEND_END_ARG_INFO()
123130
 131+ZEND_BEGIN_ARG_INFO(arginfo_luasandbox_getMemoryUsage, 0)
 132+ZEND_END_ARG_INFO()
 133+
124134 ZEND_BEGIN_ARG_INFO(arginfo_luasandbox_setCPULimit, 0)
125135 ZEND_ARG_INFO(0, normal_limit)
126136 ZEND_ARG_INFO(0, emergency_limit)
@@ -153,6 +163,7 @@
154164 PHP_ME(LuaSandbox, loadString, arginfo_luasandbox_loadString, 0)
155165 PHP_ME(LuaSandbox, loadBinary, arginfo_luasandbox_loadBinary, 0)
156166 PHP_ME(LuaSandbox, setMemoryLimit, arginfo_luasandbox_setMemoryLimit, 0)
 167+ PHP_ME(LuaSandbox, getMemoryUsage, arginfo_luasandbox_getMemoryUsage, 0)
157168 PHP_ME(LuaSandbox, setCPULimit, arginfo_luasandbox_setCPULimit, 0)
158169 PHP_ME(LuaSandbox, callFunction, arginfo_luasandbox_callFunction, 0)
159170 PHP_ME(LuaSandbox, registerLibrary, arginfo_luasandbox_registerLibrary, 0)
@@ -319,7 +330,8 @@
320331 intern = emalloc(sizeof(php_luasandbox_obj));
321332 memset(intern, 0, sizeof(php_luasandbox_obj));
322333 zend_object_std_init(&intern->std, ce TSRMLS_CC);
323 -
 334+ intern->memory_limit = (size_t)-1;
 335+
324336 // Initialise the Lua state
325337 intern->state = luasandbox_newstate(intern);
326338
@@ -343,14 +355,30 @@
344356 {
345357 lua_State * L;
346358
347 - L = lua_newstate(luasandbox_alloc, intern);
 359+#ifdef LUASANDBOX_LJ_64
 360+ // The 64-bit version of LuaJIT needs to use its own allocator
 361+ L = luaL_newstate();
 362+ if (L == NULL) {
 363+ php_error_docref(NULL TSRMLS_CC, E_ERROR,
 364+ "Attempt to allocate a new Lua state failed");
 365+ }
 366+ intern->old_alloc = lua_getallocf(L, &intern->old_alloc_ud);
 367+ lua_setallocf(L, luasandbox_passthru_alloc, intern);
 368+#else
 369+ L = lua_newstate(luasandbox_php_alloc, intern);
 370+#endif
 371+
348372 lua_atpanic(L, luasandbox_panic);
349373
350374 // Load some relatively safe standard libraries
351 - luaopen_base(L);
352 - luaopen_string(L);
353 - luaopen_table(L);
354 - luaopen_math(L);
 375+ lua_pushcfunction(L, luaopen_base);
 376+ lua_call(L, 0, 0);
 377+ lua_pushcfunction(L, luaopen_string);
 378+ lua_call(L, 0, 0);
 379+ lua_pushcfunction(L, luaopen_table);
 380+ lua_call(L, 0, 0);
 381+ lua_pushcfunction(L, luaopen_math);
 382+ lua_call(L, 0, 0);
355383
356384 // Remove any globals that aren't in a whitelist. This is mostly to remove
357385 // unsafe functions from the base library.
@@ -408,6 +436,15 @@
409437 static void luasandbox_free_storage(void *object TSRMLS_DC)
410438 {
411439 php_luasandbox_obj * intern = (php_luasandbox_obj*)object;
 440+
 441+ // In 64-bit LuaJIT mode, restore the old allocator before calling
 442+ // lua_close() because lua_close() actually checks that the value of the
 443+ // function pointer is unchanged before destroying the underlying
 444+ // allocator. If the allocator has been changed, the mmap is not freed.
 445+#ifdef LUASANDBOX_LJ_64
 446+ lua_setallocf(intern->state, intern->old_alloc, intern->old_alloc_ud);
 447+#endif
 448+
412449 lua_close(intern->state);
413450 intern->state = NULL;
414451 zend_object_std_dtor(&intern->std);
@@ -501,28 +538,22 @@
502539 }
503540 /* }}} */
504541
505 -/** {{{ luasandbox_alloc
 542+/** {{{ luasandbox_php_alloc
506543 *
507544 * The Lua allocator function. Use PHP's request-local allocator as a backend.
508545 * Account for memory usage and deny the allocation request if the amount
509546 * allocated is above the user-specified limit.
510547 */
511 -static void *luasandbox_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
 548+static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
512549 {
513550 php_luasandbox_obj * obj = (php_luasandbox_obj*)ud;
514551 void * nptr;
515552 obj->in_php = 1;
516 -
517 - // Update memory usage accounting
518 - if (obj->memory_usage + nsize < obj->memory_usage) {
519 - // Overflow
520 - // No PHP error because it's plausible that untrusted scripts could do this.
 553+ if (!luasandbox_update_memory_accounting(obj, osize, nsize)) {
521554 obj->in_php = 0;
522555 return NULL;
523556 }
524557
525 - obj->memory_usage += nsize - osize;
526 -
527558 if (nsize == 0) {
528559 if (ptr) {
529560 efree(ptr);
@@ -538,6 +569,48 @@
539570 }
540571 /* }}} */
541572
 573+/** {{{ luasandbox_passthru_alloc
 574+ *
 575+ * A Lua allocator function for use with LuaJIT on a 64-bit platform. Pass
 576+ * allocation requests through to the standard allocator, which is customised
 577+ * on this platform to always return memory from the lower 2GB of address
 578+ * space.
 579+ */
 580+static void *luasandbox_passthru_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
 581+{
 582+ php_luasandbox_obj * obj = (php_luasandbox_obj*)ud;
 583+ if (!luasandbox_update_memory_accounting(obj, osize, nsize)) {
 584+ return NULL;
 585+ }
 586+ return obj->old_alloc(obj->old_alloc_ud, ptr, osize, nsize);
 587+}
 588+/* }}} */
 589+
 590+/** {{{ luasandbox_update_memory_accounting
 591+ *
 592+ * Update memory usage statistics for the given memory allocation request.
 593+ * Returns 1 if the allocation should be allowed, 0 if it should fail.
 594+ */
 595+static inline int luasandbox_update_memory_accounting(php_luasandbox_obj* obj,
 596+ size_t osize, size_t nsize)
 597+{
 598+ if (nsize > obj->memory_limit
 599+ || obj->memory_usage > obj->memory_limit - nsize)
 600+ {
 601+ // Memory limit exceeded
 602+ return 0;
 603+ }
 604+
 605+ if (osize > nsize && obj->memory_usage + nsize < osize) {
 606+ // Negative memory usage -- do not update
 607+ return 1;
 608+ }
 609+
 610+ obj->memory_usage += nsize - osize;
 611+ return 1;
 612+}
 613+/* }}} */
 614+
542615 /** {{{ luasandbox_panic
543616 *
544617 * The Lua panic function. It is necessary to raise an E_ERROR, and thus do a
@@ -818,6 +891,20 @@
819892
820893 /* }}} */
821894
 895+/** {{{ LuaSandbox::getMemoryUsage */
 896+PHP_METHOD(LuaSandbox, getMemoryUsage)
 897+{
 898+ php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
 899+ zend_object_store_get_object(getThis() TSRMLS_CC);
 900+
 901+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
 902+ RETURN_FALSE;
 903+ }
 904+
 905+ RETURN_LONG(sandbox->memory_usage);
 906+}
 907+/* }}} */
 908+
822909 /** {{{ proto array LuaSandbox::callFunction(string name, ...)
823910 *
824911 * Call a function in the global variable with the given name. The name may
Index: trunk/php/luasandbox/timer.c
@@ -73,7 +73,7 @@
7474 } else {
7575 // Set a hook which will terminate the script execution in a graceful way
7676 lua_sethook(data->sandbox->state, luasandbox_timer_timeout_hook,
77 - LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 0);
 77+ LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 1);
7878 }
7979 }
8080

Status & tagging log