Skip to content

Commit

Permalink
Merge e0f0077 into 2347b21
Browse files Browse the repository at this point in the history
  • Loading branch information
ekilmer committed Aug 5, 2020
2 parents 2347b21 + e0f0077 commit 8910bf3
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 25 deletions.
8 changes: 8 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,11 @@
source = manticore
omit =
*__init__.py

[report]
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover

# Don't try to cover special syntax "..." in abstract class
@abstractmethod
72 changes: 47 additions & 25 deletions manticore/platforms/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,30 @@ class creation time, you will get an error only if you try to instantiate
return cls


@dataclass
class StatResult:
"""
Data structure corresponding to result received from stat, fstat, lstat for
information about a file.
See https://man7.org/linux/man-pages/man2/stat.2.html for more info
"""

st_mode: int
st_ino: int
st_dev: int
st_nlink: int
st_uid: int
st_gid: int
st_size: int
st_atime: int
st_mtime: int
st_ctime: int
st_blksize: int
st_blocks: int
st_rdev: int


class FdLike(ABC):
"""
An abstract class for different kinds of file descriptors.
Expand Down Expand Up @@ -142,6 +166,10 @@ def ioctl(self, request, argp) -> int:
def tell(self) -> int:
...

@abstractmethod
def stat(self) -> StatResult:
...


@dataclass
class FdTableEntry:
Expand Down Expand Up @@ -277,9 +305,9 @@ def closed(self) -> bool:

def stat(self):
try:
return os.fstat(self.fileno())
return os.stat(self.fileno())
except OSError as e:
return -e.errno
raise FdError(f"Cannot stat: {e.strerror}", e.errno)

def ioctl(self, request, argp):
try:
Expand Down Expand Up @@ -375,6 +403,12 @@ def close(self):
except OSError as e:
return -e.errno

def stat(self):
try:
return os.stat(self.fileno())
except OSError as e:
raise FdError(f"Cannot stat: {e.strerror}", e.errno)

def fileno(self):
return self.fd

Expand Down Expand Up @@ -541,31 +575,17 @@ def ioctl(self, request, argp):
def tell(self) -> int:
raise FdError("Invalid tell() operation on SocketDesc", errno.EBADF)

def stat(self) -> StatResult:
# Copied from Socket.stat
return StatResult(
8592, 11, 9, 1, 1000, 5, 0, 1378673920, 1378673920, 1378653796, 0x400, 0x8808, 0
)


@concreteclass
class Socket(FdLike):
def stat(self):
from collections import namedtuple

stat_result = namedtuple(
"stat_result",
[
"st_mode",
"st_ino",
"st_dev",
"st_nlink",
"st_uid",
"st_gid",
"st_size",
"st_atime",
"st_mtime",
"st_ctime",
"st_blksize",
"st_blocks",
"st_rdev",
],
)
return stat_result(
return StatResult(
8592, 11, 9, 1, 1000, 5, 0, 1378673920, 1378673920, 1378653796, 0x400, 0x8808, 0
)

Expand Down Expand Up @@ -3051,8 +3071,10 @@ def sys_getdents(self, fd, dirent, count) -> int:
# Don't overflow buffer
break

stat = item.stat()
print(f"FILE MODE: {item.name} :: {stat.st_mode:o}")
try:
stat = item.stat()
except FdError as e:
return -e.err

# https://elixir.bootlin.com/linux/v5.1.15/source/include/linux/fs_types.h#L27
d_type = (stat.st_mode >> 12) & 15
Expand Down
174 changes: 174 additions & 0 deletions tests/native/test_syscalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,180 @@ def test_directories(self):
self.linux.sys_rmdir(0x1100)
self.assertFalse(os.path.exists(dname))

def test_dir_stat(self):
dname = self.get_path("test_dir_stat")
self.assertFalse(os.path.exists(dname))

self.linux.current.memory.mmap(0x1000, 0x1000, "rw")
self.linux.current.write_string(0x1100, dname)

# Create it as a dir
self.linux.sys_mkdir(0x1100, mode=0o777)
fd = self.linux.sys_open(0x1100, flags=os.O_RDONLY | os.O_DIRECTORY, mode=0o777)
self.assertTrue(os.path.exists(dname))
self.assertGreater(fd, 0)

res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertEqual(res, 0)

# Remove from file system on host but not in Manticore
os.rmdir(dname)
self.assertFalse(os.path.exists(dname))
res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertLess(res, 0)
# The file descriptor is still valid even though the directory is gone
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertEqual(res, 0)

# Remove the directory using Manticore
self.linux.sys_rmdir(0x1100)
res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertLess(res, 0)
# The file descriptor is still valid even though the directory is gone
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertEqual(res, 0)

# Close the file descriptor to totally remove it
self.linux.sys_close(fd)
res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertLess(res, 0)

def test_file_stat(self):
fname = self.get_path("test_file_stat")
self.assertFalse(os.path.exists(fname))

self.linux.current.memory.mmap(0x1000, 0x1000, "rw")
self.linux.current.write_string(0x1100, fname)

# Create a file
fd = self.linux.sys_open(0x1100, os.O_RDWR, 0o777)
self.assertTrue(os.path.exists(fname))

res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertEqual(res, 0)

# Remove from file system on host but not in Manticore
os.remove(fname)
self.assertFalse(os.path.exists(fname))
res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertEqual(res, 0)

# Remove the file using Manticore
self.linux.sys_unlink(0x1100)
res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertEqual(res, 0)

# Close the file descriptor to totally remove it
self.linux.sys_close(fd)
res = self.linux.sys_stat32(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_stat64(0x1100, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertLess(res, 0)

def test_socketdesc_stat(self):
self.linux.current.memory.mmap(0x1000, 0x1000, "rw")

# Create a socket
fd = self.linux.sys_socket(socket.AF_INET, socket.SOCK_STREAM, 0)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertEqual(res, 0)

# Close the socket
self.linux.sys_close(fd)
res = self.linux.sys_newfstat(fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat(fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat64(fd, 0x1200)
self.assertLess(res, 0)

def test_socket_stat(self):
self.linux.current.memory.mmap(0x1000, 0x1000, "rw")

# Create a socket
sock_fd = self.linux.sys_socket(socket.AF_INET, socket.SOCK_STREAM, 0)
self.linux.sys_bind(sock_fd, None, None)
self.linux.sys_listen(sock_fd, None)
conn_fd = self.linux.sys_accept(sock_fd, None, 0)

res = self.linux.sys_newfstat(conn_fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat(conn_fd, 0x1200)
self.assertEqual(res, 0)
res = self.linux.sys_fstat64(conn_fd, 0x1200)
self.assertEqual(res, 0)

# Close the socket
self.linux.sys_close(conn_fd)
res = self.linux.sys_newfstat(conn_fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat(conn_fd, 0x1200)
self.assertLess(res, 0)
res = self.linux.sys_fstat64(conn_fd, 0x1200)
self.assertLess(res, 0)

def test_pipe(self):
self.linux.current.memory.mmap(0x1000, 0x1000, "rw")
self.linux.sys_pipe(0x1100)
Expand Down

0 comments on commit 8910bf3

Please sign in to comment.