Add methods for getting list of (un)implemented system calls (#2491)

This is primarily a helper function that is useful in evaluating the
capabilities of Manticore on Linux

* Add Linux Kernel version constant to syscalls list

* Add method for getting unimplemented syscalls

This is specific per architecture
This commit is contained in:
Eric Kilmer
2021-09-15 09:13:48 -04:00
committed by GitHub
parent b73986b141
commit 522f8ba31e
4 changed files with 89 additions and 6 deletions
+38
View File
@@ -3316,6 +3316,44 @@ class Linux(Platform):
last = load_segs[-1]
return last.header.p_vaddr + last.header.p_memsz
@classmethod
def implemented_syscalls(cls) -> Iterable[str]:
"""
Get a listing of all concretely implemented system calls for Linux. This
does not include whether a symbolic version exists. To get that listing,
use the SLinux.implemented_syscalls() method.
"""
import inspect
return (
name
for (name, obj) in inspect.getmembers(cls, predicate=inspect.isfunction)
if name.startswith("sys_") and
# Check that the class defining the method is exactly this one
getattr(inspect.getmodule(obj), obj.__qualname__.rsplit(".", 1)[0], None) == cls
)
@classmethod
def unimplemented_syscalls(cls, syscalls: Union[Set[str], Dict[int, str]]) -> Set[str]:
"""
Get a listing of all unimplemented concrete system calls for a given
collection of Linux system calls. To get a listing of unimplemented
symbolic system calls, use the ``SLinux.unimplemented_syscalls()``
method.
Available system calls can be found at ``linux_syscalls.py`` or you may
pass your own as either a set of system calls or as a mapping of system
call number to system call name.
Note that passed system calls should follow the naming convention
located in ``linux_syscalls.py``.
"""
implemented_syscalls = set(cls.implemented_syscalls())
if isinstance(syscalls, set):
return syscalls.difference(implemented_syscalls)
else:
return set(syscalls.values()).difference(implemented_syscalls)
############################################################################
# Symbolic versions follows
+3 -3
View File
@@ -2,8 +2,8 @@
#
# AUTOGENERATED, DO NOT EDIT
#
# From version: 4.11
#
LINUX_KERNEL_VERSION = "4.11"
i386 = {
0: "sys_restart_syscall",
@@ -426,7 +426,7 @@ amd64 = {
53: "sys_socketpair",
54: "sys_setsockopt",
55: "sys_getsockopt",
56: "sys_clone_ptregs",
56: "sys_clone/ptregs",
57: "sys_fork/ptregs",
58: "sys_vfork/ptregs",
59: "sys_execve/ptregs",
+2 -2
View File
@@ -78,8 +78,8 @@ if __name__ == "__main__":
args = parser.parse_args()
output = open(args.output, "w+")
output.write("#\n#\n# AUTOGENERATED, DO NOT EDIT\n#\n")
output.write(f"# From version: {args.linux_version}\n#\n\n")
output.write("#\n#\n# AUTOGENERATED, DO NOT EDIT\n#\n\n")
output.write(f'LINUX_KERNEL_VERSION = "{args.linux_version}"\n\n')
for arch, path in ARCH_TABLES:
url = BASE_URL.format(path, args.linux_version)
+46 -1
View File
@@ -15,7 +15,13 @@ from manticore.core.smtlib import BitVecVariable, issymbolic, ConstraintSet
from manticore.native import Manticore
from manticore.platforms import linux, linux_syscalls
from manticore.utils.helpers import pickle_dumps
from manticore.platforms.linux import EnvironmentError, logger as linux_logger, SymbolicFile
from manticore.platforms.linux import (
EnvironmentError,
logger as linux_logger,
SymbolicFile,
Linux,
SLinux,
)
class LinuxTest(unittest.TestCase):
@@ -417,3 +423,42 @@ class LinuxTest(unittest.TestCase):
m.run()
self.assertTrue(m.context["success"])
def test_implemented_syscall_report(self) -> None:
concrete_syscalls = set(Linux.implemented_syscalls())
symbolic_syscalls = set(SLinux.implemented_syscalls())
# Make sure at least one known syscall implementation appears in both
assert "sys_read" in concrete_syscalls
assert "sys_read" in symbolic_syscalls
# Make sure an unimplemented syscall (taken from linux_syscall_stubs)
# does not appear in our list of concrete syscalls. This could change in
# the future
assert "sys_bpf" not in concrete_syscalls
# Make sure that a concretely implemented syscall does not have a (at
# this time) symbolic equivalent. This could change in the future
assert "sys_tgkill" in concrete_syscalls
assert "sys_tgkill" not in symbolic_syscalls
# This doesn't _need_ to be true, but our design says it should be true
assert symbolic_syscalls.issubset(concrete_syscalls)
def test_unimplemented_syscall_report(self) -> None:
"""This test is the inverse of test_implemented_syscall_report"""
from manticore.platforms.linux_syscalls import amd64
unimplemented_concrete_syscalls = set(Linux.unimplemented_syscalls(amd64))
unimplemented_symbolic_syscalls = set(SLinux.unimplemented_syscalls(set(amd64.values())))
assert "sys_read" not in unimplemented_concrete_syscalls
assert "sys_read" not in unimplemented_symbolic_syscalls
assert "sys_bpf" in unimplemented_concrete_syscalls
assert "sys_tgkill" not in unimplemented_concrete_syscalls
assert "sys_tgkill" in unimplemented_symbolic_syscalls
# This doesn't _need_ to be true, but our design says it should be true
assert unimplemented_concrete_syscalls.issubset(unimplemented_symbolic_syscalls)