0

Running a script with exec, how does one "backup" python process global state in its entirety and restores it afterwards?

code example:

import os
print(os.getcwd())
a = 8
print(a)
exec_scope = {}
exec("""
import os
os.chdir('../new place')
a = 9
print(a)
""", exec_scope)
print(os.getcwd())
print(a)

output:

C:\original place
8
9
C:\new place
8

The goal is to exec non-malicious code without having any global side-effect by backing up the current state and undoing any changes that may occur legitimately during the exec of the external (but safe) script.

This question was changes because the original wording would be interpreted that there is a need to protect against malicious code and that is not the focus. The assumption is that the external code is completely safe and holds not ill intentions but may affect the global state of the process for legitimate reasons and this effect was decided is undesirable.

So the goal of the question is to find the easiest/fastest/simplest way to undo any changes to the global state that can be undone.

AturSams
  • 7,568
  • 18
  • 64
  • 98
  • `eval` and `exec` are not safe, and cannot be made so in an obvious way https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html – oskros Aug 02 '22 at 11:23
  • Changed the question, the goal is not safety and simply keeping the state of the main program in memory the same way global variables remain the same. – AturSams Aug 02 '22 at 11:27
  • does this help? https://stackoverflow.com/questions/3068139/how-can-i-sandbox-python-in-pure-python – oskros Aug 02 '22 at 11:30
  • I was hoping for a simplistic/watered down/specific version of this huge hard to understand technique: https://stackoverflow.com/questions/64068369/programmatically-execute-a-python-file-from-within-python-in-a-fresh-looking-pyt – AturSams Aug 02 '22 at 11:38

1 Answers1

2

The goal is to safely exec

Yeah, no, that's not going to happen.

You could spawn (or fork()) a subprocess that runs the exec()'d code, but that only isolates you from some state changes, not the code going rogue and e.g. destroying your file system.

On that note, you can't use exec() safely on any arbitrary code; the best you could do is pre-parse the code to see if there are "unsafe" constructs in there, and either deny running them or get rid of them altogether (and of course hope that you've thought of everything).

AKX
  • 152,115
  • 15
  • 115
  • 172
  • Hi, thanks for the answer! Because of the focus on safety, I altered the question slightly to move the focus to memory/global state. – AturSams Aug 02 '22 at 11:28
  • Again, not 100% safely possible: `(3).__class__.__bases__[0].__subclasses__()[-15].__init__.__globals__['__builtins__']['__import__']("gc").get_objects()` (`-15` needs to change depending on global state) and you have access to _all_ of the globals of the interpreter. – AKX Aug 02 '22 at 11:57
  • yes, again but I changed and focused the question, assuming the code is 100% not malicious and the purpose is to simply make sure no changes to the global state remain after it is ran? – AturSams Aug 03 '22 at 12:44
  • Hi, I reworded the question again to take responsibility and clear up the misunderstanding regarding its purpose. – AturSams Aug 03 '22 at 12:57
  • So what _is_ the code supposed to do? Do you need some output from it? I mean, if it's not supposed to have any side effects, or change state, you might as well not run it at all. – AKX Aug 03 '22 at 13:00
  • The code creates some objects inside exec's dictionary. In the code example that dictionary is called exec_scope and it will contain a=9 in this case but useful objects in the real run – AturSams Aug 04 '22 at 08:56
  • In that case, you can run the code in a subprocess (using e.g. `multiprocessing.Process`) and send the serialized `exec_scope` back to the parent process. – AKX Aug 04 '22 at 09:01
  • That sounds like an answer that would work! Thanks! A subprocess does not ... affect any global settings such as cwd? – AturSams Aug 04 '22 at 09:12
  • 1
    cwd is process-wide, and it's a separate process, so that would not affect the parent process. – AKX Aug 04 '22 at 09:16
  • So can you share this as an answer to the now modified question and I'll select it cause it appears to be exactly what is needed. – AturSams Aug 04 '22 at 09:20
  • This is already in my answer. "You could spawn a subprocess..." – AKX Aug 04 '22 at 09:21