0

I'm writing a game in Rust where each player can submit some python scripts to the server in order to automate various tasks in the game. I plan on using pyo3 to run the python from rust.

However, I can see an issue arising if a player submits a script like this:

def on_event(e):
    while True:
        pass

Now when the server calls the function (using something like PyAny::call1()) the thread will hang as it reaches the infinite loop.

My first thought was to have pyo3 execute the python one statement at a time, therefore being able to exit if the script been running for over a certain threshold, but I don't think pyo3 supports this.

My next idea was to give each player their own thread to run their own scripts on, that way if one of their scripts got stuck it only affected their gameplay. However, I still have the issue of not being able to kill a thread when it gets stuck in an infinite loop - if a lot of players submitted scripts that just looped, lots of threads would start using a lot of CPU time.

All I need is way to execute python scripts in a way such that if one of them does loop, it does not affect the server's performance at all.

Thanks :)

  • 1
    Beware that letting users run untrusted Python code on a server can be much worse than just letting the server hang: there would typically be no restrictions on what code could be run, so a user could easily do more malicious things, for example modifying the server files or installing malware or cryptominer software on your server. – Frxstrem Nov 28 '21 at 14:00
  • The python code won't have access to any of the standard python library functions or modules - so I would assume that means an attack would be basically impossible. Correct me if I'm wrong – LightningdeGolem Nov 28 '21 at 14:53
  • I personally wouldn't trust that that is sufficient. For example, a quick Google search leads me to [this page](https://book.hacktricks.xyz/misc/basic-python/bypass-python-sandboxes) full of tricks to work around such restrictions. Running untrusted user code safely is generally a _very hard_ problem. – Frxstrem Nov 28 '21 at 15:58

1 Answers1

0

One solution is to restrict the time that you give each user script to run.

You can do it via PyThreadState_SetAsyncExc, see here for some code. It uses C calls of the interpreter, which you probably can access in Rust (with PyO3 FFI magic).

Another way would be to do it on the OS level: if you spawn a process for the user script, and then kill it when it runs for too long. This might be more secure if you limit what a process can access (with some OS calls), but requires some boilerplate to communicate between the host.

battlmonstr
  • 5,841
  • 1
  • 23
  • 33