mirror of https://github.com/EasyCTF/librectf
199 lines
5.4 KiB
Python
199 lines
5.4 KiB
Python
import logging
|
|
import subprocess
|
|
import os
|
|
from abc import ABCMeta
|
|
from typing import List, Dict
|
|
|
|
import config
|
|
from models import JobVerdict
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger.setLevel(logging.INFO)
|
|
logging.info("Starting up")
|
|
|
|
|
|
class Language(metaclass=ABCMeta):
|
|
@classmethod
|
|
def compile(
|
|
cls,
|
|
source_code: str,
|
|
workdir: str,
|
|
executable_name: str,
|
|
time_limit: float = config.COMPILATION_TIME_LIMIT,
|
|
) -> str:
|
|
raise NotImplementedError()
|
|
|
|
@classmethod
|
|
def get_command(cls, workdir: str, executable_name: str) -> List[str]:
|
|
raise NotImplementedError()
|
|
|
|
@classmethod
|
|
def get_allowed_files(cls, workdir: str, executable_name: str):
|
|
raise NotImplementedError()
|
|
|
|
@classmethod
|
|
def get_allowed_file_prefixes(cls, workdir: str, executable_name: str):
|
|
raise NotImplementedError()
|
|
|
|
|
|
class CXX(Language):
|
|
@classmethod
|
|
def compile(
|
|
cls,
|
|
source_code: str,
|
|
workdir: str,
|
|
executable_name: str,
|
|
time_limit: float = config.COMPILATION_TIME_LIMIT,
|
|
) -> str:
|
|
source_file_path = os.path.join(workdir, "source.cpp")
|
|
with open(source_file_path, "wb") as source_file:
|
|
source_file.write(source_code.encode("utf-8"))
|
|
|
|
executable_file_path = os.path.join(workdir, executable_name)
|
|
try:
|
|
subprocess.check_call(
|
|
["g++", "--std=c++1y", "-o", executable_file_path, source_file_path],
|
|
timeout=config.COMPILATION_TIME_LIMIT,
|
|
)
|
|
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
|
|
return None
|
|
|
|
return executable_name
|
|
|
|
@classmethod
|
|
def get_command(cls, workdir: str, executable_name: str) -> List[str]:
|
|
return [os.path.join(workdir, executable_name)]
|
|
|
|
@classmethod
|
|
def get_allowed_files(cls, workdir: str, executable_name: str):
|
|
return []
|
|
|
|
@classmethod
|
|
def get_allowed_file_prefixes(cls, workdir: str, executable_name: str):
|
|
return []
|
|
|
|
|
|
class Python(Language):
|
|
language_name = "python"
|
|
interpreter_name = "python"
|
|
|
|
@classmethod
|
|
def compile(
|
|
cls,
|
|
source_code: str,
|
|
workdir: str,
|
|
executable_name: str,
|
|
time_limit: float = config.COMPILATION_TIME_LIMIT,
|
|
) -> str:
|
|
executable_name += ".py"
|
|
executable_path = os.path.join(workdir, executable_name)
|
|
with open(executable_path, "wb") as executable_file:
|
|
executable_file.write(source_code.encode("utf-8"))
|
|
|
|
"""try:
|
|
subprocess.check_call([cls.interpreter_name, '-m', 'py_compile', executable_name],
|
|
timeout=config.COMPILATION_TIME_LIMIT)
|
|
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
|
|
return None"""
|
|
|
|
return executable_name
|
|
|
|
@classmethod
|
|
def get_command(cls, workdir: str, executable_name: str) -> List[str]:
|
|
return [
|
|
os.path.join("/usr/bin", cls.interpreter_name),
|
|
"-s",
|
|
"-S",
|
|
os.path.join(workdir, executable_name),
|
|
]
|
|
|
|
@classmethod
|
|
def get_allowed_files(cls, workdir: str, executable_name: str):
|
|
return [
|
|
"/etc/nsswitch.conf",
|
|
"/etc/passwd",
|
|
"/dev/urandom", # TODO: come up with random policy
|
|
"/tmp",
|
|
"/bin/Modules/Setup",
|
|
workdir,
|
|
os.path.join(workdir, executable_name),
|
|
]
|
|
|
|
@classmethod
|
|
def get_allowed_file_prefixes(cls, workdir: str, executable_name: str):
|
|
return []
|
|
|
|
|
|
class Java(Language):
|
|
@classmethod
|
|
def compile(
|
|
cls,
|
|
source_code: str,
|
|
workdir: str,
|
|
executable_name: str,
|
|
time_limit: float = config.COMPILATION_TIME_LIMIT,
|
|
) -> str:
|
|
source_file_path = os.path.join(workdir, "Main.java")
|
|
with open(source_file_path, "wb") as source_file:
|
|
source_file.write(source_code.encode("utf-8"))
|
|
|
|
executable_file_path = os.path.join(workdir, "Main")
|
|
try:
|
|
subprocess.check_call(
|
|
["javac", "-d", workdir, source_file_path],
|
|
timeout=config.COMPILATION_TIME_LIMIT,
|
|
)
|
|
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
|
|
return None
|
|
|
|
return "Main"
|
|
|
|
@classmethod
|
|
def get_command(cls, workdir: str, executable_name: str) -> List[str]:
|
|
return [
|
|
"/usr/bin/java",
|
|
"-XX:-UsePerfData",
|
|
"-XX:+DisableAttachMechanism",
|
|
"-Xmx256m",
|
|
"-Xrs",
|
|
"-cp",
|
|
workdir,
|
|
executable_name,
|
|
]
|
|
|
|
@classmethod
|
|
def get_allowed_files(cls, workdir: str, executable_name: str):
|
|
return [
|
|
"/etc/nsswitch.conf",
|
|
"/etc/passwd",
|
|
"/tmp",
|
|
workdir,
|
|
os.path.join(workdir, executable_name + ".class"),
|
|
]
|
|
|
|
@classmethod
|
|
def get_allowed_file_prefixes(cls, workdir: str, executable_name: str):
|
|
return [
|
|
"/etc/java-7-openjdk/",
|
|
"/tmp/.java_pid",
|
|
"/tmp/",
|
|
]
|
|
|
|
|
|
class Python2(Python):
|
|
language_name = "python2"
|
|
interpreter_name = "python2.7"
|
|
|
|
|
|
class Python3(Python):
|
|
language_name = "python3"
|
|
interpreter_name = "python3.5"
|
|
|
|
|
|
languages = {
|
|
"cxx": CXX,
|
|
"python2": Python2,
|
|
"python3": Python3,
|
|
"java": Java,
|
|
} # type: Dict[str, Language]
|