Beispiel #1
0
    def comp_cxx(self, callback):
        '''GCC, Clang compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback(stat['detect_error'])

        with StackContext(Privilege.fileaccess):
            compile_path = self.chal_path + '/compile'
            os.mkdir(compile_path, mode=0o770)
            shutil.copyfile(self.code_path, compile_path + '/test.cpp', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(compile_path, self.compile_uid, self.compile_gid)

        if self.comp_typ == 'g++':
            compiler = '/usr/bin/g++'
        elif self.comp_typ == 'clang++':
            compiler = '/usr/bin/clang++'

        task_id = PyExt.create_task(compiler, \
            [
                '-O2',
                '-std=c++14',
                '-o', './a.out',
                './test.cpp',
            ], \
            [
                'PATH=/usr/bin',
                'TMPDIR=/home/%d/compile'%self.uniqid,
            ], \
            StdChal.null_fd, StdChal.null_fd, StdChal.null_fd, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 256 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(-1)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #2
0
    def comp_cxx(self, callback):
        '''GCC, Clang compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''
        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback(stat['detect_error'])

        with StackContext(Privilege.fileaccess):
            compile_path = self.chal_path + '/compile'
            os.mkdir(compile_path, mode=0o770)
            shutil.copyfile(self.code_path, compile_path + '/test.cpp', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(compile_path, self.compile_uid, self.compile_gid)

        if self.comp_typ == 'g++':
            compiler = '/usr/bin/g++'
        elif self.comp_typ == 'clang++':
            compiler = '/usr/bin/clang++'

        task_id = PyExt.create_task(compiler, \
            [
                '-O2',
                '-std=c++14',
                '-o', './a.out',
                './test.cpp',
            ], \
            [
                'PATH=/usr/bin',
                'TMPDIR=/home/%d/compile'%self.uniqid,
            ], \
            StdChal.null_fd, StdChal.null_fd, StdChal.null_fd, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 256 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(-1)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #3
0
    def comp_make(self, callback=None):
        '''Makefile compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback((stat['detect_error'], ''))

        make_path = self.chal_path + '/compile'
        FileUtils.copydir(self.res_path + '/make', make_path)
        with StackContext(Privilege.fileaccess):
            shutil.copyfile(self.code_path, make_path + '/main.cpp', \
                follow_symlinks=False)
        FileUtils.setperm(make_path, self.compile_uid, self.compile_gid)
        with StackContext(Privilege.fullaccess):
            os.chmod(make_path, mode=0o770)

        task_id = PyExt.create_task('/usr/bin/make', \
            [], \
            [
                'PATH=/usr/bin:/bin',
                'TMPDIR=/home/%d/compile'%self.uniqid,
                'OUT=./a.out',
            ], \
            {
                0: StdChal.null_fd,
                1: StdChal.null_fd,
                2: StdChal.null_fd,
            }, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback((PyExt.DETECT_INTERNALERR, ''))
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #4
0
    def comp_make(self, callback=None):
        '''Makefile compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback((stat['detect_error'], ''))

        make_path = self.chal_path + '/compile'
        FileUtils.copydir(self.res_path + '/make', make_path)
        with StackContext(Privilege.fileaccess):
            shutil.copyfile(self.code_path, make_path + '/main.cpp', \
                follow_symlinks=False)
        FileUtils.setperm(make_path, self.compile_uid, self.compile_gid)
        with StackContext(Privilege.fullaccess):
            os.chmod(make_path, mode=0o770)

        task_id = PyExt.create_task('/usr/bin/make', \
            [], \
            [
                'PATH=/usr/bin:/bin',
                'TMPDIR=/home/%d/compile'%self.uniqid,
                'OUT=./a.out',
            ], \
            {
                0: StdChal.null_fd,
                1: StdChal.null_fd,
                2: StdChal.null_fd,
            }, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(PyExt.DETECT_INTERNALERR)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #5
0
    def comp_python(self, callback):
        '''Python3.4 compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback(stat['detect_error'])

        with StackContext(Privilege.fileaccess):
            compile_path = self.chal_path + '/compile'
            os.mkdir(compile_path, mode=0o770)
            shutil.copyfile(self.code_path, compile_path + '/test.py', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(compile_path, self.compile_uid, self.compile_gid)

        task_id = PyExt.create_task('/usr/bin/python3.4', \
            [
                '-m',
                'py_compile',
                './test.py'
            ], \
            [
                'HOME=/home/%d/compile'%self.uniqid,
                'LANG=en_US.UTF-8'
            ], \
            StdChal.null_fd, StdChal.null_fd, StdChal.null_fd, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 256 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(-1)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #6
0
    def comp_python(self, callback):
        '''Python3.4 compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''
        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback(stat['detect_error'])

        with StackContext(Privilege.fileaccess):
            compile_path = self.chal_path + '/compile'
            os.mkdir(compile_path, mode=0o770)
            shutil.copyfile(self.code_path, compile_path + '/test.py', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(compile_path, self.compile_uid, self.compile_gid)

        task_id = PyExt.create_task('/usr/bin/python3.4', \
            [
                '-m',
                'py_compile',
                './test.py'
            ], \
            [
                'HOME=/home/%d/compile'%self.uniqid,
                'LANG=en_US.UTF-8'
            ], \
            StdChal.null_fd, StdChal.null_fd, StdChal.null_fd, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 256 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(-1)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #7
0
    def judge(self, src_path, exe_relpath, argv, envp, check_ugid, test_ugid, \
        test_relpath, test_param, metadata, callback=None):
        '''I/O redirect special judge.

        Args:
            src_path (string): Executable source path.
            exe_relpath (string): Executable or interpreter path in the sandbox.
            argv ([string]): List of arguments.
            envp ([string]): List of environment variables.
            check_ugid (int, int): Check UID/GID.
            test_ugid (int, int): Test UID/GID.
            test_relpath (string): Test relative path.
            test_param (dict): Test parameters.
            metadata (dict): Metadata.
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _check_started_cb(task_id):
            '''Check started callback.

            Close unused file descriptors after the check is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal inpipe_fd
            nonlocal outpipe_fd
            nonlocal ansfile_fd
            nonlocal check_infile_fd

            os.close(inpipe_fd[1])
            os.close(outpipe_fd[0])
            if ansfile_fd is not None:
                os.close(ansfile_fd)
            if check_infile_fd is not None:
                os.close(check_infile_fd)

        def _test_started_cb(task_id):
            '''Test started callback.

            Close unused file descriptors after the test is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal inpipe_fd
            nonlocal outpipe_fd
            nonlocal outfile_fd
            nonlocal test_infile_fd

            os.close(inpipe_fd[0])
            os.close(outpipe_fd[1])
            os.close(outfile_fd)
            if test_infile_fd is not None:
                os.close(test_infile_fd)

        def _done_cb():
            '''Done callback.'''

            nonlocal result_stat
            nonlocal result_pass

            if result_pass is not None and result_stat is not None:
                callback((result_pass, result_stat))
                return

        def _check_done_cb(task_id, stat):
            '''Check done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal result_pass

            if stat['detect_error'] == PyExt.DETECT_NONE:
                result_pass = True
            else:
                result_pass = False
            _done_cb()

        def _test_done_cb(task_id, stat):
            '''Test done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal result_stat

            result_stat = (stat['utime'], stat['peakmem'], stat['detect_error'])
            _done_cb()

        result_stat = None
        result_pass = None
        in_path = test_param['in']
        ans_path = test_param['ans']
        timelimit = test_param['timelimit']
        memlimit = test_param['memlimit']
        check_uid, check_gid = check_ugid
        test_uid, test_gid = test_ugid

        test_path = self.container_path + test_relpath
        output_relpath = test_relpath + '/output.txt'
        output_path = self.container_path + output_relpath
        verdict_relpath = test_relpath + '/verdict.txt'
        verdict_path = self.container_path + verdict_relpath

        # Prepare test environment.
        with StackContext(Privilege.fileaccess):
            os.mkdir(test_path, mode=0o771)
            shutil.copyfile(src_path, test_path + '/a.out', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(test_path + '/a.out', test_uid, test_gid)
            os.chmod(test_path + '/a.out', 0o500)

        # Prepare I/O.
        with StackContext(Privilege.fileaccess):
            try:
                check_infile_fd = os.open(in_path, os.O_RDONLY | os.O_CLOEXEC)
                test_infile_fd = os.open(in_path, os.O_RDONLY | os.O_CLOEXEC)
            except FileNotFoundError:
                check_infile_fd = None
                test_infile_fd = None
            try:
                ansfile_fd = os.open(ans_path, os.O_RDONLY | os.O_CLOEXEC)
            except FileNotFoundError:
                ansfile_fd = None
            outfile_fd = os.open(output_path, \
                os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC, mode=0o400)
            os.close(os.open(verdict_path, \
                os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC, mode=0o400))
        with StackContext(Privilege.fullaccess):
            os.chown(output_path, check_uid, check_gid)
            os.chown(verdict_path, check_uid, check_gid)

        inpipe_fd = os.pipe2(os.O_CLOEXEC)
        outpipe_fd = os.pipe2(os.O_CLOEXEC)

        # Set file descriptor mapping.
        check_fdmap = {
            0: StdChal.null_fd,
            1: StdChal.null_fd,
            2: StdChal.null_fd,
        }
        test_fdmap = {
            0: StdChal.null_fd,
            1: StdChal.null_fd,
            2: StdChal.null_fd,
        }
        if check_infile_fd is not None:
            check_fdmap[metadata['redir_check']['testin']] = check_infile_fd
        if ansfile_fd is not None:
            check_fdmap[metadata['redir_check']['ansin']] = ansfile_fd
        check_fdmap[metadata['redir_check']['pipein']] = inpipe_fd[1]
        check_fdmap[metadata['redir_check']['pipeout']] = outpipe_fd[0]
        try:
            del check_fdmap[-1]
        except KeyError:
            pass
        if test_infile_fd is not None:
            test_fdmap[metadata['redir_test']['testin']] = test_infile_fd
        test_fdmap[metadata['redir_test']['testout']] = outfile_fd
        test_fdmap[metadata['redir_test']['pipein']] = inpipe_fd[0]
        test_fdmap[metadata['redir_test']['pipeout']] = outpipe_fd[1]
        try:
            del test_fdmap[-1]
        except KeyError:
            pass

        check_task_id = PyExt.create_task(self.build_relpath + '/check', \
            [], \
            [
                'PATH=/usr/bin:/bin',
                'HOME=%s'%self.build_relpath,
                'LANG=en_US.UTF-8',
                'OUTPUT=%s'%output_relpath,
                'VERDICT=%s'%verdict_relpath,
            ], \
            check_fdmap, \
            self.build_relpath, self.container_path, \
            check_uid, check_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if check_task_id is None:
            callback((False, (0, 0, PyExt.DETECT_INTERNALERR)))
            return
        PyExt.start_task(check_task_id, _check_done_cb, _check_started_cb)

        test_task_id = PyExt.create_task(exe_relpath, argv, envp, \
            test_fdmap, \
            test_relpath, self.container_path, \
            test_uid, test_gid, timelimit, memlimit, \
            PyExt.RESTRICT_LEVEL_HIGH)

        if test_task_id is None:
            callback((False, (0, 0, PyExt.DETECT_INTERNALERR)))
            return
        PyExt.start_task(test_task_id, _test_done_cb, _test_started_cb)
Beispiel #8
0
    def build(self, build_ugid, res_path, callback=None):
        '''Build environment.

        Args:
            build_ugid ((int, int)): Build UID/GID.
            res_path (string): Resource path.
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            if stat['detect_error'] == PyExt.DETECT_NONE:
                callback(True)
            else:
                callback(False)

        build_uid, build_gid = build_ugid

        # Prepare build environment.
        FileUtils.copydir(res_path + '/check', self.build_path)
        FileUtils.setperm(self.build_path, build_uid, build_gid)
        with StackContext(Privilege.fullaccess):
            os.chmod(self.build_path, mode=0o770)

        with StackContext(Privilege.fileaccess):
            if not os.path.isfile(self.build_path + '/build'):
                callback(True)
                return

        # Build.
        task_id = PyExt.create_task(self.build_relpath + '/build', \
            [], \
            [
                'PATH=/usr/bin:/bin',
                'TMPDIR=%s'%self.build_relpath,
                'HOME=%s'%self.build_relpath,
                'LANG=en_US.UTF-8'
            ], \
            {
                0: StdChal.null_fd,
                1: StdChal.null_fd,
                2: StdChal.null_fd,
            }, \
            self.build_relpath, 'container/standard', \
            build_uid, build_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(False)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #9
0
    def judge_diff(self, src_path, exe_path, argv, envp, in_path, ans_path, \
        timelimit, memlimit, callback=None):
        '''Diff judge.

        Args:
            src_path (string): Executable source path.
            exe_path (string): Executable or interpreter path in the sandbox.
            argv ([string]): List of arguments.
            envp ([string]): List of environment variables.
            in_path (string): Input file path.
            ans_path (string): Answer file path.
            timelimit (int): Timelimit.
            memlimit (int): Memlimit.
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _started_cb(task_id):
            '''Started callback.

            Close unused file descriptors after the task is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal infile_fd
            nonlocal outpipe_fd

            os.close(infile_fd)
            os.close(outpipe_fd[1])
            IOLoop.instance().add_handler(outpipe_fd[0], _diff_out, \
                IOLoop.READ | IOLoop.ERROR)

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal result_stat
            nonlocal result_pass

            result_stat = (stat['utime'], stat['peakmem'], stat['detect_error'])
            if result_pass is not None:
                callback((result_pass, result_stat))

        def _diff_out(evfd, events):
            '''Diff the output of the task.

            Args:
                evfd (int): Event file descriptor.
                events (int): Event flags.

            Returns:
                None

            '''

            nonlocal outpipe_fd
            nonlocal ansfile
            nonlocal result_stat
            nonlocal result_pass

            end_flag = False
            if events & IOLoop.READ:
                while True:
                    try:
                        data = os.read(outpipe_fd[0], 65536)
                    except BlockingIOError:
                        break
                    ansdata = ansfile.read(len(data))
                    if data != ansdata:
                        result_pass = False
                        end_flag = True
                        break
                    if len(ansdata) == 0:
                        if len(ansfile.read(1)) == 0:
                            result_pass = True
                        else:
                            result_pass = False
                        end_flag = True
                        break

            if (events & IOLoop.ERROR) or end_flag:
                if result_pass is None:
                    if len(ansfile.read(1)) == 0:
                        result_pass = True
                    else:
                        result_pass = False

                IOLoop.instance().remove_handler(evfd)
                os.close(outpipe_fd[0])
                ansfile.close()

                if result_stat is not None:
                    callback((result_pass, result_stat))

        judge_uid, judge_gid = StdChal.get_restrict_ugid()

        # Prepare I/O and stat.
        with StackContext(Privilege.fileaccess):
            infile_fd = os.open(in_path, os.O_RDONLY | os.O_CLOEXEC)
            ansfile = open(ans_path, 'rb')
        outpipe_fd = os.pipe2(os.O_CLOEXEC)
        fcntl.fcntl(outpipe_fd[0], fcntl.F_SETFL, os.O_NONBLOCK)
        result_stat = None
        result_pass = None

        # Prepare judge environment.
        with StackContext(Privilege.fileaccess):
            judge_path = self.chal_path + '/run_%d'%judge_uid
            os.mkdir(judge_path, mode=0o771)
            shutil.copyfile(src_path, judge_path + '/a.out', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(judge_path + '/a.out', judge_uid, judge_gid)
            os.chmod(judge_path + '/a.out', 0o500)

        task_id = PyExt.create_task(exe_path, argv, envp, \
            {
                0: infile_fd,
                1: outpipe_fd[1],
                2: outpipe_fd[1],
            }, \
            '/home/%d/run_%d'%(self.uniqid, judge_uid), 'container/standard', \
            judge_uid, judge_gid, timelimit, memlimit, \
            PyExt.RESTRICT_LEVEL_HIGH)

        if task_id is None:
            os.close(infile_fd)
            os.close(outpipe_fd[0])
            os.close(outpipe_fd[1])
            ansfile.close()
            callback((False, (0, 0, PyExt.DETECT_INTERNALERR)))
        else:
            PyExt.start_task(task_id, _done_cb, _started_cb)
Beispiel #10
0
    def comp_python(self, callback=None):
        '''Python3.4 compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _started_cb(task_id):
            '''Started callback.

            Close unused file descriptors after the task is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal errpipe_fd

            os.close(errpipe_fd)

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal compile_path

            with StackContext(Privilege.fileaccess):
                verfile = open(compile_path + '/verdict.txt', 'r')
                verdict = verfile.read(140)
                verfile.close()
            callback((stat['detect_error'], verdict))

        compile_path = self.chal_path + '/compile'
        with StackContext(Privilege.fileaccess):
            os.mkdir(compile_path, mode=0o770)
            shutil.copyfile(self.code_path, compile_path + '/test.py', \
                follow_symlinks=False)
        FileUtils.setperm(compile_path, self.compile_uid, self.compile_gid)

        with StackContext(Privilege.fileaccess):
            errpipe_fd = os.open(compile_path + '/verdict.txt', \
                os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC, mode=0o440)

        task_id = PyExt.create_task('/usr/bin/python3.4', \
            [
                '-m',
                'py_compile',
                './test.py'
            ], \
            [
                'HOME=/home/%d/compile'%self.uniqid,
                'LANG=en_US.UTF-8'
            ], \
            {
                0: StdChal.null_fd,
                1: StdChal.null_fd,
                2: errpipe_fd,
            }, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            os.close(errpipe_fd)
            callback(PyExt.DETECT_INTERNALERR)
            return

        PyExt.start_task(task_id, _done_cb, _started_cb)
Beispiel #11
0
    def judge_diff(self, src_path, exe_path, argv, envp, in_path, ans_path, \
        timelimit, memlimit, callback):
        '''Diff judge.

        Args:
            src_path (string): Executable source path.
            exe_path (string): Executable or interpreter path in the sandbox.
            argv ([string]): List of arguments.
            envp ([string]): List of environment variables.
            in_path (string): Input file path.
            ans_path (string): Answer file path.
            timelimit (int): Timelimit.
            memlimit (int): Memlimit.
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        with StackContext(Privilege.fileaccess):
            infile_fd = os.open(in_path, os.O_RDONLY | os.O_CLOEXEC)
            ansfile = open(ans_path, 'rb')
        outpipe_fd = os.pipe2(os.O_CLOEXEC)
        fcntl.fcntl(outpipe_fd[0], fcntl.F_SETFL, os.O_NONBLOCK)
        result_stat = None
        result_pass = None

        def _started_cb(task_id):
            '''Started callback.

            Close unused file descriptor after the task is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal infile_fd
            nonlocal outpipe_fd
            os.close(infile_fd)
            os.close(outpipe_fd[1])

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal result_stat
            nonlocal result_pass

            result_stat = (stat['utime'], stat['peakmem'],
                           stat['detect_error'])
            if result_pass is not None:
                callback((result_pass, result_stat))

        def _diff_out(evfd, events):
            '''Diff the output of the task.

            Args:
                evfd (int): Event file descriptor.
                events (int): Event flags.

            Returns:
                None

            '''

            nonlocal outpipe_fd
            nonlocal ansfile
            nonlocal result_stat
            nonlocal result_pass

            end_flag = False
            if events & IOLoop.READ:
                while True:
                    try:
                        data = os.read(outpipe_fd[0], 65536)
                    except BlockingIOError:
                        break
                    ansdata = ansfile.read(len(data))
                    if data != ansdata:
                        result_pass = False
                        end_flag = True
                        break
                    if len(ansdata) == 0:
                        if len(ansfile.read(1)) == 0:
                            result_pass = True
                        else:
                            result_pass = False
                        end_flag = True
                        break

            if (events & IOLoop.ERROR) or end_flag:
                if result_pass is None:
                    if len(ansfile.read(1)) == 0:
                        result_pass = True
                    else:
                        result_pass = False

                IOLoop.instance().remove_handler(evfd)
                os.close(outpipe_fd[0])
                ansfile.close()

                if result_stat is not None:
                    callback((result_pass, result_stat))

        StdChal.last_judge_uid += 1
        judge_uid = StdChal.last_judge_uid
        judge_gid = judge_uid

        with StackContext(Privilege.fileaccess):
            judge_path = self.chal_path + '/run_%d' % judge_uid
            os.mkdir(judge_path, mode=0o771)
            shutil.copyfile(src_path, judge_path + '/a.out', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(judge_path + '/a.out', judge_uid, judge_gid)
            os.chmod(judge_path + '/a.out', 0o500)

        IOLoop.instance().add_handler(outpipe_fd[0], _diff_out, \
            IOLoop.READ | IOLoop.ERROR)

        task_id = PyExt.create_task(exe_path, argv, envp, \
            infile_fd, outpipe_fd[1], outpipe_fd[1], \
            '/home/%d/run_%d'%(self.uniqid, judge_uid), 'container/standard', \
            judge_uid, judge_gid, timelimit, memlimit, \
            PyExt.RESTRICT_LEVEL_HIGH)

        if task_id is None:
            callback((False, (0, 0, PyExt.DETECT_INTERNALERR)))

        PyExt.start_task(task_id, _done_cb, _started_cb)
Beispiel #12
0
    def comp_make(self, callback):
        '''Makefile compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''
        def _copy_fn(src, dst, follow_symlinks=True):
            '''Copytree helper function.

            Args:
                src (string): Source path.
                dst (string): Destination path.
                follow_symlinks: Follow symbolic link or not.

            Returns:
                None

            '''

            shutil.copy(src, dst, follow_symlinks=False)
            with StackContext(Privilege.fullaccess):
                os.chown(dst, self.compile_uid, self.compile_gid)

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback(stat['detect_error'])

        with StackContext(Privilege.fileaccess):
            make_path = self.chal_path + '/compile'
            shutil.copytree(self.res_path + '/make', make_path, symlinks=True, \
                copy_function=_copy_fn)
            shutil.copyfile(self.code_path, make_path + '/main.cpp', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(make_path, self.compile_uid, self.compile_gid)
            os.chmod(make_path, mode=0o770)

        task_id = PyExt.create_task('/usr/bin/make', \
            [], \
            [
                'PATH=/usr/bin',
                'TMPDIR=/home/%d/compile'%self.uniqid,
                'OUT=./a.out',
            ], \
            StdChal.null_fd, StdChal.null_fd, StdChal.null_fd, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 256 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(-1)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #13
0
    def comp_python(self, callback=None):
        '''Python3.4 compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _started_cb(task_id):
            '''Started callback.

            Close unused file descriptors after the task is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal errpipe_fd

            os.close(errpipe_fd)

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal compile_path

            with StackContext(Privilege.fileaccess):
                verfile = open(compile_path + '/verdict.txt', 'r')
                verdict = verfile.read(140)
                verfile.close()
            callback((stat['detect_error'], verdict))

        compile_path = self.chal_path + '/compile'
        with StackContext(Privilege.fileaccess):
            os.mkdir(compile_path, mode=0o770)
            shutil.copyfile(self.code_path, compile_path + '/test.py', \
                follow_symlinks=False)
        FileUtils.setperm(compile_path, self.compile_uid, self.compile_gid)

        with StackContext(Privilege.fileaccess):
            errpipe_fd = os.open(compile_path + '/verdict.txt', \
                os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC, mode=0o440)

        task_id = PyExt.create_task('/usr/bin/python3.4', \
            [
                '-m',
                'py_compile',
                './test.py'
            ], \
            [
                'HOME=/home/%d/compile'%self.uniqid,
                'LANG=en_US.UTF-8'
            ], \
            {
                0: StdChal.null_fd,
                1: StdChal.null_fd,
                2: errpipe_fd,
            }, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            os.close(errpipe_fd)
            callback((PyExt.DETECT_INTERNALERR, ''))
            return

        PyExt.start_task(task_id, _done_cb, _started_cb)
Beispiel #14
0
    def comp_cxx(self, callback=None):
        '''GCC, Clang compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _started_cb(task_id):
            '''Started callback.

            Close unused file descriptors after the task is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal errpipe_fd

            os.close(errpipe_fd)

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal compile_path

            with StackContext(Privilege.fileaccess):
                verfile = open(compile_path + '/verdict.txt', 'rb')
                # To fix decoding error.
                # Force convert the binary string to string temporarily.
                verdict = ''.join(chr(c) for c in verfile.read(140))
                verfile.close()
            callback((stat['detect_error'], verdict))

        compile_path = self.chal_path + '/compile'
        with StackContext(Privilege.fileaccess):
            os.mkdir(compile_path, mode=0o770)
            shutil.copyfile(self.code_path, compile_path + '/test.cpp', \
                follow_symlinks=False)
        FileUtils.setperm(compile_path, self.compile_uid, self.compile_gid)

        with StackContext(Privilege.fileaccess):
            errpipe_fd = os.open(compile_path + '/verdict.txt', \
                os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC, mode=0o440)

        if self.comp_typ == 'g++':
            compiler = '/usr/bin/g++'
        elif self.comp_typ == 'clang++':
            compiler = '/usr/bin/clang++'

        task_id = PyExt.create_task(compiler, \
            [
                '-O2',
                '-std=c++14',
                '-o', './a.out',
                './test.cpp',
            ], \
            [
                'PATH=/usr/bin:/bin',
                'TMPDIR=/home/%d/compile'%self.uniqid,
            ], \
            {
                0: StdChal.null_fd,
                1: StdChal.null_fd,
                2: errpipe_fd,
            }, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            os.close(errpipe_fd)
            callback((PyExt.DETECT_INTERNALERR, ''))
            return

        PyExt.start_task(task_id, _done_cb, _started_cb)
Beispiel #15
0
    def comp_make(self, callback):
        '''Makefile compile.

        Args:
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _copy_fn(src, dst, follow_symlinks=True):
            '''Copytree helper function.

            Args:
                src (string): Source path.
                dst (string): Destination path.
                follow_symlinks: Follow symbolic link or not.

            Returns:
                None

            '''

            shutil.copy(src, dst, follow_symlinks=False)
            with StackContext(Privilege.fullaccess):
                os.chown(dst, self.compile_uid, self.compile_gid)

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            callback(stat['detect_error'])

        with StackContext(Privilege.fileaccess):
            make_path = self.chal_path + '/compile'
            shutil.copytree(self.res_path + '/make', make_path, symlinks=True, \
                copy_function=_copy_fn)
            shutil.copyfile(self.code_path, make_path + '/main.cpp', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(make_path, self.compile_uid, self.compile_gid)
            os.chmod(make_path, mode=0o770)

        task_id = PyExt.create_task('/usr/bin/make', \
            [], \
            [
                'PATH=/usr/bin',
                'TMPDIR=/home/%d/compile'%self.uniqid,
                'OUT=./a.out',
            ], \
            StdChal.null_fd, StdChal.null_fd, StdChal.null_fd, \
            '/home/%d/compile'%self.uniqid, 'container/standard', \
            self.compile_uid, self.compile_gid, 60000, 256 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(-1)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #16
0
    def build(self, build_ugid, res_path, callback=None):
        '''Build environment.

        Args:
            build_ugid ((int, int)): Build UID/GID.
            res_path (string): Resource path.
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _done_cb(task_id, stat):
            '''Done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            if stat['detect_error'] == PyExt.DETECT_NONE:
                callback(True)
            else:
                callback(False)

        build_uid, build_gid = build_ugid

        # Prepare build environment.
        FileUtils.copydir(res_path + '/check', self.build_path)
        FileUtils.setperm(self.build_path, build_uid, build_gid)
        with StackContext(Privilege.fullaccess):
            os.chmod(self.build_path, mode=0o770)

        with StackContext(Privilege.fileaccess):
            if not os.path.isfile(self.build_path + '/build'):
                callback(True)
                return
        
        # Make the build file executable.
        with StackContext(Privilege.fullaccess):
            os.chmod(self.build_path + '/build', mode=0o770)

        # Build.
        task_id = PyExt.create_task(self.build_relpath + '/build', \
            [], \
            [
                'PATH=/usr/bin:/bin',
                'TMPDIR=%s'%self.build_relpath,
                'HOME=%s'%self.build_relpath,
                'LANG=en_US.UTF-8'
            ], \
            {
                0: StdChal.null_fd,
                1: StdChal.null_fd,
                2: StdChal.null_fd,
            }, \
            self.build_relpath, 'container/standard', \
            build_uid, build_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if task_id is None:
            callback(False)
        else:
            PyExt.start_task(task_id, _done_cb)
Beispiel #17
0
    def judge(self, src_path, exe_relpath, argv, envp, check_ugid, test_ugid, \
        test_relpath, test_param, metadata, callback=None):
        '''I/O redirect special judge.

        Args:
            src_path (string): Executable source path.
            exe_relpath (string): Executable or interpreter path in the sandbox.
            argv ([string]): List of arguments.
            envp ([string]): List of environment variables.
            check_ugid (int, int): Check UID/GID.
            test_ugid (int, int): Test UID/GID.
            test_relpath (string): Test relative path.
            test_param (dict): Test parameters.
            metadata (dict): Metadata.
            callback (function): Callback of return_future.

        Returns:
            None

        '''

        def _check_started_cb(task_id):
            '''Check started callback.

            Close unused file descriptors after the check is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal inpipe_fd
            nonlocal outpipe_fd
            nonlocal ansfile_fd
            nonlocal check_infile_fd

            os.close(inpipe_fd[1])
            os.close(outpipe_fd[0])
            if ansfile_fd is not None:
                os.close(ansfile_fd)
            if check_infile_fd is not None:
                os.close(check_infile_fd)

        def _test_started_cb(task_id):
            '''Test started callback.

            Close unused file descriptors after the test is started.

            Args:
                task_id (int): Task ID.

            Returns:
                None

            '''

            nonlocal inpipe_fd
            nonlocal outpipe_fd
            nonlocal outfile_fd
            nonlocal test_infile_fd

            os.close(inpipe_fd[0])
            os.close(outpipe_fd[1])
            os.close(outfile_fd)
            if test_infile_fd is not None:
                os.close(test_infile_fd)

        def _done_cb():
            '''Done callback.'''

            nonlocal result_stat
            nonlocal result_pass
            nonlocal verdict_path

            if result_pass is not None and result_stat is not None:
                with StackContext(Privilege.fileaccess):
                    verfile = open(verdict_path, 'r')
                    verdict = verfile.read(140)
                    verfile.close()
                callback((result_pass, result_stat, verdict))
                return

        def _check_done_cb(task_id, stat):
            '''Check done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal result_pass

            if stat['detect_error'] == PyExt.DETECT_NONE:
                result_pass = True
            else:
                result_pass = False
            _done_cb()

        def _test_done_cb(task_id, stat):
            '''Test done callback.

            Args:
                task_id (int): Task ID.
                stat (dict): Task result.

            Returns:
                None

            '''

            nonlocal result_stat

            result_stat = (stat['utime'], stat['peakmem'], stat['detect_error'])
            _done_cb()

        result_stat = None
        result_pass = None
        in_path = test_param['in']
        ans_path = test_param['ans']
        timelimit = test_param['timelimit']
        memlimit = test_param['memlimit']
        check_uid, check_gid = check_ugid
        test_uid, test_gid = test_ugid

        test_path = self.container_path + test_relpath
        output_relpath = test_relpath + '/output.txt'
        output_path = self.container_path + output_relpath
        verdict_relpath = test_relpath + '/verdict.txt'
        verdict_path = self.container_path + verdict_relpath

        # Prepare test environment.
        with StackContext(Privilege.fileaccess):
            os.mkdir(test_path, mode=0o771)
            shutil.copyfile(src_path, test_path + '/a.out', \
                follow_symlinks=False)
        with StackContext(Privilege.fullaccess):
            os.chown(test_path + '/a.out', test_uid, test_gid)
            os.chmod(test_path + '/a.out', 0o500)

        # Prepare I/O.
        with StackContext(Privilege.fileaccess):
            try:
                check_infile_fd = os.open(in_path, os.O_RDONLY | os.O_CLOEXEC)
                test_infile_fd = os.open(in_path, os.O_RDONLY | os.O_CLOEXEC)
            except (FileNotFoundError, TypeError):
                check_infile_fd = None
                test_infile_fd = None
            try:
                ansfile_fd = os.open(ans_path, os.O_RDONLY | os.O_CLOEXEC)
            except (FileNotFoundError, TypeError):
                ansfile_fd = None
            outfile_fd = os.open(output_path, \
                os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC, mode=0o400)
            os.close(os.open(verdict_path,
                os.O_CREAT | os.O_CLOEXEC, mode=0o640))
        with StackContext(Privilege.fullaccess):
            os.chown(output_path, check_uid, check_gid)
            os.chown(verdict_path, check_uid, check_gid)

        inpipe_fd = os.pipe2(os.O_CLOEXEC)
        outpipe_fd = os.pipe2(os.O_CLOEXEC)

        # Set file descriptor mapping.
        check_fdmap = {
            0: StdChal.null_fd,
            1: StdChal.null_fd,
            2: StdChal.null_fd,
        }
        test_fdmap = {
            0: StdChal.null_fd,
            1: StdChal.null_fd,
            2: StdChal.null_fd,
        }
        if check_infile_fd is not None:
            check_fdmap[metadata['redir_check']['testin']] = check_infile_fd
        if ansfile_fd is not None:
            check_fdmap[metadata['redir_check']['ansin']] = ansfile_fd
        check_fdmap[metadata['redir_check']['pipein']] = inpipe_fd[1]
        check_fdmap[metadata['redir_check']['pipeout']] = outpipe_fd[0]
        try:
            del check_fdmap[-1]
        except KeyError:
            pass
        if test_infile_fd is not None:
            test_fdmap[metadata['redir_test']['testin']] = test_infile_fd
        test_fdmap[metadata['redir_test']['testout']] = outfile_fd
        test_fdmap[metadata['redir_test']['pipein']] = inpipe_fd[0]
        test_fdmap[metadata['redir_test']['pipeout']] = outpipe_fd[1]
        try:
            del test_fdmap[-1]
        except KeyError:
            pass

        check_task_id = PyExt.create_task(self.build_relpath + '/check', \
            [], \
            [
                'PATH=/usr/bin:/bin',
                'HOME=%s'%self.build_relpath,
                'LANG=en_US.UTF-8',
                'OUTPUT=%s'%output_relpath,
                'VERDICT=%s'%verdict_relpath,
            ], \
            check_fdmap, \
            self.build_relpath, self.container_path, \
            check_uid, check_gid, 60000, 1024 * 1024 * 1024, \
            PyExt.RESTRICT_LEVEL_LOW)

        if check_task_id is None:
            callback((False, (0, 0, PyExt.DETECT_INTERNALERR), ''))
            return
        PyExt.start_task(check_task_id, _check_done_cb, _check_started_cb)

        test_task_id = PyExt.create_task(exe_relpath, argv, envp, \
            test_fdmap, \
            test_relpath, self.container_path, \
            test_uid, test_gid, timelimit, memlimit, \
            PyExt.RESTRICT_LEVEL_HIGH)

        if test_task_id is None:
            callback((False, (0, 0, PyExt.DETECT_INTERNALERR), ''))
            return
        PyExt.start_task(test_task_id, _test_done_cb, _test_started_cb)