mirror of
https://github.com/trailofbits/manticore.git
synced 2026-10-11 22:29:55 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user