Skip to content

Commit

Permalink
cptbox: implement proper sys_utimensat sandboxing
Browse files Browse the repository at this point in the history
  • Loading branch information
quantum5 committed Sep 18, 2021
1 parent ddaa53e commit 1286806
Showing 1 changed file with 31 additions and 2 deletions.
33 changes: 31 additions & 2 deletions dmoj/executors/compiled_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
import hashlib
import os
import pty
import struct
import sys
from typing import Dict, List, Optional, Sequence

import pylru

from dmoj.cptbox import IsolateTracer, TracedPopen
from dmoj.cptbox._cptbox import AT_FDCWD
from dmoj.cptbox.filesystem_policies import ExactFile, FilesystemAccessRule, RecursiveDir
from dmoj.cptbox.handlers import ALLOW
from dmoj.cptbox.handlers import ACCESS_EFAULT, ACCESS_EPERM, ALLOW
from dmoj.cptbox.syscalls import *
from dmoj.error import CompileError, OutputLimitExceeded
from dmoj.executors.base_executor import BaseExecutor
Expand Down Expand Up @@ -72,6 +74,9 @@ def __call__(self, *args, **kwargs) -> 'CompiledExecutor':
return obj


UTIME_OMIT = (1 << 30) - 2


class CompilerIsolateTracer(IsolateTracer):
def __init__(self, tmpdir, read_fs, write_fs, *args, **kwargs):
read_fs += BASE_FILESYSTEM + [
Expand Down Expand Up @@ -108,7 +113,7 @@ def handle_execve(debugger):
# FIXME: Mono breaks if we don't implement Linux's special
# handling for UTIME_OMIT. This is undocumented but nonethelss
# relied on.
sys_utimensat: ALLOW,
sys_utimensat: self.do_utimensat,
sys_statx: self.check_file_access_at('statx'),
sys_umask: ALLOW,
sys_flock: ALLOW,
Expand Down Expand Up @@ -171,6 +176,30 @@ def handle_execve(debugger):
}
)

def do_utimensat(self, debugger) -> bool:
timespec = struct.Struct({32: '=ii', 64: '=QQ'}[debugger.address_bits])

try:
buffer = debugger.readbytes(debugger.uarg2, timespec.size * 2)
except OSError as e:
return ACCESS_EFAULT(debugger)

times = list(timespec.iter_unpack(buffer))
if times[0][1] == UTIME_OMIT and times[1][1] == UTIME_OMIT:
debugger.syscall = -1

def on_return():
debugger.result = 0

debugger.on_return(on_return)
return True

if debugger.uarg0 != AT_FDCWD and not debugger.uarg1:
path = self._getfd_pid(debugger.tid, debugger.uarg0)
return True if self.write_fs_jail.check(path) else ACCESS_EPERM(debugger)

return self.check_file_access_at('utimensat')(debugger)


class CompiledExecutor(BaseExecutor, metaclass=_CompiledExecutorMeta):
executable_size = env.compiler_size_limit * 1024
Expand Down

0 comments on commit 1286806

Please sign in to comment.