def get_fs(self) -> List[FilesystemAccessRule]: fs = super().get_fs() if self.use_qemu: assert self._executable is not None fs += [ ExactFile('/proc/sys/vm/mmap_min_addr'), RecursiveDir('/etc/qemu-binfmt'), ExactFile(self._executable), ] return fs
class Executor(JavaExecutor): ext = 'kt' compiler = 'kotlinc' compiler_time_limit = 20 compiler_read_fs = [ ExactFile('/bin/uname'), ExactFile('/bin/bash'), ] vm = 'kotlin_vm' test_program = """\ fun main(args: Array<String>) { println(readLine()) } """ def create_files(self, problem_id, source_code, *args, **kwargs): super().create_files(problem_id, source_code, *args, **kwargs) self._jar_name = '%s.jar' % problem_id def get_cmdline(self, **kwargs): res = super().get_cmdline(**kwargs) res[-2:] = ['-jar', self._jar_name] return res def get_compile_args(self): return [ self.get_compiler(), '-include-runtime', '-d', self._jar_name, self._code ] @classmethod def get_versionable_commands(cls): return [('kotlinc', cls.get_compiler()), ('java', cls.get_vm())] @classmethod def autoconfig(cls): kotlinc = cls.find_command_from_list(['kotlinc']) if kotlinc is None: return None, False, 'Failed to find "kotlinc"' java = cls.find_command_from_list(['java']) if java is None: return None, False, 'Failed to find "java"' return cls.autoconfig_run_test({ cls.compiler: kotlinc, cls.vm: cls.unravel_java(java) })
def get_fs(self) -> List[FilesystemAccessRule]: home = self.runtime_dict.get('%s_home' % self.get_executor_name().lower()) fs = super().get_fs() + [ExactFile(self._code)] if home is not None: fs += [RecursiveDir(home)] return fs
class Executor(CompiledExecutor): ext = 'cbl' command = 'cobc' address_grace = 131072 compile_output_index = 0 compiler_read_fs = [ ExactFile('/etc/gnucobol/default.conf'), ] test_program = """\ IDENTIFICATION DIVISION. PROGRAM-ID. HELLO-WORLD. PROCEDURE DIVISION. DISPLAY 'echo: Hello, World!'. STOP RUN. """ # noqa: W191 def get_compile_args(self): return [self.get_command(), '-x', '-free', self._code] def get_compile_popen_kwargs(self): return {'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT} def get_compile_output(self, process): output = super().get_compile_output(process) # Some versions of the compiler have the first letter capitalized, and # others don't. for prefix in (b'Error:', b'Note:', b'Warning:'): if prefix in output or prefix.lower() in output: return output return b''
class Executor(NullStdoutMixin, CompiledExecutor): ext = 'pas' name = 'PAS' command = 'fpc' compiler_read_fs = [ ExactFile('/etc/fpc.cfg'), ] test_program = """\ var line : string; begin readln(line); writeln(line); end. """ def get_compile_args(self): return [self.get_command(), '-Fe/dev/stderr', '-So', '-O2', self._code] def get_compile_output(self, process): output = super().get_compile_output(process) return output if b'Fatal:' in output or b'Warning:' in output or b'Note:' in output else '' @classmethod def get_version_flags(cls, command): return ['-help']
def test_exact_file(self): self.fs = FilesystemPolicy([ExactFile('/etc/passwd')]) self.checkTrue('/etc/passwd') self.checkFalse('/') self.checkFalse('/etc') self.checkFalse('/etc/p') self.checkFalse('/etc/passwd2')
class Executor(ScriptExecutor): name = 'FORTH' command = 'gforth' ext = 'fs' test_program = """\ : HELLO ( -- ) ." echo: Hello, World!" CR ; HELLO """ fs = [ExactFile('/.gforth-history')] def get_cmdline(self, **kwargs): return [self.get_command(), self._code, '-e', 'bye']
def get_fs(self) -> List[FilesystemAccessRule]: fs = (super().get_fs() + [ExactFile(self._agent_file)] + [ ExactDir(str(parent)) for parent in PurePath(self._agent_file).parents ]) vm = self.get_vm() assert vm is not None vm_parent = Path(os.path.realpath(vm)).parent.parent vm_config = Path( glob.glob(f'{vm_parent}/**/jvm.cfg', recursive=True)[0]) if vm_config.is_symlink(): fs += [RecursiveDir(os.path.dirname(os.path.realpath(vm_config)))] return fs
class Executor(ScriptExecutor): ext = 'rb' address_grace = 65536 test_program = 'puts gets' nproc = -1 command_paths = (['ruby3.0'] + ['ruby2.%d' % i for i in reversed(range(0, 8))] + ['ruby2%d' % i for i in reversed(range(0, 8))]) syscalls = ['thr_set_name', 'eventfd2', 'specialfd'] fs = [ExactFile('/proc/self/loginuid')] def get_fs(self): fs = super().get_fs() home = self.runtime_dict.get('%s_home' % self.get_executor_name().lower()) if home is not None: fs.append(RecursiveDir(home)) components = home.split('/') components.pop() while components and components[-1]: fs.append(ExactDir('/'.join(components))) components.pop() return fs def get_cmdline(self, **kwargs): return [self.get_command(), '--disable-gems', self._code] @classmethod def get_version_flags(cls, command): return ['-v'] @classmethod def get_command(cls): name = cls.get_executor_name().lower() if name in cls.runtime_dict: return cls.runtime_dict[name] if '%s_home' % name in cls.runtime_dict: return os.path.join(cls.runtime_dict['%s_home' % name], 'bin', 'ruby') @classmethod def get_versionable_commands(cls): return (('ruby', cls.get_command()), ) @classmethod def get_find_first_mapping(cls): return {cls.name.lower(): cls.command_paths}
class Executor(CompiledExecutor): ext = 'rkt' name = 'RKT' fs = [RecursiveDir('/etc/racket'), ExactFile('/etc/passwd')] compiler_read_fs = [ RecursiveDir('/etc/racket'), RecursiveDir('~/.local/share/racket'), ] command = 'racket' syscalls = ['epoll_create', 'epoll_create1', 'epoll_wait', 'epoll_pwait'] # Racket SIGABRTs under low-memory conditions before actually crossing the memory limit, # so give it a bit of headroom to be properly marked as MLE. data_grace = 4096 address_grace = 131072 test_program = """\ #lang racket (displayln (read-line)) """ def get_compile_args(self): return [self.runtime_dict['raco'], 'make', self._code] def get_cmdline(self, **kwargs): return [self.get_command(), self._code] def get_executable(self): return self.get_command() @classmethod def initialize(cls): if 'raco' not in cls.runtime_dict: return False return super().initialize() @classmethod def get_versionable_commands(cls): return [('racket', cls.get_command())] @classmethod def get_find_first_mapping(cls): return {'racket': ['racket'], 'raco': ['raco']}
class Executor(CompiledExecutor): ext = 'dart' name = 'DART' nproc = -1 # Dart uses a really, really large number of threads command = 'dart' compiler_read_fs = [ # Dart shells out... ExactFile('/bin/sh'), RecursiveDir('/proc/self/fd'), ] test_program = """ void main() { print("echo: Hello, World!"); } """ address_grace = 128 * 1024 syscalls = [ 'epoll_create', 'epoll_create1', 'epoll_ctl', 'epoll_wait', 'epoll_pwait', 'timerfd_settime', 'memfd_create', 'ftruncate', ] def get_compile_args(self): return [ self.get_command(), '--snapshot=%s' % self.get_compiled_file(), self._code ] def get_cmdline(self, **kwargs): return [self.get_command(), self.get_compiled_file()] def get_executable(self): return self.get_command()
class Executor(CompiledExecutor): ext = 'd' name = 'D' address_grace = 32768 command = 'dmd' compiler_read_fs = [ ExactFile('/etc/dmd.conf'), ] test_program = """\ import std.stdio; void main() { writeln(readln()); } """ source_filename_format = 'main.{ext}' def get_compile_args(self): return [ self.get_command(), '-O', '-inline', '-release', '-w', self._code, '-of%s' % self.problem ]
class Executor(CompiledExecutor): ext = 'rs' command = 'cargo' test_program = HELLO_WORLD_PROGRAM compiler_time_limit = 20 compiler_read_fs = [ RecursiveDir('/home'), ExactFile('/etc/resolv.conf'), ] compiler_write_fs = [ RecursiveDir('~/.cargo'), ] def create_files(self, problem_id, source_code, *args, **kwargs): os.mkdir(self._file('src')) with open(self._file('src', 'main.rs'), 'wb') as f: f.write(source_code) with open(self._file('Cargo.toml'), 'wb') as f: f.write(CARGO_TOML) with open(self._file('Cargo.lock'), 'wb') as f: f.write(CARGO_LOCK) @classmethod def get_versionable_commands(cls): return [('rustc', os.path.join(os.path.dirname(cls.get_command()), 'rustc'))] def get_compile_args(self): args = [self.get_command(), 'build', '--release'] if bool_env('DMOJ_CARGO_OFFLINE'): args += ['--offline'] return args def get_compiled_file(self): return self._file('target', 'release', 'user_submission')
from dmoj.utils.ansi import print_ansi from dmoj.utils.error import print_protection_fault from dmoj.utils.unicode import utf8bytes, utf8text version_cache: Dict[str, List[Tuple[str, Tuple[int, ...]]]] = {} if os.path.isdir('/usr/home'): USR_DIR = [ RecursiveDir(f'/usr/{d}') for d in os.listdir('/usr') if d != 'home' and os.path.isdir(f'/usr/{d}') ] else: USR_DIR = [RecursiveDir('/usr')] BASE_FILESYSTEM: List[FilesystemAccessRule] = [ ExactFile('/dev/null'), ExactFile('/dev/tty'), ExactFile('/dev/zero'), ExactFile('/dev/urandom'), ExactFile('/dev/random'), *USR_DIR, RecursiveDir('/lib'), RecursiveDir('/lib32'), RecursiveDir('/lib64'), RecursiveDir('/opt'), ExactDir('/etc'), ExactFile('/etc/localtime'), ExactFile('/etc/timezone'), ExactDir('/usr'), ExactDir('/tmp'), ExactDir('/'),
def test_build_checks(self): self.assertRaises(AssertionError, FilesystemPolicy, [ExactFile('not/an/absolute/path')]) self.assertRaises(AssertionError, FilesystemPolicy, [ExactDir('/nota/./normalized/path')]) self.assertRaises(AssertionError, FilesystemPolicy, [RecursiveDir('')])
def get_write_fs(self) -> List[FilesystemAccessRule]: assert self._dir is not None return super().get_write_fs() + [ ExactFile(os.path.join(self._dir, 'submission_jvm_crash.log')) ]
def get_fs(self): return super().get_fs() + [ExactFile('/proc/self/cmdline')]
def __init__(self, *, tmpdir, read_fs, write_fs): read_fs += BASE_FILESYSTEM + [ RecursiveDir(tmpdir), ExactFile('/bin/strip'), RecursiveDir('/usr/x86_64-linux-gnu'), ] write_fs += BASE_WRITE_FILESYSTEM + [RecursiveDir(tmpdir)] super().__init__(read_fs=read_fs, write_fs=write_fs) self.update({ # Process spawning system calls sys_fork: ALLOW, sys_vfork: ALLOW, sys_execve: ALLOW, sys_getcpu: ALLOW, sys_getpgid: ALLOW, # Directory system calls sys_mkdir: self.handle_file_access(FilesystemSyscallKind.WRITE, file_reg=0), sys_mkdirat: self.handle_file_access_at(FilesystemSyscallKind.WRITE, dir_reg=0, file_reg=1), sys_rmdir: self.handle_file_access(FilesystemSyscallKind.WRITE, file_reg=0), # Linking system calls sys_link: self.handle_file_access(FilesystemSyscallKind.WRITE, file_reg=1), sys_linkat: self.handle_file_access_at(FilesystemSyscallKind.WRITE, dir_reg=2, file_reg=3), sys_unlink: self.handle_file_access(FilesystemSyscallKind.WRITE, file_reg=0), sys_unlinkat: self.handle_file_access_at(FilesystemSyscallKind.WRITE, dir_reg=0, file_reg=1), sys_symlink: self.handle_file_access(FilesystemSyscallKind.WRITE, file_reg=1), # Miscellaneous other filesystem system calls sys_chdir: self.handle_file_access(FilesystemSyscallKind.READ, file_reg=0), sys_chmod: self.handle_file_access(FilesystemSyscallKind.WRITE, file_reg=0), sys_utimensat: self.do_utimensat, sys_umask: ALLOW, sys_flock: ALLOW, sys_fsync: ALLOW, sys_fadvise64: ALLOW, sys_fchmodat: self.handle_file_access_at(FilesystemSyscallKind.WRITE, dir_reg=0, file_reg=1), sys_fchmod: self.handle_fchmod, sys_fallocate: ALLOW, sys_ftruncate: ALLOW, sys_rename: self.handle_rename, sys_renameat: self.handle_renameat, # I/O system calls sys_readv: ALLOW, sys_pwrite64: ALLOW, sys_sendfile: ALLOW, # Event loop system calls sys_epoll_create: ALLOW, sys_epoll_create1: ALLOW, sys_epoll_ctl: ALLOW, sys_epoll_wait: ALLOW, sys_epoll_pwait: ALLOW, sys_timerfd_settime: ALLOW, sys_eventfd2: ALLOW, sys_waitid: ALLOW, sys_wait4: ALLOW, # Network system calls, we don't sandbox these sys_socket: ALLOW, sys_socketpair: ALLOW, sys_connect: ALLOW, sys_setsockopt: ALLOW, sys_getsockname: ALLOW, sys_sendmmsg: ALLOW, sys_recvfrom: ALLOW, sys_sendto: ALLOW, # Miscellaneous other system calls sys_msync: ALLOW, sys_clock_nanosleep: ALLOW, sys_memfd_create: ALLOW, sys_rt_sigsuspend: ALLOW, }) # FreeBSD-specific syscalls if 'freebsd' in sys.platform: self.update({ sys_rfork: ALLOW, sys_procctl: ALLOW, sys_cap_rights_limit: ALLOW, sys_posix_fadvise: ALLOW, sys_posix_fallocate: ALLOW, sys_setrlimit: ALLOW, sys_cap_ioctls_limit: ALLOW, sys_cap_fcntls_limit: ALLOW, sys_cap_enter: ALLOW, sys_utimes: self.handle_file_access(FilesystemSyscallKind.WRITE, file_reg=0), })
def get_fs(self): return super().get_fs() + [ExactFile(self._code + 'bc')]
def get_fs(self): return super().get_fs() + [ ExactFile(self.runtime_dict['coffee']), ExactFile(self._code) ]
def test_rule_type_check(self): self.assertRaises(AssertionError, FilesystemPolicy, [ExactFile('/usr/lib')]) self.assertRaises(AssertionError, FilesystemPolicy, [ExactDir('/etc/passwd')]) self.assertRaises(AssertionError, FilesystemPolicy, [RecursiveDir('/etc/passwd')])
class Executor(JavaExecutor): ext = 'scala' compiler = 'scalac' compiler_time_limit = 20 compiler_read_fs = [ ExactFile('/bin/uname'), ExactFile('/bin/readlink'), ExactFile('/bin/grep'), ExactFile('/bin/stty'), ExactFile('/bin/bash'), RecursiveDir('/etc/alternatives'), ] vm = 'scala_vm' test_program = """\ object self_test extends App { println("echo: Hello, World!") } """ def create_files(self, problem_id, source_code, *args, **kwargs): super().create_files(problem_id, source_code, *args, **kwargs) self._class_name = problem_id def get_cmdline(self, **kwargs): res = super().get_cmdline(**kwargs) # Simply run bash -x $(which scala) and copy all arguments after -Xmx and -Xms # and add it as a list in the configuration. res[-2:-1] = self.runtime_dict['scala_args'] return res def get_compile_args(self): return [self.get_compiler(), self._code] @classmethod def get_versionable_commands(cls): return [('scalac', cls.get_compiler()), ('java', cls.get_vm())] @classmethod def autoconfig(cls): result = {} for key, files in {'scalac': ['scalac'], 'scala': ['scala']}.items(): file = cls.find_command_from_list(files) if file is None: return result, False, 'Failed to find "%s"' % key result[key] = file scala = result.pop('scala') with open(os.devnull, 'w') as devnull: process = subprocess.Popen( ['bash', '-x', scala, '-usebootcp', '-version'], stdout=devnull, stderr=subprocess.PIPE) output = utf8text(process.communicate()[1]) log = [ i for i in output.split('\n') if 'scala.tools.nsc.MainGenericRunner' in i ] if not log: return result, False, 'Failed to parse: %s' % scala cmdline = log[-1].lstrip('+ ').split() result['scala_vm'] = cls.unravel_java( cls.find_command_from_list([cmdline[0]])) result['scala_args'] = [ i for i in cmdline[1:-1] if not i.startswith(('-Xmx', '-Xms')) ] data = cls.autoconfig_run_test(result) if data[1]: data = data[:2] + ('Using %s' % scala, ) + data[3:] return data