Embedded Lua - script rogue timeout (e.g. infinite loop) - example of any?

I have included Lua in a C ++ application. I need to be able to kill rogue (i.e., poorly written scripts) from hogging resources.

I know that I will not be able to service conditions of EVERY type that make the script work indefinitely, so for now I only look at the straight-line side of Lua (for example, problems with the script).

I also know that this question is asked (in various guises) here on SO. Probably the reason that is constantly being reviewed is that no one has yet provided a few lines of code to show how the timeout (for simple cases like the one described above) can actually be implemented in the working code - instead of to talk in general terms about how this can be implemented.

If someone really implemented this type of functionality in C ++ with the built-in Lua application, I (like many other people, I'm sure) will be very grateful for a small fragment that shows:

  • How to set timeout (on C ++ side) before running Lua script
  • How to raise an event / timeout error (C ++ / Lua?)
  • How to handle event / error exception (C ++ side)

Such a fragment (even pseudo-code) would be VERY, VERY useful

+3
source share
3 answers

You need to address this with a combination of methods. First, you need to create a suitable sandbox for untrusted scripts, with an environment that provides only those global variables and functions that are safe and necessary. Secondly, you need to provide restrictions on the use of memory and processor. Third, you need to explicitly refuse to download the precompiled bytecode from untrusted sources.

The first point is simple. There is quite a bit of discussion about the Lua sandbox, available on the Lua user wiki, on the mailing list, and here in SO. You almost certainly already do this part if you know that some scripts are more reliable than others.

The second question is the question you ask. I will come back to this in a moment.

The third issue was discussed on the mailing list, but perhaps it was not clearly spelled out in other media. It turned out that in the Lua kernel there are a number of vulnerabilities that are difficult or impossible to address, but which depend on the β€œwrong” bytecode to implement. That is, they cannot be used from Lua source code, only from a pre-compiled and carefully corrected byte code. Directly write a bootloader that generally refuses to download any binary bytecode.

Given these points, this raises the question of a denial of service attack, either through CPU consumption, memory consumption, or both. Firstly, the bad news. There are no perfect methods to prevent this. However, one of the most reliable approaches is to interpret Lua in a separate process and use the security features and platform quotas to limit the capabilities of this process. In the worst case, the destruction process can be killed without prejudice to the main application. This technique is used in recent versions of Firefox to contain the side effects of bugs in plugins, so it is not necessarily as crazy as it seems.

One interesting complete example is the Lua Live Demo . This is a web page where you can enter a sample Lua code, execute it on a server and view the results. Because scripts can be entered anonymously from anywhere, they are clearly unreliable. This web application looks as secure as it can be suggested. Its source kit is available for download from one of the authors of Lua.

+8
source

The snippet is not the proper use of terminology to implement this function, and therefore you have not seen it. You can use debug hooks to provide callbacks during Lua code execution. However, interrupting this process after a timeout is non-trivial and depends on your specific architecture.

You might consider using longjmp in the jump buffer set immediately before lua_call or lua_pcall after you catch the timeout in luaHook . Then close this Lua context and handle the exception. The timeout can be implemented in many ways, and you probably already have something in mind that is used elsewhere in your project.

The best way to accomplish this task is to run the interpreter in a separate process. Then use the provided operating systems to manage the child process. For more on this approach, see RBerteig's excellent answer .

+1
source

Very naive and simple, but the all-lua method is

-- Limit may be in the millions range depending on your needs setfenv(code,sandbox) pcall (function() debug.sethook( function() error ("Timeout!") end,"", limit) code() debug.sethook() end); 

I expect that you can achieve the same through API C.

However , there are many problems with this method. Set the limit too low and it cannot do its job. Too tall and not very effective. (Can the chunk be restarted?) Allowing the code to call a function that is locked for a considerable time, and above it makes no sense. Let him make any pcall, and he can trap errors by himself. And whatever the other problems that I haven't thought about yet. Here, I also ignore warnings against using the debug library for anything (other than debugging).

So, if you want it to be reliable, you probably should go with an RB solution.

I expect it to work well against random endless loops, one that novice lua programmers love so much with: P

For excessive memory usage, you can do the same with a function that checks for an increase in collectgarbage ("count") at much shorter intervals; You will have to combine them to get both.

+1
source

Source: https://habr.com/ru/post/1489988/


All Articles