Blob Blame History Raw
#!/usr/bin/python3
"""
Run an arbitrary script inside the target tree

Runs an arbitrary script inside the target tree.

Writes the contents of the `script` item to `/osbuild-script`, sets the
permissions of the script to 0550 (-r-xr-x---), then uses the host's `chroot`
binary to chroot into the tree and execute the script. The script is removed
after it completes.

WARNING: running code inside the tree is unsafe, unreliable, and generally
discouraged. Using this stage may result in unexplained failures or other
undefined behavior, and should only be done as a last resort.

NOTE: if `script` does not start with a line like '#!/bin/bash
', executing
it will fail with ENOEXEC. Some `chroot` binaries will try to run the script
through `/bin/sh` in that case, so it might still work, but that behavior is
not guaranteed.
"""


import atexit
import json
import os
import subprocess
import sys

SCHEMA = """
"additionalProperties": false,
"required": ["script"],
"properties": {
  "script": {
    "type": "string",
    "description": "contents of the script file to be executed."
  }
}
"""

def main(tree, options):
    script = options["script"]

    scriptfile = f"{tree}/osbuild-script"

    with open(scriptfile, "w") as f:
        f.write(script)

    os.chmod(scriptfile, 0o550)
    atexit.register(lambda: os.unlink(scriptfile))

    return subprocess.run(["chroot", tree, "/osbuild-script"], check=False).returncode


if __name__ == '__main__':
    args = json.load(sys.stdin)
    r = main(args["tree"], args["options"])
    sys.exit(r)