static void luasandbox_timer_handle_signal(int signo, siginfo_t * info, void * context) { luasandbox_timer_callback_data * data; if (signo != LUASANDBOX_SIGNAL || info->si_code != SI_TIMER || !info->si_value.sival_ptr) { return; } data = (luasandbox_timer_callback_data*)info->si_value.sival_ptr; lua_State * L = data->sandbox->state; if (data->type == LUASANDBOX_TIMER_EMERGENCY) { sigset_t set; sigemptyset(&set); sigprocmask(SIG_SETMASK, &set, NULL); data->sandbox->timed_out = 1; data->sandbox->emergency_timed_out = 1; if (data->sandbox->in_php) { // The whole PHP request context is dirty now. We need to kill it, // like what happens if there is a max_execution_time timeout. zend_error(E_ERROR, "The maximum execution time for a Lua sandbox script " "was exceeded and a PHP callback failed to return"); } else { // The Lua state is dirty now and can't be used again. lua_pushstring(L, "emergency timeout"); luasandbox_wrap_fatal(L); lua_error(L); } } else { luasandbox_timer_set * lts = &data->sandbox->timer; if (luasandbox_timer_is_paused(lts)) { // The timer is paused. luasandbox_timer_unpause will reschedule when unpaused. clock_gettime(LUASANDBOX_CLOCK_ID, <s->normal_expired_at); } else if (!luasandbox_timer_is_zero(<s->pause_delta)) { // The timer is not paused, but we have a pause delta. Reschedule. luasandbox_timer_subtract(<s->usage, <s->pause_delta); lts->normal_remaining = lts->pause_delta; luasandbox_timer_zero(<s->pause_delta); luasandbox_timer_set_one_time(<s->normal_timer, <s->normal_remaining); } else { // Set a hook which will terminate the script execution in a graceful way data->sandbox->timed_out = 1; lua_sethook(L, luasandbox_timer_timeout_hook, LUA_MASKCOUNT | LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 1); } } }
void luasandbox_timer_set_limit(luasandbox_timer_set * lts, struct timespec * timeout) { int was_running = 0; int was_paused = luasandbox_timer_is_paused(lts); if (lts->is_running) { was_running = 1; luasandbox_timer_stop(lts); } lts->limiter_remaining = lts->limiter_limit = *timeout; luasandbox_timer_zero(<s->limiter_expired_at); if (was_running) { luasandbox_timer_start(lts); } if (was_paused) { luasandbox_timer_pause(lts); } }
void luasandbox_timer_set_limits(luasandbox_timer_set * lts, struct timespec * normal_timeout, struct timespec * emergency_timeout) { int was_running = 0; int was_paused = luasandbox_timer_is_paused(lts); if (lts->is_running) { was_running = 1; luasandbox_timer_stop(lts); } lts->normal_remaining = lts->normal_limit = *normal_timeout; lts->emergency_remaining = lts->emergency_limit = *emergency_timeout; luasandbox_timer_zero(<s->normal_expired_at); if (was_running) { luasandbox_timer_start(lts); } if (was_paused) { luasandbox_timer_pause(lts); } }
static void luasandbox_timer_handle_limiter(luasandbox_timer * lt) { lua_State * L = lt->sandbox->state; luasandbox_timer_set * lts = <->sandbox->timer; if (luasandbox_timer_is_paused(lts)) { // The timer is paused. luasandbox_timer_unpause will reschedule when unpaused. // Note that we need to use lt->clock_id here since CLOCK_THREAD_CPUTIME_ID // would get the time usage of the timer thread rather than the Lua thread. clock_gettime(lt->clock_id, <s->limiter_expired_at); } else if (!luasandbox_timer_is_zero(<s->pause_delta)) { // The timer is not paused, but we have a pause delta. Reschedule. luasandbox_timer_subtract(<s->usage, <s->pause_delta); lts->limiter_remaining = lts->pause_delta; luasandbox_timer_zero(<s->pause_delta); luasandbox_timer_set_one_time(lts->limiter_timer, <s->limiter_remaining); } else { // Set a hook which will terminate the script execution in a graceful way lt->sandbox->timed_out = 1; lua_sethook(L, luasandbox_timer_timeout_hook, LUA_MASKCOUNT | LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 1); } }