What is the correct way to provoke a timeout in Openresty?

554 views
Skip to first unread message

kik...@gmail.com

unread,
May 5, 2014, 2:10:32 PM5/5/14
to openre...@googlegroups.com
Hi there,

I have a web application where the end user is able to input certain Lua code to be executed.

Code coming from users is heavily sandboxed - they can't touch anything dangerous. However, they can halt the worker they are in if they try to execute an infinite loop (or a similarly lengthy operation):

while true do end

The sandbox solution I am using comes with a facility for that, but it's based in Lua's debug.sethook, which luajit deactivates by default in loops. So I need to find another solution.

I have tried to use threads to provoke a timeout, but had no luck. My code does the equivalent to this:


local timeout_function = function()
  ngx
.sleep(4)
 
return "TIMED OUT"
end


local execute_sandboxed_code = function()
 
... (Execute code coming from the user here)
end


local timeout_thread = ngx.thread.spawn(timeout_function)
local execute_thread = ngx.thread.spawn(execute_sandboxed_code)


local ok, res = ngx.wait(timeout_thread, execute_thread)
if ok then
 
if res == "TIMED OUT" then
    ngx
.status = 500
    ngx
.print("Sandboxed code took too long")
    ngx
.eof()
 
end
else
  error
(res)
end

I have tried this with an infinite loop as the input, and tried adding some prints.

It seems that the timeout_function, once it reaches the ngx.sleep, never wakes up.

What am I missing? Is there any other way around this?

Yichun Zhang (agentzh)

unread,
May 5, 2014, 2:50:54 PM5/5/14
to openresty-en
Hello!

On Mon, May 5, 2014 at 11:10 AM, kikito wrote:
> I have a web application where the end user is able to input certain Lua
> code to be executed.
>
> Code coming from users is heavily sandboxed - they can't touch anything
> dangerous. However, they can halt the worker they are in if they try to
> execute an infinite loop (or a similarly lengthy operation):
>
> while true do end
>

The ngx_lua module has not yet provided a built-in mechanism for
automatically aborting such infinite loop with a timeout or some other
threshold. Along this path, we need to use a custom OS thread to call
lua_sethook() to add a hook with a count of 1 to abort the too hot Lua
thread (in the main OS thread of nginx) and abandon it. And we need to
enable -DLUAJIT_ENABLE_CHECKHOOK for the LuaJIT build too. See Mike
Pall's explanation here:

http://www.freelists.org/post/luajit/Efficient-query-timeouts-in-LuaJIT,1

Just as Mike mentioned in the mail above, a much more efficient (and
simpler) way is to use a higher level DSL for your user input rather
than direct Lua code (or you can parse the Lua code yourself) and
check the threshold in the resulting Lua code to be run directly by
the LuaJIT VM. The lua_sethook() thing can only serve as the last
resort.

Anyway, you're welcome to submit patches for the lua_sethook() thing
if you decide to go that path.

Regards,
-agentzh

kik...@gmail.com

unread,
May 5, 2014, 4:08:31 PM5/5/14
to openre...@googlegroups.com
Hi there,

Thanks for the quick response!

The ngx_lua module has not yet provided a built-in mechanism for
automatically aborting such infinite loop with a timeout or some other
threshold.

Is there any other option? Maybe outside Lua? Does raw nginx provide a "script timeout" facility that I might have missed?

If the timeout is reached, I just really want to return 500 and an error message - I don't care if it's openresty or nginx who delivers it.
 
The lua_sethook() thing can only serve as the last
resort.

Anyway, you're welcome to submit patches for the lua_sethook() thing
if you decide to go that path.

I am afraid that falls totally out of my area of expertise. If I did a patch for that I would probably do more bad than good.

But I will keep speaking about it on my talks. (So far your project has appeared in the last two). That's all I can do to contribute to the project for now, I am afraid.

Thanks a lot for your excellent work, and again for your quick response.

Regards,

Enrique

Yichun Zhang (agentzh)

unread,
May 5, 2014, 4:20:25 PM5/5/14
to openresty-en
Hello!

On Mon, May 5, 2014 at 1:08 PM, kikito wrote:
>> The ngx_lua module has not yet provided a built-in mechanism for
>> automatically aborting such infinite loop with a timeout or some other
>> threshold.
>
> Is there any other option? Maybe outside Lua? Does raw nginx provide a
> "script timeout" facility that I might have missed?
>

Nope.

> If the timeout is reached, I just really want to return 500 and an error
> message - I don't care if it's openresty or nginx who delivers it.
>

Yes, that's also what I was thinking about.

> I am afraid that falls totally out of my area of expertise. If I did a patch
> for that I would probably do more bad than good.
>
> But I will keep speaking about it on my talks. (So far your project has
> appeared in the last two). That's all I can do to contribute to the project
> for now, I am afraid.
>

Thank you all the same :)

Regards,
-agentzh
Reply all
Reply to author
Forward
0 new messages