Make runs under the 'unprivileged' user

Simplify the handling of timeouts.
This commit is contained in:
Nicolas Setton
2019-01-23 11:16:48 -05:00
parent f82659d3cf
commit b4a2e6403c
3 changed files with 36 additions and 13 deletions

View File

@@ -281,13 +281,22 @@ def run_program(request):
doctor_main_gpr(tempd, main)
# Push the code to the container
try:
subprocess.check_call(["lxc", "file", "push", "--recursive", tempd,
"safecontainer/workspace/sessions/"])
subprocess.check_call(["lxc", "exec", "safecontainer", "--",
"chmod", "-R", "a+rx",
"/workspace/sessions/{}".format
(os.path.basename(tempd))])
except subprocess.CalledProcessError, exception:
result = {'message': "error transferring the program"}
return CrossDomainResponse(result)
# Run the command(s) to check the program
commands = [
# Copy the program over
["lxc", "file", "push", "--recursive", tempd,
"safecontainer/workspace/sessions/"],
# Run it
# Run the program
["lxc", "exec", "safecontainer", "--", "su", "runner",
"-c",
"python /workspace/run.py /workspace/sessions/{} {} {}".format(

View File

@@ -33,6 +33,9 @@ protect:
mkdir -p /home/unprivileged
chown unprivileged /home/unprivileged
# Allow runner to run unprivileged
echo "runner ALL=(unprivileged) NOPASSWD:ALL" > /etc/sudoers.d/runner
# Prevent unprivileged from writing to /tmp
chmod 775 /tmp
chmod 775 /var/tmp

View File

@@ -15,7 +15,8 @@ import traceback
CONT = 'safecontainer'
INTERRUPT_STRING = '<interrupted>'
DEBUG = True
INTERRUPT_RETURNCODE = 124
DEBUG = False
def run(command):
@@ -30,27 +31,36 @@ def run(command):
def safe_run(workdir, mode, main):
def c(cl):
def c(cl=[]):
"""Aux procedure, run the given command line and output to stdout"""
try:
if DEBUG:
print "running: {}".format(cl)
subprocess.call(cl, cwd=workdir, stdout=sys.stdout, shell=True)
returncode = subprocess.call(cl, cwd=workdir,
stdout=sys.stdout, shell=False)
if returncode == INTERRUPT_RETURNCODE:
print INTERRUPT_STRING
return True
except Exception:
print "ERROR when running {}".format(' '.join(cl))
traceback.print_exc()
return False
c(["echo", workdir, mode, main])
c(["echo"])
try:
if mode == "run":
# In "run" mode, first build, and then launch the main
if c(["gprbuild", "-q", "-P", "main"]):
if main:
line = 'timeout 10s bash -c "LD_PRELOAD=/preloader.so {}" || echo {}'.format(
os.path.join(workdir, main.split('.')[0]),
INTERRUPT_STRING)
c([line])
# We run:
# - as user 'unprivileged' that has no write access
# - under a timeout
# - with our ld preloader to prevent forks
line = ['sudo', '-u', 'unprivileged', 'timeout', '10s',
'bash', '-c',
'LD_PRELOAD=/preloader.so {}'.format(
os.path.join(workdir, main.split('.')[0]))]
c(line)
except Exception:
traceback.print_exc()
@@ -70,6 +80,7 @@ if __name__ == '__main__':
if len(sys.argv) > 3:
main = sys.argv[3]
# This is where the compiler is installed
os.environ["PATH"] = "/gnat/bin:{}".format(os.environ["PATH"])
safe_run(workdir, mode, main)