nits for common Socket/File FD operations (#301)
* nits for common Socket/File FD operations * rev * _is_open changed to _assert_open throwing IndexError * reverted NotImplemented in File sync() * moved sys_fstat from SLinux to Linux & fixes for _assert_open * nit in sys_write * comment nits
This commit is contained in:
parent
9abef20b67
commit
285aaf8258
@ -26,12 +26,16 @@ class RestartSyscall(Exception):
|
||||
class Deadlock(Exception):
|
||||
pass
|
||||
|
||||
class BadFd(Exception):
|
||||
pass
|
||||
|
||||
def perms_from_elf(elf_flags):
|
||||
return [' ', ' x', ' w ', ' wx', 'r ', 'r x', 'rw ', 'rwx'][elf_flags&7]
|
||||
|
||||
def perms_from_protflags(prot_flags):
|
||||
return [' ', 'r ', ' w ', 'rw ', ' x', 'r x', ' wx', 'rwx'][prot_flags&7]
|
||||
|
||||
|
||||
class File(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
# TODO: assert file is seekable otherwise we should save what was
|
||||
@ -206,14 +210,14 @@ class Socket(object):
|
||||
a = Socket()
|
||||
b = Socket()
|
||||
a.connect(b)
|
||||
return a,b
|
||||
return a, b
|
||||
|
||||
def __init__(self):
|
||||
self.buffer = [] #queue os bytes
|
||||
self.peer = None
|
||||
|
||||
def __repr__(self):
|
||||
return "SOCKET(%x, %r, %x)"%(hash(self), self.buffer, hash(self.peer))
|
||||
return "SOCKET(%x, %r, %x)" % (hash(self), self.buffer, hash(self.peer))
|
||||
|
||||
def is_connected(self):
|
||||
return self.peer is not None
|
||||
@ -247,9 +251,14 @@ class Socket(object):
|
||||
|
||||
def _transmit(self, buf):
|
||||
for c in buf:
|
||||
self.buffer.insert(0,c)
|
||||
self.buffer.insert(0, c)
|
||||
return len(buf)
|
||||
|
||||
def sync(self):
|
||||
raise BadFd("Invalid sync() operation on Socket")
|
||||
|
||||
def seek(self):
|
||||
raise BadFd("Invalid lseek() operation on Socket")
|
||||
|
||||
class Linux(Platform):
|
||||
'''
|
||||
@ -263,6 +272,8 @@ class Linux(Platform):
|
||||
:param string program: The path to ELF binary
|
||||
:param list argv: The argv array; not including binary.
|
||||
:param list envp: The ENV variables.
|
||||
:ivar files: List of active file descriptors
|
||||
:type files: list[Socket] or list[File]
|
||||
'''
|
||||
super(Linux, self).__init__(program)
|
||||
|
||||
@ -276,7 +287,7 @@ class Linux(Platform):
|
||||
self.arch = {'x86': 'i386', 'x64': 'amd64', 'ARM': 'armv7'}[self.elf.get_machine_arch()]
|
||||
|
||||
self._init_cpu(self.arch)
|
||||
self._init_fds()
|
||||
self._init_std_fds()
|
||||
self._execve(program, argv, envp)
|
||||
|
||||
@classmethod
|
||||
@ -289,10 +300,10 @@ class Linux(Platform):
|
||||
'''
|
||||
platform = cls(None)
|
||||
platform._init_cpu(arch)
|
||||
platform._init_fds()
|
||||
platform._init_std_fds()
|
||||
return platform
|
||||
|
||||
def _init_fds(self):
|
||||
def _init_std_fds(self):
|
||||
# open standard files stdin, stdout, stderr
|
||||
logger.debug("Opening file descriptors (0,1,2) (STDIN, STDOUT, STDERR)")
|
||||
self.input = Socket()
|
||||
@ -368,13 +379,14 @@ class Linux(Platform):
|
||||
state['input'] = self.input.buffer
|
||||
state['output'] = self.output.buffer
|
||||
|
||||
files = []
|
||||
# Store the type of file descriptor and the respective contents
|
||||
state_files = []
|
||||
for fd in self.files:
|
||||
if isinstance(fd, Socket):
|
||||
files.append(('Socket', fd.buffer))
|
||||
state_files.append(('Socket', fd.buffer))
|
||||
else:
|
||||
files.append(('File',fd))
|
||||
state['files'] = files
|
||||
state_files.append(('File', fd))
|
||||
state['files'] = state_files
|
||||
|
||||
state['procs'] = self.procs
|
||||
state['current'] = self._current
|
||||
@ -407,6 +419,7 @@ class Linux(Platform):
|
||||
self.output = Socket()
|
||||
self.output.buffer = state['output']
|
||||
|
||||
# fetch each file descriptor (Socket or File())
|
||||
self.files = []
|
||||
for ty, buf in state['files']:
|
||||
if ty == 'Socket':
|
||||
@ -527,9 +540,10 @@ class Linux(Platform):
|
||||
vdso_top = {32: 0x7fff0000, 64: 0x7fff00007fff0000}[bits]
|
||||
vdso_size = len(file('vdso%2d.dump'%bits).read())
|
||||
vdso_addr = self.memory.mmapFile(self.memory._floor(vdso_top - vdso_size),
|
||||
vdso_size, 'r x',
|
||||
{32: 'vdso32.dump', 64: 'vdso64.dump'}[bits],
|
||||
0 )
|
||||
vdso_size,
|
||||
'r x',
|
||||
{32: 'vdso32.dump', 64: 'vdso64.dump'}[bits],
|
||||
0)
|
||||
return vdso_addr
|
||||
|
||||
|
||||
@ -577,19 +591,19 @@ class Linux(Platform):
|
||||
|
||||
auxv = self.auxv
|
||||
logger.debug("Setting argv, envp and auxv.")
|
||||
logger.debug("\tArguments: %s"%repr(argv))
|
||||
logger.debug("\tArguments: %s", repr(argv))
|
||||
if envp:
|
||||
logger.debug("\tEnvironment:")
|
||||
for e in envp:
|
||||
logger.debug("\t\t%s"%repr(e))
|
||||
logger.debug("\t\t%s", repr(e))
|
||||
|
||||
logger.debug("\tAuxv:")
|
||||
for name, val in auxv.items():
|
||||
logger.debug("\t\t%s: %s"%(name, hex(val)))
|
||||
logger.debug("\t\t%s: %s", name, hex(val))
|
||||
|
||||
#We save the argument and environment pointers
|
||||
argvlst=[]
|
||||
envplst=[]
|
||||
argvlst = []
|
||||
envplst = []
|
||||
|
||||
#end envp marker empty string
|
||||
for evar in envp:
|
||||
@ -607,7 +621,7 @@ class Linux(Platform):
|
||||
for name, value in auxv.items():
|
||||
if hasattr(value, '__len__'):
|
||||
cpu.push_bytes(value)
|
||||
auxv[name]=cpu.STACK
|
||||
auxv[name] = cpu.STACK
|
||||
|
||||
#The "secure execution" mode of secure_getenv() is controlled by the
|
||||
#AT_SECURE flag contained in the auxiliary vector passed from the
|
||||
@ -784,7 +798,7 @@ class Linux(Platform):
|
||||
# cpu.memory.mprotect(cpu.memory._ceil(elf_bss), elf_brk-elf_bss, saved_perms)
|
||||
|
||||
|
||||
if cpu.memory.access_ok(slice(elf_bss,elf_brk), 'w'):
|
||||
if cpu.memory.access_ok(slice(elf_bss, elf_brk), 'w'):
|
||||
cpu.memory[elf_bss:elf_brk] = '\x00'*(elf_brk-elf_bss)
|
||||
else:
|
||||
logger.warning("Failing to zerify the trailing: elf_brk-elf_bss")
|
||||
@ -799,7 +813,7 @@ class Linux(Platform):
|
||||
stack = cpu.memory.mmap(stack_base, stack_size, 'rwx', name='stack') + stack_size
|
||||
assert stack_top == stack
|
||||
|
||||
reserved = cpu.memory.mmap(base+vaddr+memsz,0x1000000,' ')
|
||||
reserved = cpu.memory.mmap(base+vaddr+memsz,0x1000000, ' ')
|
||||
interpreter_base = 0
|
||||
if interpreter is not None:
|
||||
base = 0
|
||||
@ -841,9 +855,9 @@ class Linux(Platform):
|
||||
base -= vaddr
|
||||
logger.debug("Loading interpreter offset: %08x addr:%08x %08x %s%s%s" %(offset, base+vaddr, base+vaddr+memsz, (flags&1 and 'r' or ' '), (flags&2 and 'w' or ' '), (flags&4 and 'x' or ' ')))
|
||||
|
||||
k = base + vaddr+ filesz;
|
||||
if k > elf_bss :
|
||||
elf_bss = k;
|
||||
k = base + vaddr + filesz;
|
||||
if k > elf_bss:
|
||||
elf_bss = k
|
||||
if (flags & 4) and end_code < k: #PF_X
|
||||
end_code = k
|
||||
if end_data < k:
|
||||
@ -857,8 +871,8 @@ class Linux(Platform):
|
||||
interpreter_base = base
|
||||
|
||||
logger.debug("Zeroing interpreter elf fractional pages. From %x to %x.", elf_bss, elf_brk)
|
||||
logger.debug("Interpreter bss:%x"%elf_bss)
|
||||
logger.debug("Interpreter brk %x:"%elf_brk)
|
||||
logger.debug("Interpreter bss:%x", elf_bss)
|
||||
logger.debug("Interpreter brk %x:", elf_brk)
|
||||
|
||||
cpu.memory.mprotect(cpu.memory._floor(elf_bss), elf_brk-elf_bss, 'rw ')
|
||||
try:
|
||||
@ -912,15 +926,15 @@ class Linux(Platform):
|
||||
|
||||
def _open(self, f):
|
||||
'''
|
||||
It opens a file on the given a file descriptor
|
||||
Adds a file descriptor to the current file descriptor list
|
||||
|
||||
:rtype: int
|
||||
:param filename: pathname of the file to open.
|
||||
:param mode: file permissions mode.
|
||||
:return: a file description of the opened file.
|
||||
:param f: the file descriptor to add.
|
||||
:return: the index of the file descriptor in the file descr. list
|
||||
'''
|
||||
if None in self.files:
|
||||
fd = self.files.index(None)
|
||||
self.files[fd]=f
|
||||
self.files[fd] = f
|
||||
else:
|
||||
fd = len(self.files)
|
||||
self.files.append(f)
|
||||
@ -928,7 +942,7 @@ class Linux(Platform):
|
||||
|
||||
def _close(self, fd):
|
||||
'''
|
||||
Closes a file descriptor
|
||||
Removes a file descriptor from the file descriptor list
|
||||
:rtype: int
|
||||
:param fd: the file descriptor to close.
|
||||
:return: C{0} on success.
|
||||
@ -939,13 +953,16 @@ class Linux(Platform):
|
||||
'''
|
||||
Duplicates a file descriptor
|
||||
:rtype: int
|
||||
:param fd: the file descriptor to close.
|
||||
:param fd: the file descriptor to duplicate.
|
||||
:return: C{0} on success.
|
||||
'''
|
||||
return self._open(self.files[fd])
|
||||
|
||||
def _is_open(self, fd):
|
||||
return fd >= 0 and fd < len(self.files) and self.files[fd] is not None
|
||||
def _get_fd(self, fd):
|
||||
if fd < 0 or fd >= len(self.files) or self.files[fd] is None:
|
||||
raise BadFd()
|
||||
else:
|
||||
return self.files[fd]
|
||||
|
||||
def sys_umask(self, mask):
|
||||
'''
|
||||
@ -953,7 +970,7 @@ class Linux(Platform):
|
||||
|
||||
:param int mask: New mask
|
||||
'''
|
||||
logger.debug("umask({:o})".format(mask))
|
||||
logger.debug("umask(%o)", mask)
|
||||
return os.umask(mask)
|
||||
|
||||
def sys_chdir(self, path):
|
||||
@ -962,7 +979,7 @@ class Linux(Platform):
|
||||
:param int path: Pointer to path
|
||||
'''
|
||||
path_str = self.current.read_string(path)
|
||||
logger.debug("chdir({})".format(path_str))
|
||||
logger.debug("chdir(%s)", path_str)
|
||||
try:
|
||||
os.chdir(path_str)
|
||||
return 0
|
||||
@ -986,43 +1003,42 @@ class Linux(Platform):
|
||||
|
||||
:return: 0 (Success), or EBADF (fd is not a valid file descriptor or is not open)
|
||||
|
||||
'''
|
||||
if not self._is_open(fd):
|
||||
logger.info("LSEEK: Not valid file descriptor on lseek. Returning EBADF")
|
||||
'''
|
||||
try:
|
||||
self._get_fd(fd).seek(offset)
|
||||
except BadFd:
|
||||
logger.info(("LSEEK: Not valid file descriptor on lseek."
|
||||
"Fd not seekable. Returning EBADF"))
|
||||
return -errno.EBADF
|
||||
|
||||
if isinstance(self.files[fd], Socket):
|
||||
logger.info("LSEEK: Not valid file descriptor on lseek. Fd not seekable. Returning EBADF")
|
||||
return -errno.EBADF
|
||||
|
||||
# Read the data and put in tin memory
|
||||
self.files[fd].seek(offset)
|
||||
#self.syscall_trace.append(("_seek", fd, offset, whence))
|
||||
|
||||
logger.debug("LSEEK(%d, 0x%08x, %d)"%(fd, offset, whence))
|
||||
logger.debug("LSEEK(%d, 0x%08x, %d)", fd, offset, whence)
|
||||
return 0
|
||||
|
||||
def sys_read(self, fd, buf, count):
|
||||
data = ''
|
||||
if count != 0:
|
||||
if not self._is_open(fd):
|
||||
logger.info("READ: Not valid file descriptor on read. Returning EBADF")
|
||||
return -errno.EBADF
|
||||
|
||||
# TODO check count bytes from buf
|
||||
if not buf in self.current.memory: # or not self.current.memory.isValid(buf+count):
|
||||
logger.info("READ: buf points to invalid address. Returning EFAULT")
|
||||
return -errno.EFAULT
|
||||
|
||||
if isinstance(self.files[fd],Socket) and self.files[fd].is_empty():
|
||||
return 0
|
||||
|
||||
# Read the data and put in tin memory
|
||||
data = self.files[fd].read(count)
|
||||
try:
|
||||
# Read the data and put in tin memory
|
||||
data = self._get_fd(fd).read(count)
|
||||
except BadFd:
|
||||
logger.info(("READ: Not valid file descriptor on read."
|
||||
" Returning EBADF"))
|
||||
return -errno.EBADF
|
||||
self.syscall_trace.append(("_read", fd, data))
|
||||
self.current.write_bytes(buf, data)
|
||||
|
||||
logger.debug("READ(%d, 0x%08x, %d, 0x%08x) -> <%s> (size:%d)"%(fd, buf, count, len(data), repr(data)[:min(count,10)],len(data)))
|
||||
logger.debug("READ(%d, 0x%08x, %d, 0x%08x) -> <%s> (size:%d)",
|
||||
fd,
|
||||
buf,
|
||||
count,
|
||||
len(data),
|
||||
repr(data)[:min(count,10)],
|
||||
len(data))
|
||||
return len(data)
|
||||
|
||||
def sys_write(self, fd, buf, count):
|
||||
@ -1041,26 +1057,31 @@ class Linux(Platform):
|
||||
data = []
|
||||
cpu = self.current
|
||||
if count != 0:
|
||||
|
||||
if not self._is_open(fd):
|
||||
try:
|
||||
write_fd = self._get_fd(fd)
|
||||
except BadFd:
|
||||
logger.error("WRITE: Not valid file descriptor. Returning EBADFD %d", fd)
|
||||
return -errno.EBADF
|
||||
|
||||
# TODO check count bytes from buf
|
||||
if buf not in cpu.memory or buf+count not in cpu.memory:
|
||||
if buf not in cpu.memory or buf + count not in cpu.memory:
|
||||
logger.debug("WRITE: buf points to invalid address. Returning EFAULT")
|
||||
return -errno.EFAULT
|
||||
|
||||
if fd > 2 and self.files[fd].is_full():
|
||||
if fd > 2 and write_fd.is_full():
|
||||
cpu.PC -= cpu.instruction.size
|
||||
self.wait([],[fd],None)
|
||||
self.wait([], [fd], None)
|
||||
raise RestartSyscall()
|
||||
|
||||
data = cpu.read_bytes(buf, count)
|
||||
self.files[fd].write(data)
|
||||
write_fd.write(data)
|
||||
|
||||
for line in ''.join([str(x) for x in data]).split('\n'):
|
||||
logger.debug("WRITE(%d, 0x%08x, %d) -> <%.48r>"%(fd, buf, count, line))
|
||||
logger.debug("WRITE(%d, 0x%08x, %d) -> <%.48r>",
|
||||
fd,
|
||||
buf,
|
||||
count,
|
||||
line)
|
||||
self.syscall_trace.append(("_write", fd, data))
|
||||
self.signal_transmit(fd)
|
||||
|
||||
@ -1078,17 +1099,16 @@ class Linux(Platform):
|
||||
- C{-1} if the calling process can not access the file in the desired mode.
|
||||
'''
|
||||
filename = ""
|
||||
for i in xrange(0,255):
|
||||
for i in xrange(0, 255):
|
||||
c = Operators.CHR(self.current.read_int(buf + i, 8))
|
||||
if c == '\x00':
|
||||
break
|
||||
filename += c
|
||||
|
||||
#if path.isfile(PATH) and access(PATH, MODE):
|
||||
# print "File exists and is readable"
|
||||
#else:
|
||||
# print "Either file is missing or is not readable"
|
||||
logger.debug("access(%s, %x) -> %r", filename, mode, os.access(filename, mode))
|
||||
logger.debug("access(%s, %x) -> %r",
|
||||
filename,
|
||||
mode,
|
||||
os.access(filename, mode))
|
||||
if os.access(filename, mode):
|
||||
return 0
|
||||
else:
|
||||
@ -1107,12 +1127,12 @@ class Linux(Platform):
|
||||
return s +'\x00'*(65-len(s))
|
||||
|
||||
now = datetime.now().strftime("%a %b %d %H:%M:%S ART %Y")
|
||||
info = (('sysname', 'Linux'),
|
||||
('nodename', 'ubuntu'),
|
||||
('release', '4.4.0-77-generic'),
|
||||
('version', '#98 SMP ' + now),
|
||||
('machine', self._uname_machine),
|
||||
('domainname', ''))
|
||||
info = (('sysname', 'Linux'),
|
||||
('nodename', 'ubuntu'),
|
||||
('release', '4.4.0-77-generic'),
|
||||
('version', '#98 SMP ' + now),
|
||||
('machine', self._uname_machine),
|
||||
('domainname', ''))
|
||||
|
||||
uname_buf = ''.join(pad(pair[1]) for pair in info)
|
||||
self.current.write_bytes(old_utsname, uname_buf)
|
||||
@ -1156,7 +1176,7 @@ class Linux(Platform):
|
||||
ARCH_GET_FS = 0x1003
|
||||
ARCH_GET_GS = 0x1004
|
||||
assert code == ARCH_SET_FS
|
||||
self.current.FS=0x63
|
||||
self.current.FS = 0x63
|
||||
self.current.set_descriptor(self.current.FS, addr, 0x4000, 'rw')
|
||||
logger.debug("sys_arch_prctl(%04x, %016x) -> 0", code, addr)
|
||||
return 0
|
||||
@ -1183,12 +1203,12 @@ class Linux(Platform):
|
||||
logger.info("FIXME!")
|
||||
mode = {os.O_RDWR: 'r+', os.O_RDONLY: 'r', os.O_WRONLY: 'w'}[flags&7]
|
||||
if filename in self.symbolic_files:
|
||||
logger.debug("%s file is considered symbolic" % filename)
|
||||
logger.debug("%s file is considered symbolic", filename)
|
||||
assert flags & 7 == os.O_RDWR or flags & 7 == os.O_RDONLY, (
|
||||
"Symbolic files should be readable?")
|
||||
f = SymbolicFile(self.constraints, filename, mode)
|
||||
else:
|
||||
f = File(filename, mode) # todo modes, flags
|
||||
f = File(filename, mode) # TODO (theo) modes, flags
|
||||
logger.debug("Opening file %s for %s real fd %d",
|
||||
filename, mode, f.fileno())
|
||||
# FIXME(theo) generic exception
|
||||
@ -1212,9 +1232,9 @@ class Linux(Platform):
|
||||
try:
|
||||
os.rename(oldname, newname)
|
||||
except OSError as e:
|
||||
ret = -e.errno
|
||||
ret = -e.errno
|
||||
|
||||
logger.debug("sys_rename('{}', '{}') -> {}".format(oldname, newname, ret))
|
||||
logger.debug("sys_rename('%s', '%s') -> %s", oldname, newname, ret)
|
||||
|
||||
return ret
|
||||
|
||||
@ -1225,15 +1245,13 @@ class Linux(Platform):
|
||||
|
||||
ret = 0
|
||||
try:
|
||||
f = self.files[fd]
|
||||
if isinstance(f, Socket):
|
||||
ret = -errno.EINVAL
|
||||
else:
|
||||
f.sync()
|
||||
self.files[fd].sync()
|
||||
except IndexError:
|
||||
ret = -errno.EBADF
|
||||
except BadFd:
|
||||
ret = -errno.EINVAL
|
||||
|
||||
logger.debug("sys_fsync({}) -> {}".format(fd, ret))
|
||||
logger.debug("sys_fsync(%d) -> %d", fd, ret)
|
||||
|
||||
return ret
|
||||
|
||||
@ -1249,19 +1267,20 @@ class Linux(Platform):
|
||||
|
||||
#Signals..
|
||||
def sys_kill(self, pid, sig):
|
||||
logger.debug("KILL, Ignoring Sending signal %d to pid %d", sig, pid )
|
||||
logger.debug("KILL, Ignoring Sending signal %d to pid %d", sig, pid)
|
||||
return 0
|
||||
|
||||
def sys_rt_sigaction(self, signum, act,oldact):
|
||||
'Wrapper for sys_sigaction'
|
||||
def sys_rt_sigaction(self, signum, act, oldact):
|
||||
"""Wrapper for sys_sigaction"""
|
||||
return self.sys_sigaction(signum, act, oldact)
|
||||
|
||||
def sys_sigaction(self, signum, act, oldact):
|
||||
logger.debug("SIGACTION, Ignoring changing signal handler for signal %d", signum)
|
||||
logger.debug("SIGACTION, Ignoring changing signal handler for signal %d",
|
||||
signum)
|
||||
return 0
|
||||
|
||||
def sys_rt_sigprocmask(self, cpu, how, newset, oldset):
|
||||
'Wrapper for sys_sigprocmask'
|
||||
'''Wrapper for sys_sigprocmask'''
|
||||
return self.sys_sigprocmask(cpu, how, newset, oldset)
|
||||
|
||||
def sys_sigprocmask(self, cpu, how, newset, oldset):
|
||||
@ -1379,13 +1398,19 @@ class Linux(Platform):
|
||||
total = 0
|
||||
for i in xrange(0, count):
|
||||
buf = cpu.read_int(iov + i * sizeof_iovec, ptrsize)
|
||||
size = cpu.read_int(iov + i * sizeof_iovec + (sizeof_iovec // 2), ptrsize)
|
||||
size = cpu.read_int(iov + i * sizeof_iovec + (sizeof_iovec // 2),
|
||||
ptrsize)
|
||||
|
||||
data = self.files[fd].read(size)
|
||||
total += len(data)
|
||||
cpu.write_bytes(buf, data)
|
||||
self.syscall_trace.append(("_read", fd, data))
|
||||
logger.debug("READV(%r, %r, %r) -> <%r> (size:%r)"%(fd, buf, size, data, len(data)))
|
||||
logger.debug("READV(%r, %r, %r) -> <%r> (size:%r)",
|
||||
fd,
|
||||
buf,
|
||||
size,
|
||||
data,
|
||||
len(data))
|
||||
return total
|
||||
|
||||
def sys_writev(self, fd, iov, count):
|
||||
@ -1429,7 +1454,7 @@ class Linux(Platform):
|
||||
flags = self.current.read_int(user_info + 12, 32)
|
||||
assert n == 0xffffffff
|
||||
assert flags == 0x51 #TODO: fix
|
||||
self.current.GS=0x63
|
||||
self.current.GS = 0x63
|
||||
self.current.set_descriptor(self.current.GS, pointer, 0x4000, 'rw')
|
||||
self.current.write_int(user_info, (0x63 - 3) / 8, 32)
|
||||
return 0
|
||||
@ -1478,7 +1503,7 @@ class Linux(Platform):
|
||||
self.running.remove(procid)
|
||||
#self.procs[procid] = None
|
||||
logger.debug("EXIT_GROUP PROC_%02d %s", procid, error_code)
|
||||
if len(self.running) == 0 :
|
||||
if len(self.running) == 0:
|
||||
raise ProcessExit(error_code)
|
||||
return error_code
|
||||
|
||||
@ -1503,7 +1528,7 @@ class Linux(Platform):
|
||||
logger.debug("sys_futex(...) -> -1")
|
||||
return -1
|
||||
def sys_getrlimit(self, resource, rlim):
|
||||
logger.debug("sys_getrlimit(%x, %x) -> -1",resource, rlim)
|
||||
logger.debug("sys_getrlimit(%x, %x) -> -1", resource, rlim)
|
||||
return -1
|
||||
def sys_fadvise64(self, fd, offset, length, advice):
|
||||
logger.debug("sys_fadvise64(%x, %x, %x, %x) -> 0", fd, offset, length, advice)
|
||||
@ -1522,7 +1547,7 @@ class Linux(Platform):
|
||||
|
||||
try:
|
||||
table = getattr(linux_syscalls, self.current.machine)
|
||||
name = table.get(index,None)
|
||||
name = table.get(index, None)
|
||||
implementation = getattr(self, name)
|
||||
except (AttributeError, KeyError):
|
||||
raise SyscallNotImplemented(self.current.address_bit_size, index, name)
|
||||
@ -1547,7 +1572,7 @@ class Linux(Platform):
|
||||
current running process. May give the same cpu if only one running
|
||||
process.
|
||||
'''
|
||||
if len(self.procs)>1:
|
||||
if len(self.procs) > 1:
|
||||
logger.debug("SCHED:")
|
||||
logger.debug("\tProcess: %r", self.procs)
|
||||
logger.debug("\tRunning: %r", self.running)
|
||||
@ -1561,16 +1586,18 @@ class Linux(Platform):
|
||||
logger.debug("None running checking if there is some process waiting for a timeout")
|
||||
if all([x is None for x in self.timers]):
|
||||
raise Deadlock()
|
||||
self.clocks = min(filter(lambda x: x is not None, self.timers))+1
|
||||
self.clocks = min(filter(lambda x: x is not None, self.timers)) + 1
|
||||
self.check_timers()
|
||||
assert len(self.running) != 0, "DEADLOCK!"
|
||||
self._current = self.running[0]
|
||||
return
|
||||
next_index = (self.running.index(self._current) + 1) % len(self.running)
|
||||
next = self.running[ next_index ]
|
||||
if len(self.procs)>1:
|
||||
logger.debug("\tTransfer control from process %d to %d", self._current, next)
|
||||
self._current = next
|
||||
next_running_idx = self.running[next_index]
|
||||
if len(self.procs) > 1:
|
||||
logger.debug("\tTransfer control from process %d to %d",
|
||||
self._current,
|
||||
next_running_idx)
|
||||
self._current = next_running_idx
|
||||
|
||||
def wait(self, readfds, writefds, timeout):
|
||||
''' Wait for file descriptors or timeout.
|
||||
@ -1578,7 +1605,11 @@ class Linux(Platform):
|
||||
yield the cpu to another running process.
|
||||
'''
|
||||
logger.debug("WAIT:")
|
||||
logger.debug("\tProcess %d is going to wait for [ %r %r %r ]", self._current, readfds, writefds, timeout)
|
||||
logger.debug("\tProcess %d is going to wait for [ %r %r %r ]",
|
||||
self._current,
|
||||
readfds,
|
||||
writefds,
|
||||
timeout)
|
||||
logger.debug("\tProcess: %r", self.procs)
|
||||
logger.debug("\tRunning: %r", self.running)
|
||||
logger.debug("\tRWait: %r", self.rwait)
|
||||
@ -1595,13 +1626,13 @@ class Linux(Platform):
|
||||
procid = self._current
|
||||
#self.sched()
|
||||
next_index = (self.running.index(procid) + 1) % len(self.running)
|
||||
self._current = self.running[ next_index ]
|
||||
self._current = self.running[next_index]
|
||||
logger.debug("\tTransfer control from process %d to %d", procid, self._current)
|
||||
logger.debug( "\tREMOVING %r from %r. Current: %r",procid, self.running, self._current)
|
||||
logger.debug( "\tREMOVING %r from %r. Current: %r", procid, self.running, self._current)
|
||||
self.running.remove(procid)
|
||||
if self._current not in self.running:
|
||||
logger.debug( "\tCurrent not running. Checking for timers...")
|
||||
self._current=None
|
||||
logger.debug("\tCurrent not running. Checking for timers...")
|
||||
self._current = None
|
||||
self.check_timers()
|
||||
|
||||
def awake(self, procid):
|
||||
@ -1611,15 +1642,19 @@ class Linux(Platform):
|
||||
if procid in wait_list: wait_list.remove(procid)
|
||||
for wait_list in self.twait:
|
||||
if procid in wait_list: wait_list.remove(procid)
|
||||
self.timers[procid]=None
|
||||
self.timers[procid] = None
|
||||
self.running.append(procid)
|
||||
if self._current is None:
|
||||
self._current = procid
|
||||
|
||||
def connections(self, fd):
|
||||
if fd in [0,1,2]:
|
||||
""" File descriptors are connected to each other like pipes. Except
|
||||
for 0,1,2. If you write to FD(N) then that comes out from FD(N+1)
|
||||
and vice-versa
|
||||
"""
|
||||
if fd in [0, 1, 2]:
|
||||
return None
|
||||
if fd%2:
|
||||
if fd % 2:
|
||||
return fd + 1
|
||||
else:
|
||||
return fd - 1
|
||||
@ -1644,9 +1679,9 @@ class Linux(Platform):
|
||||
|
||||
def check_timers(self):
|
||||
''' Awake process if timer has expired '''
|
||||
if self._current is None :
|
||||
if self._current is None:
|
||||
#Advance the clocks. Go to future!!
|
||||
advance = min([self.clocks] + filter(lambda x: x is not None, self.timers)) +1
|
||||
advance = min([self.clocks] + filter(lambda x: x is not None, self.timers)) + 1
|
||||
logger.debug("Advancing the clock from %d to %d", self.clocks, advance)
|
||||
self.clocks = advance
|
||||
for procid in range(len(self.timers)):
|
||||
@ -1664,20 +1699,18 @@ class Linux(Platform):
|
||||
|
||||
:todo: This is where we could implement a simple schedule.
|
||||
"""
|
||||
syscallret = None
|
||||
try:
|
||||
self.current.execute()
|
||||
self.clocks += 1
|
||||
if self.clocks % 10000 == 0:
|
||||
self.check_timers()
|
||||
self.sched()
|
||||
except (Interruption, Syscall) as e:
|
||||
except (Interruption, Syscall):
|
||||
try:
|
||||
syscallret = self.syscall()
|
||||
self.syscall()
|
||||
except RestartSyscall:
|
||||
pass
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@ -1694,8 +1727,8 @@ class Linux(Platform):
|
||||
stat = self.files[fd].stat()
|
||||
|
||||
def add(width, val):
|
||||
format = {2:'H',4:'L',8:'Q'}[width]
|
||||
return struct.pack('<'+format, val)
|
||||
fformat = {2:'H', 4:'L', 8:'Q'}[width]
|
||||
return struct.pack('<'+fformat, val)
|
||||
|
||||
def to_timespec(width, ts):
|
||||
'Note: this is a platform-dependent timespec (8 or 16 bytes)'
|
||||
@ -1705,7 +1738,7 @@ class Linux(Platform):
|
||||
# Numerous fields are native width-wide
|
||||
nw = self.current.address_bit_size / 8
|
||||
|
||||
bufstat = add(nw, stat.st_dev) # long st_dev
|
||||
bufstat = add(nw, stat.st_dev) # long st_dev
|
||||
bufstat += add(nw, stat.st_ino) # long st_ino
|
||||
bufstat += add(nw, stat.st_nlink) # long st_nlink
|
||||
bufstat += add(4, stat.st_mode) # 32 mode
|
||||
@ -1720,11 +1753,49 @@ class Linux(Platform):
|
||||
bufstat += to_timespec(nw, stat.st_mtime) # long st_mtime, nsec;
|
||||
bufstat += to_timespec(nw, stat.st_ctime) # long st_ctime, nsec;
|
||||
|
||||
logger.debug("sys_newfstat({}, ...) -> {} bytes".format(fd, len(bufstat)))
|
||||
logger.debug("sys_newfstat(%d, ...) -> %d bytes", fd, len(bufstat))
|
||||
|
||||
self.current.write_bytes(buf, bufstat)
|
||||
return 0
|
||||
|
||||
def sys_fstat(self, fd, buf):
|
||||
'''
|
||||
Determines information about a file based on its file descriptor.
|
||||
:rtype: int
|
||||
:param fd: the file descriptor of the file that is being inquired.
|
||||
:param buf: a buffer where data about the file will be stored.
|
||||
:return: C{0} on success.
|
||||
'''
|
||||
stat = self.files[fd].stat()
|
||||
|
||||
def add(width, val):
|
||||
fformat = {2:'H', 4:'L', 8:'Q'}[width]
|
||||
return struct.pack('<'+fformat, val)
|
||||
|
||||
def to_timespec(ts):
|
||||
return struct.pack('<LL', int(ts), int(ts % 1 * 1e9))
|
||||
|
||||
logger.debug("sys_fstat %d", fd)
|
||||
|
||||
bufstat = add(8, stat.st_dev) # dev_t st_dev;
|
||||
bufstat += add(4, 0) # __pad1
|
||||
bufstat += add(4, stat.st_ino) # unsigned long st_ino;
|
||||
bufstat += add(4, stat.st_mode) # unsigned short st_mode;
|
||||
bufstat += add(4, stat.st_nlink) # unsigned short st_nlink;
|
||||
bufstat += add(4, stat.st_uid) # unsigned short st_uid;
|
||||
bufstat += add(4, stat.st_gid) # unsigned short st_gid;
|
||||
bufstat += add(4, stat.st_rdev) # unsigned long st_rdev;
|
||||
bufstat += add(4, stat.st_size) # unsigned long st_size;
|
||||
bufstat += add(4, stat.st_blksize)# unsigned long st_blksize;
|
||||
bufstat += add(4, stat.st_blocks) # unsigned long st_blocks;
|
||||
bufstat += to_timespec(stat.st_atime) # unsigned long st_atime;
|
||||
bufstat += to_timespec(stat.st_mtime) # unsigned long st_mtime;
|
||||
bufstat += to_timespec(stat.st_ctime) # unsigned long st_ctime;
|
||||
bufstat += add(4, 0) # unsigned long __unused4;
|
||||
bufstat += add(4, 0) # unsigned long __unused5;
|
||||
|
||||
self.current.write_bytes(buf, bufstat)
|
||||
return 0
|
||||
|
||||
def sys_fstat64(self, fd, buf):
|
||||
'''
|
||||
@ -1738,15 +1809,15 @@ class Linux(Platform):
|
||||
stat = self.files[fd].stat()
|
||||
|
||||
def add(width, val):
|
||||
format = {2:'H',4:'L',8:'Q'}[width]
|
||||
return struct.pack('<'+format, val)
|
||||
fformat = {2:'H', 4:'L', 8:'Q'}[width]
|
||||
return struct.pack('<'+fformat, val)
|
||||
|
||||
def to_timespec(ts):
|
||||
return struct.pack('<LL', int(ts), int(ts % 1 * 1e9))
|
||||
|
||||
logger.debug("sys_fstat64 {}".format(fd))
|
||||
logger.debug("sys_fstat64 %d", fd)
|
||||
|
||||
bufstat = add(8, stat.st_dev) # unsigned long long st_dev;
|
||||
bufstat = add(8, stat.st_dev) # unsigned long long st_dev;
|
||||
bufstat += add(4, 0) # unsigned char __pad0[4];
|
||||
bufstat += add(4, stat.st_ino) # unsigned long __st_ino;
|
||||
bufstat += add(4, stat.st_mode) # unsigned int st_mode;
|
||||
@ -1808,7 +1879,7 @@ class Linux(Platform):
|
||||
|
||||
# Establish segment registers for x86 architectures
|
||||
if self.arch in {'i386', 'amd64'}:
|
||||
x86_defaults = { 'CS': 0x23, 'SS': 0x2b, 'DS': 0x2b, 'ES': 0x2b, }
|
||||
x86_defaults = {'CS': 0x23, 'SS': 0x2b, 'DS': 0x2b, 'ES': 0x2b}
|
||||
for reg, val in x86_defaults.iteritems():
|
||||
self.current.regfile.write(reg, val)
|
||||
|
||||
@ -1892,48 +1963,8 @@ class SLinux(Linux):
|
||||
|
||||
return super(SLinux, self).sys_read(fd, buf, count)
|
||||
|
||||
|
||||
def sys_fstat(self, fd, buf):
|
||||
'''
|
||||
Determines information about a file based on its file descriptor.
|
||||
:rtype: int
|
||||
:param fd: the file descriptor of the file that is being inquired.
|
||||
:param buf: a buffer where data about the file will be stored.
|
||||
:return: C{0} on success.
|
||||
'''
|
||||
stat = self.files[fd].stat()
|
||||
|
||||
def add(width, val):
|
||||
format = {2:'H',4:'L',8:'Q'}[width]
|
||||
return struct.pack('<'+format, val)
|
||||
|
||||
def to_timespec(ts):
|
||||
return struct.pack('<LL', int(ts), int(ts % 1 * 1e9))
|
||||
|
||||
logger.debug("sys_fstat {}".format(fd))
|
||||
|
||||
bufstat = add(8, stat.st_dev) # dev_t st_dev;
|
||||
bufstat += add(4, 0) # __pad1
|
||||
bufstat += add(4, stat.st_ino) # unsigned long st_ino;
|
||||
bufstat += add(4, stat.st_mode) # unsigned short st_mode;
|
||||
bufstat += add(4, stat.st_nlink) # unsigned short st_nlink;
|
||||
bufstat += add(4, stat.st_uid) # unsigned short st_uid;
|
||||
bufstat += add(4, stat.st_gid) # unsigned short st_gid;
|
||||
bufstat += add(4, stat.st_rdev) # unsigned long st_rdev;
|
||||
bufstat += add(4, stat.st_size) # unsigned long st_size;
|
||||
bufstat += add(4, stat.st_blksize)# unsigned long st_blksize;
|
||||
bufstat += add(4, stat.st_blocks) # unsigned long st_blocks;
|
||||
bufstat += to_timespec(stat.st_atime) # unsigned long st_atime;
|
||||
bufstat += to_timespec(stat.st_mtime) # unsigned long st_mtime;
|
||||
bufstat += to_timespec(stat.st_ctime) # unsigned long st_ctime;
|
||||
bufstat += add(4, 0) # unsigned long __unused4;
|
||||
bufstat += add(4, 0) # unsigned long __unused5;
|
||||
|
||||
self.current.write_bytes(buf, bufstat)
|
||||
return 0
|
||||
|
||||
def sys_mmap_pgoff(self, address, size, prot, flags, fd, offset):
|
||||
'Wrapper for mmap2'
|
||||
'''Wrapper for mmap2'''
|
||||
return self.sys_mmap2(address, size, prot, flags, fd, offset)
|
||||
|
||||
def sys_mmap2(self, address, size, prot, flags, fd, offset):
|
||||
@ -1983,18 +2014,18 @@ class SLinux(Linux):
|
||||
address = None
|
||||
|
||||
cpu = self.current
|
||||
if flags & 0x10 !=0 :
|
||||
if flags & 0x10 != 0:
|
||||
cpu.memory.munmap(address,size)
|
||||
|
||||
perms = perms_from_protflags(prot)
|
||||
|
||||
if (flags & 0x20 != 0):
|
||||
if flags & 0x20 != 0:
|
||||
result = cpu.memory.mmap(address, size, perms)
|
||||
elif fd == 0:
|
||||
assert offset == 0
|
||||
result = cpu.memory.mmap(address, size, perms)
|
||||
data = self.files[fd].read(size)
|
||||
cpu.write_bytes(result,data)
|
||||
cpu.write_bytes(result, data)
|
||||
else:
|
||||
#FIXME Check if file should be symbolic input and do as with fd0
|
||||
result = cpu.memory.mmapFile(address, size, perms, self.files[fd].name, offset)
|
||||
@ -2004,11 +2035,17 @@ class SLinux(Linux):
|
||||
address = address or 0
|
||||
actually_mapped += ' [requested: 0x{:016x}]'.format(address)
|
||||
|
||||
if (flags & 0x10 !=0) and result != address:
|
||||
if flags & 0x10 != 0 and result != address:
|
||||
cpu.memory.munmap(result, size)
|
||||
result = -1
|
||||
|
||||
logger.debug("sys_mmap(%s, 0x%x, %s, %x, %d) - (0x%x)", actually_mapped, size, perms, flags, fd, result)
|
||||
logger.debug("sys_mmap(%s, 0x%x, %s, %x, %d) - (0x%x)",
|
||||
actually_mapped,
|
||||
size,
|
||||
perms,
|
||||
flags,
|
||||
fd,
|
||||
result)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user