Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a syscall implementation for llseek #1640

Merged
merged 16 commits into from
Mar 30, 2020
Merged
87 changes: 61 additions & 26 deletions manticore/platforms/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,7 @@ def __init__(self, constraints, path="sfile", mode="rw", max_size=100, wildcard=

if symbols_cnt > max_size:
logger.warning(
(
"Found more wildcards in the file than free ",
"symbolic values allowed (%d > %d)",
),
"Found more wildcards in the file than free symbolic values allowed (%d > %d)",
symbols_cnt,
max_size,
)
Expand Down Expand Up @@ -1231,7 +1228,7 @@ def _close(self, fd):
) # Keep track for SymbolicFile testcase generation
self.files[fd] = None
except IndexError:
raise FdError(f"Bad file descriptor ({fd})")
raise FdError(f"Bad file descriptor ({fd})", os.EBADF)

def _dup(self, fd):
"""
Expand All @@ -1251,7 +1248,7 @@ def _is_fd_open(self, fd):

def _get_fd(self, fd):
if not self._is_fd_open(fd):
raise FdError
raise FdError(f"File descriptor is not open", errno.EBADF)
else:
return self.files[fd]

Expand Down Expand Up @@ -1307,13 +1304,13 @@ def sys_getcwd(self, buf, size):

if size > 0 and size < length:
logger.info(
"GETCWD: size is greater than 0, but is smaller than the length"
"of the path + 1. Returning ERANGE"
"GETCWD: size is greater than 0, but is smaller than the length "
"of the path + 1. Returning -errno.ERANGE"
)
return -errno.ERANGE

if not self.current.memory.access_ok(slice(buf, buf + length), "w"):
logger.info("GETCWD: buf within invalid memory. Returning EFAULT")
logger.info("GETCWD: buf within invalid memory. Returning -errno.EFAULT")
return -errno.EFAULT

self.current.write_string(buf, current_dir)
Expand All @@ -1333,19 +1330,57 @@ def sys_lseek(self, fd, offset, whence):

:param fd: a valid file descriptor
:param offset: the offset in bytes
:param whence: SEEK_SET: The file offset is set to offset bytes.
SEEK_CUR: The file offset is set to its current location plus offset bytes.
SEEK_END: The file offset is set to the size of the file plus offset bytes.
:param whence: os.SEEK_SET: The file offset is set to offset bytes.
os.SEEK_CUR: The file offset is set to its current location plus offset bytes.
os.SEEK_END: The file offset is set to the size of the file plus offset bytes.

:return: offset from file beginning, or EBADF (fd is not a valid file descriptor or is not open)

"""
signed_offset = self._to_signed_dword(offset)
try:
return self._get_fd(fd).seek(signed_offset, whence)
except FdError as e:
logger.info(
("LSEEK: Not valid file descriptor on lseek." "Fd not seekable. Returning EBADF")
f"LSEEK: Not valid file descriptor on lseek. Fd not seekable. Returning {-e.err}"
)
return -e.err

def sys_llseek(self, fd, offset_high, offset_low, resultp, whence):
bradlarsen marked this conversation as resolved.
Show resolved Hide resolved
"""
_llseek - reposition read/write file offset

The _llseek() system call repositions the offset of the open
file description associated with the file descriptor fd to
(offset_high<<32) | offset_low bytes relative to the beginning of the
file, the current file offset, or the end of the file, depending on
whether whence is os.SEEK_SET, os.SEEK_CUR, or os.SEEK_END,
respectively. It returns the resulting file position in the argument
result.

This system call exists on various 32-bit platforms to support seeking
to large file offsets.

:param fd: a valid file descriptor
:param offset_high: the high 32 bits of the byte offset
:param offset_low: the low 32 bits of the byte offset
:param resultp: a pointer to write the position into on success
:param whence: os.SEEK_SET: The file offset is set to offset bytes.
os.SEEK_CUR: The file offset is set to its current location plus offset bytes.
os.SEEK_END: The file offset is set to the size of the file plus offset bytes.

:return: 0 on success, negative on error
"""
signed_offset_high = self._to_signed_dword(offset_high)
signed_offset_low = self._to_signed_dword(offset_low)
signed_offset = (signed_offset_high << 32) | signed_offset_low
try:
pos = self._get_fd(fd).seek(signed_offset, whence)
posbuf = struct.pack("q", pos) # `loff_t * resultp` in linux, which is `long long`
self.current.write_bytes(resultp, posbuf)
return 0
except FdError as e:
logger.info(
f"LSEEK: Not valid file descriptor on llseek. Fd not seekable. Returning {-e.err}"
)
return -e.err

Expand All @@ -1354,14 +1389,14 @@ def sys_read(self, fd, buf, count):
if count != 0:
# TODO check count bytes from buf
if buf not in self.current.memory: # or not self.current.memory.isValid(buf+count):
logger.info("READ: buf points to invalid address. Returning EFAULT")
logger.info("READ: buf points to invalid address. Returning -errno.EFAULT")
return -errno.EFAULT

try:
# Read the data and put it in memory
data = self._get_fd(fd).read(count)
except FdError as e:
logger.info(("READ: Not valid file descriptor on read." " Returning EBADF"))
logger.info(f"READ: Not valid file descriptor ({fd}). Returning -{e.err}")
return -e.err
self.syscall_trace.append(("_read", fd, data))
self.current.write_bytes(buf, data)
Expand Down Expand Up @@ -1392,7 +1427,7 @@ def sys_write(self, fd, buf, count):

# TODO check count bytes from buf
if buf not in cpu.memory or buf + count not in cpu.memory:
logger.debug("WRITE: buf points to invalid address. Returning EFAULT")
logger.debug("WRITE: buf points to invalid address. Returning -errno.EFAULT")
return -errno.EFAULT

if fd > 2 and write_fd.is_full():
Expand Down Expand Up @@ -1578,11 +1613,11 @@ def sys_openat(self, dirfd, buf, flags, mode):
try:
dir_entry = self._get_fd(dirfd)
except FdError as e:
logger.info("openat: Not valid file descriptor. Returning EBADF")
logger.info(f"openat: Not valid file descriptor. Returning {-e.err}")
return -e.err

if not isinstance(dir_entry, Directory):
logger.info("openat: Not directory descriptor. Returning ENOTDIR")
logger.info("openat: Not directory descriptor. Returning -errno.ENOTDIR")
return -errno.ENOTDIR

dir_path = dir_entry.name
Expand Down Expand Up @@ -1674,7 +1709,7 @@ def sys_dup(self, fd):
"""

if not self._is_fd_open(fd):
logger.info("DUP: Passed fd is not open. Returning EBADF")
logger.info(f"DUP: Passed fd is not open ({fd}). Returning -errno.EBADF")
return -errno.EBADF

newfd = self._dup(fd)
Expand All @@ -1691,12 +1726,12 @@ def sys_dup2(self, fd, newfd):
try:
file = self._get_fd(fd)
except FdError as e:
logger.info("DUP2: Passed fd is not open. Returning EBADF")
logger.info("DUP2: fd ({fd}) is not open. Returning {-e.err}")
return -e.err

soft_max, hard_max = self._rlimits[self.RLIMIT_NOFILE]
if newfd >= soft_max:
logger.info("DUP2: newfd is above max descriptor table size")
logger.info(f"DUP2: newfd ({newfd}) is above max descriptor table size")
return -errno.EBADF

if self._is_fd_open(newfd):
Expand Down Expand Up @@ -2136,7 +2171,7 @@ def sys_accept4(self, sockfd, addr, addrlen, flags):
def sys_recv(self, sockfd, buf, count, flags, trace_str="_recv"):
data: bytes = bytes()
if not self.current.memory.access_ok(slice(buf, buf + count), "w"):
logger.info("RECV: buf within invalid memory. Returning EFAULT")
logger.info("RECV: buf within invalid memory. Returning -errno.EFAULT")
return -errno.EFAULT

try:
Expand Down Expand Up @@ -2216,7 +2251,7 @@ def sys_getrandom(self, buf, size, flags):
return 0

if buf not in self.current.memory:
logger.info("getrandom: Provided an invalid address. Returning EFAULT")
logger.info("getrandom: Provided an invalid address. Returning -errno.EFAULT")
return -errno.EFAULT

if flags & ~(GRND_NONBLOCK | GRND_RANDOM):
Expand Down Expand Up @@ -2509,7 +2544,7 @@ def sys_fstat(self, fd, buf):
try:
stat = self._get_fd(fd).stat()
except FdError as e:
logger.info("Calling fstat with invalid fd, returning EBADF")
logger.info(f"Calling fstat with invalid fd, returning {-e.err}")
return -e.err

def add(width, val):
Expand Down Expand Up @@ -2552,7 +2587,7 @@ def sys_fstat64(self, fd, buf):
try:
stat = self._get_fd(fd).stat()
except FdError as e:
logger.info("Calling fstat with invalid fd, returning EBADF")
logger.info(f"Calling fstat with invalid fd, returning {-e.err}")
return -e.err

def add(width, val):
Expand Down
Loading