示例#1
0
 def __init__(self):
     self.control = os.fdopen(CONTROL_FD, 'w+', 0)
     shmem = self.shmem_open()
     self.trustedthread = TrustedThread(sys.argv[1], THREAD_FD, shmem)
     memory_mappings = self.trustedthread.get_protected_sections()
     self.security = security.SecurityManager(memory_mappings)
示例#2
0
 def __init__(self):
     self.control = os.fdopen(CONTROL_FD, 'w+', 0)
     shmem = self.shmem_open()
     self.trustedthread = TrustedThread(sys.argv[1], THREAD_FD, shmem)
     memory_mappings = self.trustedthread.get_protected_sections()
     self.security = security.SecurityManager(memory_mappings)
示例#3
0
class HybridSandbox:
    def __init__(self):
        self.control = os.fdopen(CONTROL_FD, 'w+', 0)
        shmem = self.shmem_open()
        self.trustedthread = TrustedThread(sys.argv[1], THREAD_FD, shmem)
        memory_mappings = self.trustedthread.get_protected_sections()
        self.security = security.SecurityManager(memory_mappings)

    def shmem_open(self):
        self.shmemfd = open(SHMEM_FILENAME, 'w+')
        self.shmemfd.truncate(SHMEM_SIZE)
        return mmap.mmap(self.shmemfd.fileno(), 0)

    def syscall_request(self):
        sandboxlog.debug('syscall request ringing...')
        msg = self.control.read(7*4)
        mm = Memory.parse(msg)
        sandboxlog.debug('>>> %s' % mm)
        return self.do(mm)

    def do(self, mm):
        if not mm.eax in syscalls_table:
            sandboxlog.error('syscall %s [nr=%#x] not implemented' % (syscalls.syscallnr2human.get(mm.eax, ('???')), mm.eax))
            return 0
        func = syscalls_table.get(mm.eax)
        registers = mm.aslist()[1:func.argc+1]
        return func(self, *registers)

    @syscall('NR_open')
    def open(self, filename_ptr, perms, mode):
        if not self.security.is_valid(filename_ptr):
            return -1
        filename = self.peek_asciiz(filename_ptr)
        if not self.security.open(filename, perms, mode):
            return -1
        args = Memory(eax=syscalls.NR_open,
                      ebx=filename,
                      ecx = perms,
                      edx = mode)
        ret = self.trustedthread.delegate(args)
        if ret < 0x80000000:
            self.security.register_descriptor(ret, filename)
        return ret

    @syscall('NR_close')
    def close(self, fd):
        if not self.security.close(fd):
            return -1
        args = Memory(eax=syscalls.NR_close,
                      ebx=fd)
        ret = self.trustedthread.delegate(args)
        if ret == 0:
            self.security.unregister_descriptor(fd)
        return ret

    @syscall('NR_access')
    def access(self, path_ptr, mode):
        if not self.security.is_valid(path_ptr):
            return (-1, EACCES)
        path = self.peek_asciiz(path_ptr)
        if not self.security.access(path, mode):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_access,
                      ebx=path,
                      ecx=mode)
        return self.trustedthread.delegate(args)

    @syscall('NR_getcwd')
    def getcwd(self, path_ptr):
        if not self.security.getcwd(path_ptr):
            return (0, EFAULT)
        args = Memory(eax=syscalls.NR_getcwd, ebx=path_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_getpgrp')
    def getpgrp(self):
        if not self.security.getpgrp():
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_getpgrp)
        return self.trustedthread.delegate(args)

    @syscall('NR_getpid')
    def getpid(self):
        return int(self.trustedthread.pid)

    @syscall('NR_gettimeofday')
    def gettimeofday(self, tv_ptr, tz_ptr):
        if not self.security.gettimeofday(tv_ptr, tz_ptr):
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_gettimeofday, ebx=tv_ptr, ecx=tz_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_exit')
    def exit(self, val):
        args = Memory(eax=syscalls.NR_exit_group, ebx=val)
        sandboxlog.info('EXIT')
        self.control.write(struct.pack('II', NATIVE_EXIT, val))
        self.control.flush()
        self.trustedthread.delegate(args, willexit=True)
        sys.exit(val)

    @syscall('NR_ioctl')
    def ioctl(self, fd, request):
        sandboxlog.debug('ioctl(%d, %#x)' % (fd, request))
        ## we should eventually support some ioctl but for the moment
        ## let's simulate a success :)
        return 0

    @syscall('NR_lseek')
    def lseek(self, fd, offset, whence):
        if not self.security.lseek(fd, offset, whence):
            return (-1, EBADF)
        args = Memory(eax=syscalls.NR_lseek,
                      ebx=fd,
                      ecx=offset,
                      edx=whence)
        return self.trustedthread.delegate(args)

    @syscall('NRllseek')
    def llseek(self, fd, offset_high, offset_low, result, whence):
        if not self.security.llseek(fd, offset_high, offset_low, result, whence):
            return (-1, EBADF)
        args = Memory(eax=syscalls.NRllseek,
                      ebx=fd,
                      ecx=offset_high,
                      edx=offset_low,
                      esi=result,
                      edi=whence)
        return self.trustedthread.delegate(args)

    @syscall('NR_readlink')
    def readlink(self, path_ptr):
        if not self.security.readlink(path_ptr):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_readlink, ebx=path_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_stat64')
    def stat64(self, path_ptr, addr):
        if not self.security.is_valid(path_ptr):
            return (-1, EACCES)
        path = self.peek_asciiz(path_ptr)
        if not self.security.stat64(path, addr):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_stat64,
                      ebx=path,
                      ecx=addr)
        return self.trustedthread.delegate(args)

    @syscall('NR_fstat64')
    def fstat64(self, fd, ptr):
        if not self.security.fstat(fd, ptr):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_fstat64,
                      ebx=fd,
                      ecx=ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_mmap2')
    def mmap2(self, addr, length, prot, flags, fd, pgoffset):
        if not self.security.mmap2(addr, length, prot, flags, fd, pgoffset):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_mmap2,
                      ebx=addr,
                      ecx=length,
                      edx=prot,
                      esi=flags,
                      edi=fd,
                      ebp=pgoffset)
        return self.trustedthread.delegate(args)

    @syscall('NR_mmap')
    def mmap(self, addr, length, prot, flags, fd, offset):
        if not self.security.mmap(addr, length, prot, flags, fd, offset):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_mmap,
                      ebx=addr,
                      ecx=length,
                      edx=prot,
                      esi=flags,
                      edi=fd,
                      ebp=offset)
        return self.trustedthread.delegate(args)

    @syscall('NR_brk')
    def brk(self, addr):
        if not self.security.brk(addr):
            return (-1, ENOMEM)
        args = Memory(eax=syscalls.NR_brk, ebx=addr)
        return self.trustedthread.delegate(args)

    @syscall('NR_ugetrlimit')
    def ugetrlimit(self, ptr):
        if not self.security.ugetrlimit(ptr):
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_ugetrlimit, ebx=ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_munmap')
    def munmap(self, addr, length):
        if not self.security.munmap(addr, length):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_munmap,
                      ebx=addr,
                      ecx=length)
        return self.trustedthread.delegate(args)

    @syscall('NR_rt_sigaction')
    def rt_sigaction(self, signum, ptr, oldptr):
        ## signals will never be supported so we cross our fingers and
        ## let the caller believe the syscall succeed
        return 0

    @syscall('NR_sigaction')
    def sigaction(self, signum, ptr, oldptr):
        ## signals will never be supported so we cross our fingers and
        ## let the caller believe the syscall succeed
        return 0

    @mux_syscall('NR_socketcall', 'SYS_SOCKET')
    def _socket(self, domain, type, protocol):
        if not self.security.socket(domain, type, protocol):
            return (-1, EACCESS)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_SOCKET,
                      ecx=struct.pack('3I', domain, type, protocol))
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_CONNECT')
    def _connect(self, sockfd, addr_ptr, addrlen):
        if not self.security.connect(sockfd, addr_ptr, addrlen):
            return (-1, EACCESS)
        tubelog.debug(hex(addr_ptr))
        addr = self.peek_memory(addr_ptr, addrlen)
        ptr  = self.trustedthread.push_volatile(addr)
        structure = struct.pack('III', sockfd, ptr, addrlen)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_CONNECT,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_RECVMSG')
    def _recvmsg(self, sockfd, ptr, flags):
        if not self.security.is_valid(ptr, sizeof.sockaddr):
            return (-1, EACCESS)
        buf = self.peek_memory(ptr, 28) # XXX sizeof(struct msghdr)
        if not self.security.recvmsg(sockfd, buf, flags):
            return (-1, EACCESS)
        ptr = self.trustedthread.push_volatile(buf)
        structure = struct.pack('III', sockfd, ptr, flags)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_RECVMSG,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_SENDTO')
    def _sendto(self, sockfd, ptr, buflen, flags):
        if not self.security.is_valid(ptr, buflen):
            return (-1, EACCESS)
        buf = self.peek_memory(ptr, buflen)
        if not self.security.sendto(sockfd, buf, flags):
            return (-1, EACCESS)
        ptr = self.trustedthread.push_volatile(buf)
        structure = struct.pack('IIII', sockfd, ptr, buflen, flags)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_SENDTO,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_BIND')
    def _bind(self, sockfd, ptr, addrlen):
        if not self.security.is_valid(ptr, addrlen):
            return (-1, EACCESS)
        addr = self.peek_memory(ptr, addrlen)
        if not self.security.bind(sockfd, addr):
            return (-1, EACCESS)
        ptr = self.trustedthread.push_volatile(addr)
        structure = struct.pack('III', sockfd, ptr, addrlen)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_BIND,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_GETSOCKNAME')
    def _getsockname(self, sockfd, ptr, addrlen):
        if not self.security.getsockname(sockfd, ptr, addrlen):
            return (-1, EACCES)
        structure = struct.pack('III', sockfd, ptr, addrlen)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_GETSOCKNAME,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_SOCKETPAIR')
    def _socketpair(self, domain, type, protocol, fdpair_ptr):
        if not (self.security.is_valid(fdpair_ptr, 8)
                and self.security.socket(domain, type, protocol)):
            return (-1, EACCES)
        structure = struct.pack('IIII', domain, type, protocol, fdpair_ptr)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_SOCKETPAIR,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_LISTEN')
    def _listen(self, sockfd, backlog):
        structure = struct.pack('II', sockfd, backlog)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_LISTEN,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_ACCEPT')
    def _accept(self, sockfd, sockadr_ptr, addrlen_ptr):
        if not self.security.is_valid(addrlen_ptr):
            return (-1, EACCES)
        addrlen = struct.unpack('I', self.peek_memory(addrlen_ptr, 4))[0]
        if not self.security.is_valid(sockadr_ptr, addrlen):
            return (-1, EACCES)
        structure = struct.pack('III', sockfd, sockadr_ptr, addrlen_ptr)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_ACCEPT,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @syscall('NR_socketcall')
    def socketcall(self, call, ptr):
        if call not in mux_syscall_tables[syscalls.NR_socketcall]:
            sandboxlog.error('socketcall(call=#%d) not implemented *************************************************************' % call)
            return 0
        func = mux_syscall_tables[syscalls.NR_socketcall][call]
        structsize = 4*func.argc
        if not self.security.is_valid(ptr, structsize):
            return (-1, EACCES)
        buf = self.peek_memory(ptr, structsize)
        args = struct.unpack('L'*func.argc, buf)
        return func(self, *args)

    @syscall('NR_time')
    def time(self, time_ptr):
        if not self.security.time(time_ptr):
            return (-1, EFAULT)
        args = Memory(eax=syscalls.NR_time, ebx=time_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_times')
    def times(self, bufptr):
        if not self.security.times(bufptr):
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_times, ebx=tms_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_getuid32')
    def getuid32(self):
        return 1000

    @syscall('NR_geteuid32')
    def geteuid32(self):
        return 1000

    @syscall('NR_getgid32')
    def getgid32(self):
        return 1000

    @syscall('NR_getegid32')
    def getegid32(self):
        return 1000

    @syscall('NR_epoll_create')
    def epoll_create(self, size):
        if not self.security.epoll_create(size):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_epoll_create,
                      ebx=size)
        return self.trustedthread.delegate(args)

    @syscall('NR_fcntl64')
    def fcntl64(self, fd, cmd, args_list):
        if not self.security.fcntl64(fd, cmd, args_list):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_fcntl64,
                      ebx=fd,
                      ecx=cmd,
                      edx=args_list)
        return self.trustedthread.delegate(args)

    @syscall('NR_epoll_ctl')
    def epoll_ctl(self, epollfd, op, fd, event_ptr):
        if not self.security.is_valid(event_ptr, sizeof.event):
            return (-1, EACCES)
        event = self.peek_memory(event_ptr, sizeof.event)
        args = Memory(eax=syscalls.NR_epoll_ctl,
                      ebx=epollfd,
                      ecx=op,
                      edx=fd,
                      esi=event)
        return self.trustedthread.delegate(args)

    @syscall('NR_epoll_wait')
    def epoll_wait(self, epollfd, event_ptr, max_events, timeout):
        if not self.security.is_valid(event_ptr, sizeof.event):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_epoll_wait,
                      ebx=epollfd,
                      ecx=event_ptr,
                      edx=max_events,
                      esi=timeout)
        return self.trustedthread.delegate(args)

    @syscall('NR_eventfd2')
    def eventfd2(self, initval, flags):
        args = Memory(eax=syscalls.NR_eventfd2,
                      ebx=initval,
                      ecx=flags)
        return self.trustedthread.delegate(args)

    @syscall('NR_readv')
    def readv(self, fd, iovptr, iovcnt):
        iovs = self.get_iov(iovptr, iovcnt)
        s = ''.join(iovs)
        args = Memory(eax=syscalls.NR_readv,
                      ebx=fd,
                      ecx=s,
                      edx=len(iovs))
        return self.trustedthread.delegate(args)

    @syscall('NR_writev')
    def writev(self, fd, iovptr, iovcnt):
        iovs = self.get_iov(iovptr, iovcnt)
        s = ''.join(iovs)
        args = Memory(eax=syscalls.NR_writev,
                      ebx=fd,
                      ecx=s,
                      edx=len(iovs))
        return self.trustedthread.delegate(args)

    @syscall('NR_sendfile')
    def sendfile(self, outfd, infd, offset_ptr, count):
        if not self.security.sendfile(outfd, infd, offset_ptr, count):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_sendfile,
                      ebx=outfd,
                      ecx=infd,
                      edx=offset_ptr,
                      esi=count)
        return self.trustedthread.delegate(args)

    @syscall('NR_getdents')
    def getdents(self, fd, dirp_ptr, count):
        if not self.security.is_valid(dirp_ptr, sizeof.linux_dirent):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_getdents,
                      ebx=fd,
                      ecx=dirp_ptr,
                      edx=count)
        return self.trustedthread.delegate(args)

    def op_retval(self, ret, errno=0):
        tubelog.debug('<<< op_retval(%#x, %d)' % (ret,errno))
        self.control.write(struct.pack('III', RETVAL, ret & 0xffffffff, errno))
        return ret

    def raisetrap(self):
        self.control.write(struct.pack('I', RAISE_TRAP))

    def get_iov(self, ptr, count):
        array=[]
        while count > 0:
            iov = self.peek_memory(ptr, sizeof.iovec)
            iov_base, iov_len = struct.unpack('II', iov)
            if self.security.is_valid(iov_base, iov_len):
                array.append(iov)
            count -= 1
            ptr += sizeof.iovec
        return array

    def peek_asciiz(self, ptr):
        tubelog.debug('<<< peek_asciiz(%#x)' % ptr)
        self.control.write(struct.pack('II', PEEK_ASCIIZ, ptr))
        buf = self.control.read(4)
        nbytes = struct.unpack('I', buf)[0]
        tubelog.debug('    Waiting for %d bytes' % nbytes)
        buf = self.control.read(nbytes)
        tubelog.debug('>>> ' + buf)
        return buf

    def peek_memory(self, ptr, length):
        tubelog.debug('<<< peek_memory(%#x, %d)' % (ptr, length))
        self.control.write(struct.pack('III', PEEK_MEMORY, ptr, length))
        buf = self.control.read(length)
        tubelog.debug('>>> ' + buf.encode('hex'))
        return buf

    def poke_memory(self, addr, buf):
        length = len(buf)
        tubelog.debug('<<< poke_memory(%#x, "...") len=%d' % (addr, length))
        self.control.write(struct.pack('III', POKE_MEMORY, addr, length))
        written=0
        while written < length:
            written += self.control.write(buf[written:])

    def dispatcher(self, rawtype):
        msgtype = struct.unpack('I', rawtype)[0]
        if msgtype == DO_SYSCALL:
            ret = self.syscall_request()
            if type(ret) is tuple:
                ret,errno=ret
            else:
                errno=0
            self.op_retval(ret, errno)
        else:
            tubelog.error('Unknown message type: %#x' % msgtype)

    def run(self):
        while True:
            buf = os.read(CONTROL_FD, 4)
            if not buf:
                break
            self.dispatcher(buf)
示例#4
0
class HybridSandbox:
    def __init__(self):
        self.control = os.fdopen(CONTROL_FD, 'w+', 0)
        shmem = self.shmem_open()
        self.trustedthread = TrustedThread(sys.argv[1], THREAD_FD, shmem)
        memory_mappings = self.trustedthread.get_protected_sections()
        self.security = security.SecurityManager(memory_mappings)

    def shmem_open(self):
        self.shmemfd = open(SHMEM_FILENAME, 'w+')
        self.shmemfd.truncate(SHMEM_SIZE)
        return mmap.mmap(self.shmemfd.fileno(), 0)

    def syscall_request(self):
        sandboxlog.debug('syscall request ringing...')
        msg = self.control.read(7 * 4)
        mm = Memory.parse(msg)
        sandboxlog.debug('>>> %s' % mm)
        return self.do(mm)

    def do(self, mm):
        if not mm.eax in syscalls_table:
            sandboxlog.error('syscall %s [nr=%#x] not implemented' %
                             (syscalls.syscallnr2human.get(mm.eax,
                                                           ('???')), mm.eax))
            return 0
        func = syscalls_table.get(mm.eax)
        registers = mm.aslist()[1:func.argc + 1]
        return func(self, *registers)

    @syscall('NR_open')
    def open(self, filename_ptr, perms, mode):
        if not self.security.is_valid(filename_ptr):
            return -1
        filename = self.peek_asciiz(filename_ptr)
        if not self.security.open(filename, perms, mode):
            return -1
        args = Memory(eax=syscalls.NR_open, ebx=filename, ecx=perms, edx=mode)
        ret = self.trustedthread.delegate(args)
        if ret < 0x80000000:
            self.security.register_descriptor(ret, filename)
        return ret

    @syscall('NR_close')
    def close(self, fd):
        if not self.security.close(fd):
            return -1
        args = Memory(eax=syscalls.NR_close, ebx=fd)
        ret = self.trustedthread.delegate(args)
        if ret == 0:
            self.security.unregister_descriptor(fd)
        return ret

    @syscall('NR_access')
    def access(self, path_ptr, mode):
        if not self.security.is_valid(path_ptr):
            return (-1, EACCES)
        path = self.peek_asciiz(path_ptr)
        if not self.security.access(path, mode):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_access, ebx=path, ecx=mode)
        return self.trustedthread.delegate(args)

    @syscall('NR_getcwd')
    def getcwd(self, path_ptr):
        if not self.security.getcwd(path_ptr):
            return (0, EFAULT)
        args = Memory(eax=syscalls.NR_getcwd, ebx=path_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_getpgrp')
    def getpgrp(self):
        if not self.security.getpgrp():
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_getpgrp)
        return self.trustedthread.delegate(args)

    @syscall('NR_getpid')
    def getpid(self):
        return int(self.trustedthread.pid)

    @syscall('NR_gettimeofday')
    def gettimeofday(self, tv_ptr, tz_ptr):
        if not self.security.gettimeofday(tv_ptr, tz_ptr):
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_gettimeofday, ebx=tv_ptr, ecx=tz_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_exit')
    def exit(self, val):
        args = Memory(eax=syscalls.NR_exit_group, ebx=val)
        sandboxlog.info('EXIT')
        self.control.write(struct.pack('II', NATIVE_EXIT, val))
        self.control.flush()
        self.trustedthread.delegate(args, willexit=True)
        sys.exit(val)

    @syscall('NR_ioctl')
    def ioctl(self, fd, request):
        sandboxlog.debug('ioctl(%d, %#x)' % (fd, request))
        ## we should eventually support some ioctl but for the moment
        ## let's simulate a success :)
        return 0

    @syscall('NR_lseek')
    def lseek(self, fd, offset, whence):
        if not self.security.lseek(fd, offset, whence):
            return (-1, EBADF)
        args = Memory(eax=syscalls.NR_lseek, ebx=fd, ecx=offset, edx=whence)
        return self.trustedthread.delegate(args)

    @syscall('NRllseek')
    def llseek(self, fd, offset_high, offset_low, result, whence):
        if not self.security.llseek(fd, offset_high, offset_low, result,
                                    whence):
            return (-1, EBADF)
        args = Memory(eax=syscalls.NRllseek,
                      ebx=fd,
                      ecx=offset_high,
                      edx=offset_low,
                      esi=result,
                      edi=whence)
        return self.trustedthread.delegate(args)

    @syscall('NR_readlink')
    def readlink(self, path_ptr):
        if not self.security.readlink(path_ptr):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_readlink, ebx=path_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_stat64')
    def stat64(self, path_ptr, addr):
        if not self.security.is_valid(path_ptr):
            return (-1, EACCES)
        path = self.peek_asciiz(path_ptr)
        if not self.security.stat64(path, addr):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_stat64, ebx=path, ecx=addr)
        return self.trustedthread.delegate(args)

    @syscall('NR_fstat64')
    def fstat64(self, fd, ptr):
        if not self.security.fstat(fd, ptr):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_fstat64, ebx=fd, ecx=ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_mmap2')
    def mmap2(self, addr, length, prot, flags, fd, pgoffset):
        if not self.security.mmap2(addr, length, prot, flags, fd, pgoffset):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_mmap2,
                      ebx=addr,
                      ecx=length,
                      edx=prot,
                      esi=flags,
                      edi=fd,
                      ebp=pgoffset)
        return self.trustedthread.delegate(args)

    @syscall('NR_mmap')
    def mmap(self, addr, length, prot, flags, fd, offset):
        if not self.security.mmap(addr, length, prot, flags, fd, offset):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_mmap,
                      ebx=addr,
                      ecx=length,
                      edx=prot,
                      esi=flags,
                      edi=fd,
                      ebp=offset)
        return self.trustedthread.delegate(args)

    @syscall('NR_brk')
    def brk(self, addr):
        if not self.security.brk(addr):
            return (-1, ENOMEM)
        args = Memory(eax=syscalls.NR_brk, ebx=addr)
        return self.trustedthread.delegate(args)

    @syscall('NR_ugetrlimit')
    def ugetrlimit(self, ptr):
        if not self.security.ugetrlimit(ptr):
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_ugetrlimit, ebx=ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_munmap')
    def munmap(self, addr, length):
        if not self.security.munmap(addr, length):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_munmap, ebx=addr, ecx=length)
        return self.trustedthread.delegate(args)

    @syscall('NR_rt_sigaction')
    def rt_sigaction(self, signum, ptr, oldptr):
        ## signals will never be supported so we cross our fingers and
        ## let the caller believe the syscall succeed
        return 0

    @syscall('NR_sigaction')
    def sigaction(self, signum, ptr, oldptr):
        ## signals will never be supported so we cross our fingers and
        ## let the caller believe the syscall succeed
        return 0

    @mux_syscall('NR_socketcall', 'SYS_SOCKET')
    def _socket(self, domain, type, protocol):
        if not self.security.socket(domain, type, protocol):
            return (-1, EACCESS)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_SOCKET,
                      ecx=struct.pack('3I', domain, type, protocol))
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_CONNECT')
    def _connect(self, sockfd, addr_ptr, addrlen):
        if not self.security.connect(sockfd, addr_ptr, addrlen):
            return (-1, EACCESS)
        tubelog.debug(hex(addr_ptr))
        addr = self.peek_memory(addr_ptr, addrlen)
        ptr = self.trustedthread.push_volatile(addr)
        structure = struct.pack('III', sockfd, ptr, addrlen)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_CONNECT,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_RECVMSG')
    def _recvmsg(self, sockfd, ptr, flags):
        if not self.security.is_valid(ptr, sizeof.sockaddr):
            return (-1, EACCESS)
        buf = self.peek_memory(ptr, 28)  # XXX sizeof(struct msghdr)
        if not self.security.recvmsg(sockfd, buf, flags):
            return (-1, EACCESS)
        ptr = self.trustedthread.push_volatile(buf)
        structure = struct.pack('III', sockfd, ptr, flags)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_RECVMSG,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_SENDTO')
    def _sendto(self, sockfd, ptr, buflen, flags):
        if not self.security.is_valid(ptr, buflen):
            return (-1, EACCESS)
        buf = self.peek_memory(ptr, buflen)
        if not self.security.sendto(sockfd, buf, flags):
            return (-1, EACCESS)
        ptr = self.trustedthread.push_volatile(buf)
        structure = struct.pack('IIII', sockfd, ptr, buflen, flags)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_SENDTO,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_BIND')
    def _bind(self, sockfd, ptr, addrlen):
        if not self.security.is_valid(ptr, addrlen):
            return (-1, EACCESS)
        addr = self.peek_memory(ptr, addrlen)
        if not self.security.bind(sockfd, addr):
            return (-1, EACCESS)
        ptr = self.trustedthread.push_volatile(addr)
        structure = struct.pack('III', sockfd, ptr, addrlen)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_BIND,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_GETSOCKNAME')
    def _getsockname(self, sockfd, ptr, addrlen):
        if not self.security.getsockname(sockfd, ptr, addrlen):
            return (-1, EACCES)
        structure = struct.pack('III', sockfd, ptr, addrlen)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_GETSOCKNAME,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_SOCKETPAIR')
    def _socketpair(self, domain, type, protocol, fdpair_ptr):
        if not (self.security.is_valid(fdpair_ptr, 8)
                and self.security.socket(domain, type, protocol)):
            return (-1, EACCES)
        structure = struct.pack('IIII', domain, type, protocol, fdpair_ptr)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_SOCKETPAIR,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_LISTEN')
    def _listen(self, sockfd, backlog):
        structure = struct.pack('II', sockfd, backlog)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_LISTEN,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @mux_syscall('NR_socketcall', 'SYS_ACCEPT')
    def _accept(self, sockfd, sockadr_ptr, addrlen_ptr):
        if not self.security.is_valid(addrlen_ptr):
            return (-1, EACCES)
        addrlen = struct.unpack('I', self.peek_memory(addrlen_ptr, 4))[0]
        if not self.security.is_valid(sockadr_ptr, addrlen):
            return (-1, EACCES)
        structure = struct.pack('III', sockfd, sockadr_ptr, addrlen_ptr)
        args = Memory(eax=syscalls.NR_socketcall,
                      ebx=constants.SYS_ACCEPT,
                      ecx=structure)
        return self.trustedthread.delegate(args)

    @syscall('NR_socketcall')
    def socketcall(self, call, ptr):
        if call not in mux_syscall_tables[syscalls.NR_socketcall]:
            sandboxlog.error(
                'socketcall(call=#%d) not implemented *************************************************************'
                % call)
            return 0
        func = mux_syscall_tables[syscalls.NR_socketcall][call]
        structsize = 4 * func.argc
        if not self.security.is_valid(ptr, structsize):
            return (-1, EACCES)
        buf = self.peek_memory(ptr, structsize)
        args = struct.unpack('L' * func.argc, buf)
        return func(self, *args)

    @syscall('NR_time')
    def time(self, time_ptr):
        if not self.security.time(time_ptr):
            return (-1, EFAULT)
        args = Memory(eax=syscalls.NR_time, ebx=time_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_times')
    def times(self, bufptr):
        if not self.security.times(bufptr):
            return (-1, EPERM)
        args = Memory(eax=syscalls.NR_times, ebx=tms_ptr)
        return self.trustedthread.delegate(args)

    @syscall('NR_getuid32')
    def getuid32(self):
        return 1000

    @syscall('NR_geteuid32')
    def geteuid32(self):
        return 1000

    @syscall('NR_getgid32')
    def getgid32(self):
        return 1000

    @syscall('NR_getegid32')
    def getegid32(self):
        return 1000

    @syscall('NR_epoll_create')
    def epoll_create(self, size):
        if not self.security.epoll_create(size):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_epoll_create, ebx=size)
        return self.trustedthread.delegate(args)

    @syscall('NR_fcntl64')
    def fcntl64(self, fd, cmd, args_list):
        if not self.security.fcntl64(fd, cmd, args_list):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_fcntl64, ebx=fd, ecx=cmd, edx=args_list)
        return self.trustedthread.delegate(args)

    @syscall('NR_epoll_ctl')
    def epoll_ctl(self, epollfd, op, fd, event_ptr):
        if not self.security.is_valid(event_ptr, sizeof.event):
            return (-1, EACCES)
        event = self.peek_memory(event_ptr, sizeof.event)
        args = Memory(eax=syscalls.NR_epoll_ctl,
                      ebx=epollfd,
                      ecx=op,
                      edx=fd,
                      esi=event)
        return self.trustedthread.delegate(args)

    @syscall('NR_epoll_wait')
    def epoll_wait(self, epollfd, event_ptr, max_events, timeout):
        if not self.security.is_valid(event_ptr, sizeof.event):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_epoll_wait,
                      ebx=epollfd,
                      ecx=event_ptr,
                      edx=max_events,
                      esi=timeout)
        return self.trustedthread.delegate(args)

    @syscall('NR_eventfd2')
    def eventfd2(self, initval, flags):
        args = Memory(eax=syscalls.NR_eventfd2, ebx=initval, ecx=flags)
        return self.trustedthread.delegate(args)

    @syscall('NR_readv')
    def readv(self, fd, iovptr, iovcnt):
        iovs = self.get_iov(iovptr, iovcnt)
        s = ''.join(iovs)
        args = Memory(eax=syscalls.NR_readv, ebx=fd, ecx=s, edx=len(iovs))
        return self.trustedthread.delegate(args)

    @syscall('NR_writev')
    def writev(self, fd, iovptr, iovcnt):
        iovs = self.get_iov(iovptr, iovcnt)
        s = ''.join(iovs)
        args = Memory(eax=syscalls.NR_writev, ebx=fd, ecx=s, edx=len(iovs))
        return self.trustedthread.delegate(args)

    @syscall('NR_sendfile')
    def sendfile(self, outfd, infd, offset_ptr, count):
        if not self.security.sendfile(outfd, infd, offset_ptr, count):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_sendfile,
                      ebx=outfd,
                      ecx=infd,
                      edx=offset_ptr,
                      esi=count)
        return self.trustedthread.delegate(args)

    @syscall('NR_getdents')
    def getdents(self, fd, dirp_ptr, count):
        if not self.security.is_valid(dirp_ptr, sizeof.linux_dirent):
            return (-1, EACCES)
        args = Memory(eax=syscalls.NR_getdents,
                      ebx=fd,
                      ecx=dirp_ptr,
                      edx=count)
        return self.trustedthread.delegate(args)

    def op_retval(self, ret, errno=0):
        tubelog.debug('<<< op_retval(%#x, %d)' % (ret, errno))
        self.control.write(struct.pack('III', RETVAL, ret & 0xffffffff, errno))
        return ret

    def raisetrap(self):
        self.control.write(struct.pack('I', RAISE_TRAP))

    def get_iov(self, ptr, count):
        array = []
        while count > 0:
            iov = self.peek_memory(ptr, sizeof.iovec)
            iov_base, iov_len = struct.unpack('II', iov)
            if self.security.is_valid(iov_base, iov_len):
                array.append(iov)
            count -= 1
            ptr += sizeof.iovec
        return array

    def peek_asciiz(self, ptr):
        tubelog.debug('<<< peek_asciiz(%#x)' % ptr)
        self.control.write(struct.pack('II', PEEK_ASCIIZ, ptr))
        buf = self.control.read(4)
        nbytes = struct.unpack('I', buf)[0]
        tubelog.debug('    Waiting for %d bytes' % nbytes)
        buf = self.control.read(nbytes)
        tubelog.debug('>>> ' + buf)
        return buf

    def peek_memory(self, ptr, length):
        tubelog.debug('<<< peek_memory(%#x, %d)' % (ptr, length))
        self.control.write(struct.pack('III', PEEK_MEMORY, ptr, length))
        buf = self.control.read(length)
        tubelog.debug('>>> ' + buf.encode('hex'))
        return buf

    def poke_memory(self, addr, buf):
        length = len(buf)
        tubelog.debug('<<< poke_memory(%#x, "...") len=%d' % (addr, length))
        self.control.write(struct.pack('III', POKE_MEMORY, addr, length))
        written = 0
        while written < length:
            written += self.control.write(buf[written:])

    def dispatcher(self, rawtype):
        msgtype = struct.unpack('I', rawtype)[0]
        if msgtype == DO_SYSCALL:
            ret = self.syscall_request()
            if type(ret) is tuple:
                ret, errno = ret
            else:
                errno = 0
            self.op_retval(ret, errno)
        else:
            tubelog.error('Unknown message type: %#x' % msgtype)

    def run(self):
        while True:
            buf = os.read(CONTROL_FD, 4)
            if not buf:
                break
            self.dispatcher(buf)