diff --git a/qiling/os/filestruct.py b/qiling/os/filestruct.py index c57bbc54e..511f505a8 100644 --- a/qiling/os/filestruct.py +++ b/qiling/os/filestruct.py @@ -30,10 +30,7 @@ def __init__(self, path: AnyStr, fd: int): def open(cls, path: AnyStr, flags: int, mode: int, dir_fd: Optional[int] = None): mode &= 0x7fffffff - try: - fd = os.open(path, flags, mode, dir_fd=dir_fd) - except OSError as e: - raise QlSyscallError(e.errno, e.args[1] + ' : ' + e.filename) + fd = os.open(path, flags, mode, dir_fd=dir_fd) return cls(path, fd) diff --git a/qiling/os/freebsd/syscall.py b/qiling/os/freebsd/syscall.py index 77691936a..bb1c563bd 100644 --- a/qiling/os/freebsd/syscall.py +++ b/qiling/os/freebsd/syscall.py @@ -1,16 +1,18 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +import ctypes +from datetime import datetime +from math import floor +from qiling import Qiling from qiling.arch.x86_const import * from qiling.os.freebsd.const import * +from qiling.os.posix.const import ENOENT from qiling.os.posix.syscall.unistd import ql_syscall_getcwd from qiling.os.posix.syscall.stat import ql_syscall_newfstatat -from datetime import datetime -from math import floor -import ctypes class timespec(ctypes.Structure): _fields_ = [ @@ -59,20 +61,21 @@ def ql_syscall___getcwd(ql, path_buff, path_buffsize, *args, **kw): def ql_syscall_fstatat(ql, newfstatat_dirfd, newfstatat_path, newfstatat_buf_ptr, newfstatat_flag, *args, **kw): return ql_syscall_newfstatat(ql, newfstatat_dirfd, newfstatat_path, newfstatat_buf_ptr, newfstatat_flag, *args, **kw) -def ql_syscall___sysctl(ql, name, namelen, old, oldlenp, new_arg, newlen): +def ql_syscall___sysctl(ql: Qiling, name: int, namelen: int, old: int, oldlenp: int, new_arg: int, newlen: int): ql.log.debug("__sysctl(name: 0x%x, namelen: 0x%x, old: 0x%x, oldlenp: 0x%x, new: 0x%x, newlen: 0x%x)" % ( name, namelen, old, oldlenp, new_arg, newlen )) - vecs = [] - for i in range(namelen): - vecs.append(ql.unpack32s(ql.mem.read(name + i*4, 4))) + + vecs = [ql.mem.read_ptr(name + i * 4, 4, signed=True) for i in range(namelen)] + ql.log.debug(f"__sysctl vectors: {vecs}") if vecs[0] == CTL_SYSCTL: if vecs[1] == CTL_SYSCTL_NAME2OID: # Write oid to old and oldlenp - sysctl_name = ql.mem.string(new_arg) + sysctl_name = ql.os.utils.read_cstring(new_arg) out_vecs = [] out_len = 0 + # TODO: Implement oid<-->name as many as possible from FreeBSD source. # Search SYSCTL_ADD_NODE etc. if sysctl_name == "hw.pagesizes": @@ -80,16 +83,21 @@ def ql_syscall___sysctl(ql, name, namelen, old, oldlenp, new_arg, newlen): out_len = 2 else: ql.log.warning("Unknown oid name!") + for i, v in enumerate(out_vecs): - ql.mem.write(old + 4*i, ql.pack32s(v)) - ql.mem.write(oldlenp, ql.pack32s(out_len)) - return 2 # ENOENT + ql.mem.write_ptr(old + i * 4, v, 32, signed=True) + + ql.mem.write_ptr(oldlenp, out_len, 32, signed=True) + + return -ENOENT + if vecs[0] == CTL_KERN: if vecs[1] == KERN_OSRELDATE: - if old == 0 or oldlenp == 0: + if old == 0 or oldlenp == 0: return -1 + # Ignore oldlenp check. - ql.mem.write(old, ql.pack32s(FREEBSD_OSRELDATE)) + ql.mem.write_ptr(old, FREEBSD_OSRELDATE, 32, signed=True) + return 0 return 0 - \ No newline at end of file diff --git a/qiling/os/memory.py b/qiling/os/memory.py index b5be6d91d..ec643c0e4 100644 --- a/qiling/os/memory.py +++ b/qiling/os/memory.py @@ -313,13 +313,14 @@ def read(self, addr: int, size: int) -> bytearray: return self.ql.uc.mem_read(addr, size) - def read_ptr(self, addr: int, size: int = 0) -> int: + def read_ptr(self, addr: int, size: int = 0, *, signed = False) -> int: """Read an integer value from a memory address. Bytes read will be unpacked using emulated architecture properties. Args: addr: memory address to read size: pointer size (in bytes): either 1, 2, 4, 8, or 0 for arch native size + signed: interpret value as a signed integer (default: False) Returns: integer value stored at the specified memory address """ @@ -327,12 +328,17 @@ def read_ptr(self, addr: int, size: int = 0) -> int: if not size: size = self.ql.arch.pointersize - __unpack = { + __unpack = ({ + 1: self.ql.unpack8s, + 2: self.ql.unpack16s, + 4: self.ql.unpack32s, + 8: self.ql.unpack64s + } if signed else { 1: self.ql.unpack8, 2: self.ql.unpack16, 4: self.ql.unpack32, 8: self.ql.unpack64 - }.get(size) + }).get(size) if __unpack is None: raise QlErrorStructConversion(f"Unsupported pointer size: {size}") @@ -349,7 +355,7 @@ def write(self, addr: int, data: bytes) -> None: self.ql.uc.mem_write(addr, data) - def write_ptr(self, addr: int, value: int, size: int = 0) -> None: + def write_ptr(self, addr: int, value: int, size: int = 0, *, signed = False) -> None: """Write an integer value to a memory address. Bytes written will be packed using emulated architecture properties. @@ -357,17 +363,23 @@ def write_ptr(self, addr: int, value: int, size: int = 0) -> None: addr: target memory address value: integer value to write size: pointer size (in bytes): either 1, 2, 4, 8, or 0 for arch native size + signed: interpret value as a signed integer (default: False) """ if not size: size = self.ql.arch.pointersize - __pack = { + __pack = ({ + 1: self.ql.pack8s, + 2: self.ql.pack16s, + 4: self.ql.pack32s, + 8: self.ql.pack64s + } if signed else { 1: self.ql.pack8, 2: self.ql.pack16, 4: self.ql.pack32, 8: self.ql.pack64 - }.get(size) + }).get(size) if __pack is None: raise QlErrorStructConversion(f"Unsupported pointer size: {size}") diff --git a/qiling/os/posix/const.py b/qiling/os/posix/const.py index b12f429c4..87fc41153 100644 --- a/qiling/os/posix/const.py +++ b/qiling/os/posix/const.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from enum import Flag +from enum import Enum, Flag # OS Threading Constants THREAD_EVENT_INIT_VAL = 0 @@ -19,620 +19,611 @@ SOCK_TYPE_MASK = 0x0f -linux_x86_socket_types = { - 'SOCK_STREAM' : 0x1, - 'SOCK_DGRAM' : 0x2, - 'SOCK_RAW' : 0x3, - 'SOCK_RDM' : 0x4, - 'SOCK_SEQPACKET' : 0x5, - 'SOCK_DCCP' : 0x6, - 'SOCK_PACKET' : 0xa, - 'SOCK_NONBLOCK' : 0x800, - 'SOCK_CLOEXEC' : 0x80000, -} +class linux_x86_socket_types(Enum): + SOCK_STREAM = 0x00001 + SOCK_DGRAM = 0x00002 + SOCK_RAW = 0x00003 + SOCK_RDM = 0x00004 + SOCK_SEQPACKET = 0x00005 + SOCK_DCCP = 0x00006 + SOCK_PACKET = 0x0000a + SOCK_NONBLOCK = 0x00800 + SOCK_CLOEXEC = 0x80000 + + +class linux_x86_socket_domain(Enum): + AF_UNSPEC = 0x0 + AF_LOCAL = 0x1 + AF_INET = 0x2 + AF_AX25 = 0x3 + AF_IPX = 0x4 + AF_APPLETALK = 0x5 + AF_NETROM = 0x6 + AF_BRIDGE = 0x7 + AF_AAL5 = 0x8 + AF_X25 = 0x9 + AF_INET6 = 0xa + AF_MAX = 0xc -linux_x86_socket_domain = { - 'AF_UNSPEC' : 0x0, - 'AF_LOCAL' : 0x1, - 'AF_INET' : 0x2, - 'AF_AX25' : 0x3, - 'AF_IPX' : 0x4, - 'AF_APPLETALK' : 0x5, - 'AF_NETROM' : 0x6, - 'AF_BRIDGE' : 0x7, - 'AF_AAL5' : 0x8, - 'AF_X25' : 0x9, - 'AF_INET6' : 0xa, - 'AF_MAX' : 0xc, -} # https://github.com/torvalds/linux/blob/master/include/uapi/linux/in.h -linux_x86_socket_level = { - 'IPPROTO_IP' : 0x0000, - 'SOL_SOCKET' : 0x0001, - 'IPPROTO_TCP' : 0x0006, - 'IPPROTO_UDP' : 0x0011, - 'IPPROTO_IPV6' : 0x0029, - 'IPPROTO_RAW' : 0x00ff, -} +class linux_x86_socket_level(Enum): + IPPROTO_IP = 0x0000 + SOL_SOCKET = 0x0001 + IPPROTO_TCP = 0x0006 + IPPROTO_UDP = 0x0011 + IPPROTO_IPV6 = 0x0029 + IPPROTO_RAW = 0x00ff + # https://github.com/torvalds/linux/blob/master/tools/include/uapi/asm-generic/socket.h -linux_x86_socket_options = { - "SO_DEBUG" : 0x0001, - "SO_REUSEADDR" : 0x0002, - "SO_TYPE" : 0x0003, - "SO_ERROR" : 0x0004, - "SO_DONTROUTE" : 0x0005, - "SO_BROADCAST" : 0x0006, - "SO_SNDBUF" : 0x0007, - "SO_RCVBUF" : 0x0008, - "SO_SNDBUFFORCE" : 0x0020, - "SO_RCVBUFFORCE" : 0x0021, - "SO_KEEPALIVE" : 0x0009, - "SO_OOBINLINE" : 0x000a, - "SO_NO_CHECK" : 0x000b, - "SO_PRIORITY" : 0x000c, - "SO_LINGER" : 0x000d, - "SO_BSDCOMPAT" : 0x000e, - "SO_REUSEPORT" : 0x000f, - "SO_PASSCRED" : 0x0010, - "SO_PEERCRED" : 0x0011, - "SO_RCVLOWAT" : 0x0012, - "SO_SNDLOWAT" : 0x0013, - "SO_RCVTIMEO_OLD" : 0x0014, - "SO_SNDTIMEO_OLD" : 0x0015, -} +class linux_x86_socket_options(Enum): + SO_DEBUG = 0x0001 + SO_REUSEADDR = 0x0002 + SO_TYPE = 0x0003 + SO_ERROR = 0x0004 + SO_DONTROUTE = 0x0005 + SO_BROADCAST = 0x0006 + SO_SNDBUF = 0x0007 + SO_RCVBUF = 0x0008 + SO_SNDBUFFORCE = 0x0020 + SO_RCVBUFFORCE = 0x0021 + SO_KEEPALIVE = 0x0009 + SO_OOBINLINE = 0x000a + SO_NO_CHECK = 0x000b + SO_PRIORITY = 0x000c + SO_LINGER = 0x000d + SO_BSDCOMPAT = 0x000e + SO_REUSEPORT = 0x000f + SO_PASSCRED = 0x0010 + SO_PEERCRED = 0x0011 + SO_RCVLOWAT = 0x0012 + SO_SNDLOWAT = 0x0013 + SO_RCVTIMEO_OLD = 0x0014 + SO_SNDTIMEO_OLD = 0x0015 + # https://man7.org/linux/man-pages/man7/ip.7.html # https://github.com/torvalds/linux/blob/master/include/uapi/linux/in.h -linux_socket_ip_options = { - "IP_TOS" : 0x0001, - "IP_TTL" : 0x0002, - "IP_HDRINCL" : 0x0003, - "IP_OPTIONS" : 0x0004, - "IP_ROUTER_ALERT" : 0x0005, - "IP_RECVOPTS" : 0x0006, - "IP_RETOPTS" : 0x0007, - "IP_PKTINFO" : 0x0008, - "IP_MTU_DISCOVER" : 0x000a, - "IP_RECVERR" : 0x000b, - "IP_RECVTTL" : 0x000c, - "IP_RECVTOS" : 0x000d, - "IP_MTU" : 0x000e, - "IP_FREEBIND" : 0x000f, - "IP_PASSSEC" : 0x0012, - "IP_TRANSPARENT" : 0x0013, - "IP_RECVORIGDSTADDR" : 0x0014, - "IP_NODEFRAG" : 0x0016, - "IP_BIND_ADDRESS_NO_PORT" : 0x0018, - "IP_MULTICAST_IF" : 0x0020, - "IP_MULTICAST_TTL" : 0x0021, - "IP_MULTICAST_LOOP" : 0x0022, - "IP_ADD_MEMBERSHIP" : 0x0023, - "IP_DROP_MEMBERSHIP" : 0x0024, - "IP_UNBLOCK_SOURCE" : 0x0025, - "IP_BLOCK_SOURCE" : 0x0026, - "IP_ADD_SOURCE_MEMBERSHIP" : 0x0027, - "IP_DROP_SOURCE_MEMBERSHIP" : 0x0028, - "IP_MSFILTER" : 0x0029, - "IP_MULTICAST_ALL" : 0x0031, -} +class linux_socket_ip_options(Enum): + IP_TOS = 0x0001 + IP_TTL = 0x0002 + IP_HDRINCL = 0x0003 + IP_OPTIONS = 0x0004 + IP_ROUTER_ALERT = 0x0005 + IP_RECVOPTS = 0x0006 + IP_RETOPTS = 0x0007 + IP_PKTINFO = 0x0008 + IP_MTU_DISCOVER = 0x000a + IP_RECVERR = 0x000b + IP_RECVTTL = 0x000c + IP_RECVTOS = 0x000d + IP_MTU = 0x000e + IP_FREEBIND = 0x000f + IP_PASSSEC = 0x0012 + IP_TRANSPARENT = 0x0013 + IP_RECVORIGDSTADDR = 0x0014 + IP_NODEFRAG = 0x0016 + IP_BIND_ADDRESS_NO_PORT = 0x0018 + IP_MULTICAST_IF = 0x0020 + IP_MULTICAST_TTL = 0x0021 + IP_MULTICAST_LOOP = 0x0022 + IP_ADD_MEMBERSHIP = 0x0023 + IP_DROP_MEMBERSHIP = 0x0024 + IP_UNBLOCK_SOURCE = 0x0025 + IP_BLOCK_SOURCE = 0x0026 + IP_ADD_SOURCE_MEMBERSHIP = 0x0027 + IP_DROP_SOURCE_MEMBERSHIP = 0x0028 + IP_MSFILTER = 0x0029 + IP_MULTICAST_ALL = 0x0031 -# https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h -linux_socket_tcp_options = { - "TCP_NODELAY" : 0x1, - "TCP_MAXSEG" : 0x2, - "TCP_CORK" : 0x3, - "TCP_KEEPIDLE" : 0x4, - "TCP_KEEPINTVL" : 0x5, - "TCP_KEEPCNT" : 0x6, - "TCP_SYNCNT" : 0x7, - "TCP_LINGER2" : 0x8, - "TCP_DEFER_ACCEPT" : 0x9, - "TCP_WINDOW_CLAMP" : 0xa, - "TCP_INFO" : 0xb, - "TCP_QUICKACK" : 0xc, - "TCP_CONGESTION" : 0xd, - "TCP_MD5SIG" : 0xe, - "TCP_THIN_LINEAR_TIMEOUTS" : 0x10, - "TCP_THIN_DUPACK" : 0x11, - "TCP_USER_TIMEOUT" : 0x12, - "TCP_REPAIR" : 0x13, - "TCP_REPAIR_QUEUE" : 0x14, - "TCP_QUEUE_SEQ" : 0x15, - "TCP_REPAIR_OPTIONS" : 0x16, - "TCP_FASTOPEN" : 0x17, - "TCP_TIMESTAMP" : 0x18, - "TCP_NOTSENT_LOWAT" : 0x19, - "TCP_CC_INFO" : 0x1a, - "TCP_SAVE_SYN" : 0x1b, - "TCP_SAVED_SYN" : 0x1c, - "TCP_REPAIR_WINDOW" : 0x1d, - "TCP_FASTOPEN_CONNECT" : 0x1e, - "TCP_ULP" : 0x1f, - "TCP_MD5SIG_EXT" : 0x20, - "TCP_FASTOPEN_KEY" : 0x21, - "TCP_FASTOPEN_NO_COOKIE" : 0x22, - "TCP_ZEROCOPY_RECEIVE" : 0x23, - "TCP_INQ" : 0x24, - "TCP_TX_DELAY" : 0x25, -} - -macos_socket_ip_options = { - "IP_TOS" : 0x0003, - "IP_TTL" : 0x0004, - "IP_HDRINCL" : 0x0002, - "IP_OPTIONS" : 0x0001, - # "IP_ROUTER_ALERT" : 0x0005, - "IP_RECVOPTS" : 0x0005, - "IP_RETOPTS" : 0x0008, - # "IP_PKTINFO" : 0x0008, - # "IP_MTU_DISCOVER" : 0x000a, - # "IP_RECVERR" : 0x000b, - # "IP_RECVTTL" : 0x000c, - # "IP_RECVTOS" : 0x000d, - # "IP_MTU" : 0x000e, - # "IP_FREEBIND" : 0x000f, - # "IP_PASSSEC" : 0x0012, - # "IP_TRANSPARENT" : 0x0013, - # "IP_RECVORIGDSTADDR" : 0x0014, - # "IP_NODEFRAG" : 0x0016, - # "IP_BIND_ADDRESS_NO_PORT" : 0x0018, - "IP_MULTICAST_IF" : 0x0009, - "IP_MULTICAST_TTL" : 0x000a, - "IP_MULTICAST_LOOP" : 0x000b, - "IP_ADD_MEMBERSHIP" : 0x000c, - "IP_DROP_MEMBERSHIP" : 0x000d, - # "IP_UNBLOCK_SOURCE" : 0x0025, - # "IP_BLOCK_SOURCE" : 0x0026, - # "IP_ADD_SOURCE_MEMBERSHIP" : 0x0027, - # "IP_DROP_SOURCE_MEMBERSHIP" : 0x0028, - # "IP_MSFILTER" : 0x0029, - # "IP_MULTICAST_ALL" : 0x0031, -} - -macos_x86_socket_domain = { - 'AF_UNSPEC' : 0x0, - 'AF_LOCAL' : 0x1, - 'AF_INET' : 0x2, - 'AF_IMPLINK' : 0x3, - 'AF_PUP' : 0x4, - 'AF_CHAOS' : 0x5, - 'AF_NS' : 0x6, - 'AF_ISO' : 0x7, - 'AF_OSI' : 0x7, - 'AF_ECMA' : 0x8, - 'AF_DATAKIT' : 0x9, - 'AF_CCITT' : 0xa, - 'AF_SNA' : 0xb, - 'AF_DECnet' : 0xc, - 'AF_INET6' : 0x1e, -} +# https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h +class linux_socket_tcp_options(Enum): + TCP_NODELAY = 0x01 + TCP_MAXSEG = 0x02 + TCP_CORK = 0x03 + TCP_KEEPIDLE = 0x04 + TCP_KEEPINTVL = 0x05 + TCP_KEEPCNT = 0x06 + TCP_SYNCNT = 0x07 + TCP_LINGER2 = 0x08 + TCP_DEFER_ACCEPT = 0x09 + TCP_WINDOW_CLAMP = 0x0a + TCP_INFO = 0x0b + TCP_QUICKACK = 0x0c + TCP_CONGESTION = 0x0d + TCP_MD5SIG = 0x0e + TCP_THIN_LINEAR_TIMEOUTS = 0x10 + TCP_THIN_DUPACK = 0x11 + TCP_USER_TIMEOUT = 0x12 + TCP_REPAIR = 0x13 + TCP_REPAIR_QUEUE = 0x14 + TCP_QUEUE_SEQ = 0x15 + TCP_REPAIR_OPTIONS = 0x16 + TCP_FASTOPEN = 0x17 + TCP_TIMESTAMP = 0x18 + TCP_NOTSENT_LOWAT = 0x19 + TCP_CC_INFO = 0x1a + TCP_SAVE_SYN = 0x1b + TCP_SAVED_SYN = 0x1c + TCP_REPAIR_WINDOW = 0x1d + TCP_FASTOPEN_CONNECT = 0x1e + TCP_ULP = 0x1f + TCP_MD5SIG_EXT = 0x20 + TCP_FASTOPEN_KEY = 0x21 + TCP_FASTOPEN_NO_COOKIE = 0x22 + TCP_ZEROCOPY_RECEIVE = 0x23 + TCP_INQ = 0x24 + TCP_TX_DELAY = 0x25 + + +class macos_socket_ip_options(Enum): + IP_TOS = 0x03 + IP_TTL = 0x04 + IP_HDRINCL = 0x02 + IP_OPTIONS = 0x01 + # IP_ROUTER_ALERT = 0x05 + IP_RECVOPTS = 0x05 + IP_RETOPTS = 0x08 + # IP_PKTINFO = 0x08 + # IP_MTU_DISCOVER = 0x0a + # IP_RECVERR = 0x0b + # IP_RECVTTL = 0x0c + # IP_RECVTOS = 0x0d + # IP_MTU = 0x0e + # IP_FREEBIND = 0x0f + # IP_PASSSEC = 0x12 + # IP_TRANSPARENT = 0x13 + # IP_RECVORIGDSTADDR = 0x14 + # IP_NODEFRAG = 0x16 + # IP_BIND_ADDRESS_NO_PORT= 0x18 + IP_MULTICAST_IF = 0x09 + IP_MULTICAST_TTL = 0x0a + IP_MULTICAST_LOOP = 0x0b + IP_ADD_MEMBERSHIP = 0x0c + IP_DROP_MEMBERSHIP = 0x0d + # IP_UNBLOCK_SOURCE = 0x25 + # IP_BLOCK_SOURCE = 0x26 + # IP_ADD_SOURCE_MEMBERSHIP = 0x27 + # IP_DROP_SOURCE_MEMBERSHIP = 0x28 + # IP_MSFILTER = 0x29 + # IP_MULTICAST_ALL = 0x31 + + +class macos_x86_socket_domain(Enum): + AF_UNSPEC = 0x00 + AF_LOCAL = 0x01 + AF_INET = 0x02 + AF_IMPLINK = 0x03 + AF_PUP = 0x04 + AF_CHAOS = 0x05 + AF_NS = 0x06 + AF_ISO = 0x07 + AF_OSI = 0x07 + AF_ECMA = 0x08 + AF_DATAKIT = 0x09 + AF_CCITT = 0x0a + AF_SNA = 0x0b + AF_DECnet = 0x0c + AF_INET6 = 0x1e # https://gfiber.googlesource.com/toolchains/mindspeed/+/refs/heads/newkernel_dev/arm-unknown-linux-gnueabi/sysroot/usr/include/bits/socket.h -linux_arm_socket_types = { - 'SOCK_STREAM' : 0x1, - 'SOCK_DGRAM' : 0x2, - 'SOCK_RAW' : 0x3, - 'SOCK_RDM' : 0x4, - 'SOCK_SEQPACKET' : 0x5, - 'SOCK_DCCP' : 0x6, - 'SOCK_PACKET' : 0xa, - 'SOCK_NONBLOCK' : 0x800, - 'SOCK_CLOEXEC' : 0x80000, -} - - -linux_arm_socket_domain = { - 'AF_UNSPEC' : 0x0, - 'AF_FILE' : 0x1, - 'AF_UNIX' : 0x1, - 'AF_LOCAL' : 0x1, - 'AF_INET' : 0x2, - 'AF_AX25' : 0x3, - 'AF_IPX' : 0x4, - 'AF_APPLETALK' : 0x5, - 'AF_NETROM' : 0x6, - 'AF_BRIDGE' : 0x7, - 'AF_ATMPVC' : 0x8, - 'AF_X25' : 0x9, - 'AF_INET6' : 0xa, - 'AF_ROSE' : 0xb, - 'AF_DECnet' : 0xc, - 'AF_NETBEUI' : 0xd, - 'AF_SECURITY' : 0xe, - 'AF_KEY' : 0xf, - 'AF_NETLINK' : 0x10, - 'AF_ROUTE' : 0x10, - 'AF_PACKET' : 0x11, - 'AF_ASH' : 0x12, - 'AF_ECONET' : 0x13, - 'AF_ATMSVC' : 0x14, - 'AF_RDS' : 0x15, - 'AF_SNA' : 0x16, - 'AF_IRDA' : 0x17, - 'AF_PPPOX' : 0x18, - 'AF_WANPIPE' : 0x19, - 'AF_LLC' : 0x1a, - 'AF_IB' : 0x1b, - 'AF_MPLS' : 0x1c, - 'AF_CAN' : 0x1d, - 'AF_TIPC' : 0x1e, - 'AF_BLUETOOTH' : 0x1f, - 'AF_IUCV' : 0x20, - 'AF_RXRPC' : 0x21, - 'AF_ISDN' : 0x22, - 'AF_PHONE' : 0x23, - 'AF_IEEE802154' : 0x24, - 'AF_CAIF' : 0x25, - 'AF_ALG' : 0x26, - 'AF_NFC' : 0x27, - 'AF_VSOCK' : 0x28, - 'AF_KCM' : 0x29, - 'AF_QIPCRTR' : 0x2a, - 'AF_SMC' : 0x2b, - 'AF_MAX' : 0x2c, -} +class linux_arm_socket_types(Enum): + SOCK_STREAM = 0x00001 + SOCK_DGRAM = 0x00002 + SOCK_RAW = 0x00003 + SOCK_RDM = 0x00004 + SOCK_SEQPACKET = 0x00005 + SOCK_DCCP = 0x00006 + SOCK_PACKET = 0x0000a + SOCK_NONBLOCK = 0x00800 + SOCK_CLOEXEC = 0x80000 + + +class linux_arm_socket_domain(Enum): + AF_UNSPEC = 0x00 + AF_FILE = 0x01 + AF_UNIX = 0x01 + AF_LOCAL = 0x01 + AF_INET = 0x02 + AF_AX25 = 0x03 + AF_IPX = 0x04 + AF_APPLETALK = 0x05 + AF_NETROM = 0x06 + AF_BRIDGE = 0x07 + AF_ATMPVC = 0x08 + AF_X25 = 0x09 + AF_INET6 = 0x0a + AF_ROSE = 0x0b + AF_DECnet = 0x0c + AF_NETBEUI = 0x0d + AF_SECURITY = 0x0e + AF_KEY = 0x0f + AF_NETLINK = 0x10 + AF_ROUTE = 0x10 + AF_PACKET = 0x11 + AF_ASH = 0x12 + AF_ECONET = 0x13 + AF_ATMSVC = 0x14 + AF_RDS = 0x15 + AF_SNA = 0x16 + AF_IRDA = 0x17 + AF_PPPOX = 0x18 + AF_WANPIPE = 0x19 + AF_LLC = 0x1a + AF_IB = 0x1b + AF_MPLS = 0x1c + AF_CAN = 0x1d + AF_TIPC = 0x1e + AF_BLUETOOTH = 0x1f + AF_IUCV = 0x20 + AF_RXRPC = 0x21 + AF_ISDN = 0x22 + AF_PHONE = 0x23 + AF_IEEE802154 = 0x24 + AF_CAIF = 0x25 + AF_ALG = 0x26 + AF_NFC = 0x27 + AF_VSOCK = 0x28 + AF_KCM = 0x29 + AF_QIPCRTR = 0x2a + AF_SMC = 0x2b + AF_MAX = 0x2c # https://gfiber.googlesource.com/toolchains/mindspeed/+/refs/heads/newkernel_dev/arm-unknown-linux-gnueabi/sysroot/usr/include/asm/socket.h -linux_arm_socket_level = { - 'IPPROTO_IP' : 0x0000, - 'SOL_SOCKET' : 0x0001, - 'IPPROTO_TCP' : 0x0006, - 'IPPROTO_UDP' : 0x0011, - 'IPPROTO_IPV6' : 0x0029, - 'IPPROTO_RAW' : 0x00ff, -} - -# https://gfiber.googlesource.com/toolchains/mindspeed/+/refs/heads/newkernel_dev/arm-unknown-linux-gnueabi/sysroot/usr/include/asm/socket.h -linux_arm_socket_options = { - "SO_DEBUG" : 0x0001, - "SO_REUSEADDR" : 0x0002, - "SO_TYPE" : 0x0003, - "SO_ERROR" : 0x0004, - "SO_DONTROUTE" : 0x0005, - "SO_BROADCAST" : 0x0006, - "SO_SNDBUF" : 0x0007, - "SO_RCVBUF" : 0x0008, - "SO_KEEPALIVE" : 0x0009, - "SO_OOBINLINE" : 0x000a, - "SO_LINGER" : 0x000d, - "SO_REUSEPORT" : 0x000f, - "SO_SNDLOWAT" : 0x0013, - "SO_RCVLOWAT" : 0x0012, - "SO_SNDTIMEO" : 0x0015, - "SO_RCVTIMEO" : 0x0014, -} - - -linux_mips_socket_types = { - 'SOCK_STREAM' : 0x2, - 'SOCK_DGRAM' : 0x1, - 'SOCK_RAW' : 0x3, - 'SOCK_RDM' : 0x4, - 'SOCK_SEQPACKET' : 0x5, - 'SOCK_DCCP' : 0x6, - 'SOCK_PACKET' : 0xa, -} +class linux_arm_socket_level(Enum): + IPPROTO_IP = 0x00 + SOL_SOCKET = 0x01 + IPPROTO_TCP = 0x06 + IPPROTO_UDP = 0x11 + IPPROTO_IPV6 = 0x29 + IPPROTO_RAW = 0xff -linux_mips_socket_domain = { - 'AF_UNSPEC' : 0x0, - 'AF_FILE' : 0x1, - 'AF_UNIX' : 0x1, - 'AF_LOCAL' : 0x1, - 'AF_INET' : 0x2, - 'AF_AX25' : 0x3, - 'AF_IPX' : 0x4, - 'AF_APPLETALK' : 0x5, - 'AF_NETROM' : 0x6, - 'AF_BRIDGE' : 0x7, - 'AF_ATMPVC' : 0x8, - 'AF_X25' : 0x9, - 'AF_INET6' : 0xa, - 'AF_ROSE' : 0xb, - 'AF_DECnet' : 0xc, - 'AF_NETBEUI' : 0xd, - 'AF_SECURITY' : 0xe, - 'AF_KEY' : 0xf, - 'AF_NETLINK' : 0x10, - 'AF_ROUTE' : 0x10, - 'AF_PACKET' : 0x11, - 'AF_ASH' : 0x12, - 'AF_ECONET' : 0x13, - 'AF_ATMSVC' : 0x14, - 'AF_RDS' : 0x15, - 'AF_SNA' : 0x16, - 'AF_IRDA' : 0x17, - 'AF_PPPOX' : 0x18, - 'AF_WANPIPE' : 0x19, - 'AF_LLC' : 0x1a, - 'AF_IB' : 0x1b, - 'AF_MPLS' : 0x1c, - 'AF_CAN' : 0x1d, - 'AF_TIPC' : 0x1e, - 'AF_BLUETOOTH' : 0x1f, - 'AF_IUCV' : 0x20, - 'AF_RXRPC' : 0x21, - 'AF_ISDN' : 0x22, - 'AF_PHONE' : 0x23, - 'AF_IEEE802154' : 0x24, - 'AF_CAIF' : 0x25, - 'AF_ALG' : 0x26, - 'AF_NFC' : 0x27, - 'AF_VSOCK' : 0x28, - 'AF_KCM' : 0x29, - 'AF_QIPCRTR' : 0x2a, - 'AF_SMC' : 0x2b, - 'AF_MAX' : 0x2c, -} +# https://gfiber.googlesource.com/toolchains/mindspeed/+/refs/heads/newkernel_dev/arm-unknown-linux-gnueabi/sysroot/usr/include/asm/socket.h +class linux_arm_socket_options(Enum): + SO_DEBUG = 0x01 + SO_REUSEADDR = 0x02 + SO_TYPE = 0x03 + SO_ERROR = 0x04 + SO_DONTROUTE = 0x05 + SO_BROADCAST = 0x06 + SO_SNDBUF = 0x07 + SO_RCVBUF = 0x08 + SO_KEEPALIVE = 0x09 + SO_OOBINLINE = 0x0a + SO_LINGER = 0x0d + SO_REUSEPORT = 0x0f + SO_SNDLOWAT = 0x13 + SO_RCVLOWAT = 0x12 + SO_SNDTIMEO = 0x15 + SO_RCVTIMEO = 0x14 + + +class linux_mips_socket_types(Enum): + SOCK_STREAM = 0x2 + SOCK_DGRAM = 0x1 + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_DCCP = 0x6 + SOCK_PACKET = 0xa + + +class linux_mips_socket_domain(Enum): + AF_UNSPEC = 0x00 + AF_FILE = 0x01 + AF_UNIX = 0x01 + AF_LOCAL = 0x01 + AF_INET = 0x02 + AF_AX25 = 0x03 + AF_IPX = 0x04 + AF_APPLETALK = 0x05 + AF_NETROM = 0x06 + AF_BRIDGE = 0x07 + AF_ATMPVC = 0x08 + AF_X25 = 0x09 + AF_INET6 = 0x0a + AF_ROSE = 0x0b + AF_DECnet = 0x0c + AF_NETBEUI = 0x0d + AF_SECURITY = 0x0e + AF_KEY = 0x0f + AF_NETLINK = 0x10 + AF_ROUTE = 0x10 + AF_PACKET = 0x11 + AF_ASH = 0x12 + AF_ECONET = 0x13 + AF_ATMSVC = 0x14 + AF_RDS = 0x15 + AF_SNA = 0x16 + AF_IRDA = 0x17 + AF_PPPOX = 0x18 + AF_WANPIPE = 0x19 + AF_LLC = 0x1a + AF_IB = 0x1b + AF_MPLS = 0x1c + AF_CAN = 0x1d + AF_TIPC = 0x1e + AF_BLUETOOTH = 0x1f + AF_IUCV = 0x20 + AF_RXRPC = 0x21 + AF_ISDN = 0x22 + AF_PHONE = 0x23 + AF_IEEE802154 = 0x24 + AF_CAIF = 0x25 + AF_ALG = 0x26 + AF_NFC = 0x27 + AF_VSOCK = 0x28 + AF_KCM = 0x29 + AF_QIPCRTR = 0x2a + AF_SMC = 0x2b + AF_MAX = 0x2c # https://docs.huihoo.com/doxygen/linux/kernel/3.7/arch_2mips_2include_2uapi_2asm_2socket_8h_source.html # https://android-review.linaro.org/plugins/gitiles/platform/prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.4.3/+/78060bd30f50c43c7442f32e7740efcdb87ba587/sysroot/usr/include/linux/in.h -linux_mips_socket_level = { - 'SOL_SOCKET' : 0xffff, - 'IPPROTO_IP' : 0x0000, - 'IPPROTO_TCP' : 0x0006, - 'IPPROTO_UDP' : 0x0011, - 'IPPROTO_IPV6' : 0x0029, - 'IPPROTO_RAW' : 0x00ff, -} +class linux_mips_socket_level(Enum): + SOL_SOCKET = 0xffff + IPPROTO_IP = 0x0000 + IPPROTO_TCP = 0x0006 + IPPROTO_UDP = 0x0011 + IPPROTO_IPV6 = 0x0029 + IPPROTO_RAW = 0x00ff + # https://docs.huihoo.com/doxygen/linux/kernel/3.7/arch_2mips_2include_2uapi_2asm_2socket_8h_source.html # https://github.com/torvalds/linux/blob/master/arch/mips/include/uapi/asm/socket.h -linux_mips_socket_options = { - "SO_DEBUG" : 0x0001, - "SO_REUSEADDR" : 0x0004, - "SO_KEEPALIVE" : 0x0008, - "SO_DONTROUTE" : 0x0010, - "SO_BINDTODEVICE" : 0x0019, - "SO_BROADCAST" : 0x0020, - "SO_LINGER" : 0x0080, - "SO_OOBINLINE" : 0x0100, - "SO_REUSEPORT" : 0x0200, - "SO_SNDBUF" : 0x1001, - "SO_RCVBUF" : 0x1002, - "SO_SNDLOWAT" : 0x1003, - "SO_RCVLOWAT" : 0x1004, - "SO_SNDTIMEO_OLD" : 0x1005, - "SO_RCVTIMEO_OLD" : 0x1006, - "SO_TIMESTAMP_OLD" : 0x001d, - # "SO_TIMESTAMPNS_OLD" : 0x0023, - # "SO_TIMESTAMPING_OLD" : 0x0025, - "SO_TIMESTAMP_NEW" : 0x003f, - "SO_TIMESTAMPNS_NEW" : 0x0040, - "SO_TIMESTAMPING_NEW" : 0x0041, - "SO_RCVTIMEO_NEW" : 0x0042, - "SO_SNDTIMEO_NEW" : 0x0043, -} - - -linux_mips_socket_ip_options = { - "IP_TOS" : 0x0001, - "IP_TTL" : 0x0002, - "IP_HDRINCL" : 0x0003, - "IP_OPTIONS" : 0x0004, - "IP_ROUTER_ALERT" : 0x0005, - "IP_RECVOPTS" : 0x0006, - "IP_RETOPTS" : 0x0007, - "IP_PKTINFO" : 0x0008, - "IP_MTU_DISCOVER" : 0x000a, - "IP_RECVERR" : 0x000b, - "IP_RECVTTL" : 0x000c, - "IP_RECVTOS" : 0x000d, - "IP_MTU" : 0x000e, - "IP_FREEBIND" : 0x000f, - "IP_PASSSEC" : 0x0012, - "IP_TRANSPARENT" : 0x0013, - "IP_RECVORIGDSTADDR" : 0x0014, - "IP_NODEFRAG" : 0x0016, - "IP_BIND_ADDRESS_NO_PORT" : 0x0018, - "IP_MULTICAST_IF" : 0x0020, - "IP_MULTICAST_TTL" : 0x0021, - "IP_MULTICAST_LOOP" : 0x0022, - "IP_ADD_MEMBERSHIP" : 0x0023, - "IP_DROP_MEMBERSHIP" : 0x0024, - "IP_UNBLOCK_SOURCE" : 0x0025, - "IP_BLOCK_SOURCE" : 0x0026, - "IP_ADD_SOURCE_MEMBERSHIP" : 0x0027, - "IP_DROP_SOURCE_MEMBERSHIP" : 0x0028, - "IP_MSFILTER" : 0x0029, - "IP_MULTICAST_ALL" : 0x0031, - "SO_SNDTIMEO_OLD" : 0x1005, - "SO_RCVTIMEO_OLD" : 0x1006, - "SO_TIMESTAMP_OLD" : 0x001d, - # "SO_TIMESTAMPNS_OLD" : 0x0023, - # "SO_TIMESTAMPING_OLD" : 0x0025, - "SO_TIMESTAMP_NEW" : 0x003f, - "SO_TIMESTAMPNS_NEW" : 0x0040, - "SO_TIMESTAMPING_NEW" : 0x0041, - "SO_RCVTIMEO_NEW" : 0x0042, - "SO_SNDTIMEO_NEW" : 0x0043, -} - -open_flags_name = [ - "O_RDONLY", - "O_WRONLY", - "O_RDWR", - "O_NONBLOCK", - "O_APPEND", - "O_ASYNC", - "O_SYNC", - "O_NOFOLLOW", - "O_CREAT", - "O_TRUNC", - "O_EXCL", - "O_NOCTTY", - "O_DIRECTORY", - "O_BINARY", - "O_LARGEFILE" -] - -macos_x86_open_flags = { - "O_RDONLY": 0x0, - "O_WRONLY": 0x1, - "O_RDWR": 0x2, - "O_NONBLOCK": 0x4, - "O_APPEND": 0x8, - "O_ASYNC": 0x40, - "O_SYNC": 0x80, - "O_NOFOLLOW": 0x100, - "O_CREAT": 0x200, - "O_TRUNC": 0x400, - "O_EXCL": 0x800, - "O_NOCTTY": 0x20000, - "O_DIRECTORY": 0x100000, - "O_BINARY": None, - 'O_LARGEFILE': None -} - -linux_x86_open_flags = { - 'O_RDONLY': 0x0, - 'O_WRONLY': 0x1, - 'O_RDWR': 0x2, - 'O_NONBLOCK': 0x800, - 'O_APPEND': 0x400, - 'O_ASYNC': 0x2000, - 'O_SYNC': 0x101000, - 'O_NOFOLLOW': 0x20000, - 'O_CREAT': 0x40, - 'O_TRUNC': 0x200, - 'O_EXCL': 0x80, - 'O_NOCTTY': 0x100, - 'O_DIRECTORY': 0x10000, - 'O_BINARY': None, - 'O_LARGEFILE': 0x0 -} - -linux_arm_open_flags = { - 'O_RDONLY': 0x0, - 'O_WRONLY': 0x1, - 'O_RDWR': 0x2, - 'O_NONBLOCK': 0x800, - 'O_APPEND': 0x400, - 'O_ASYNC': 0x2000, - 'O_SYNC': 0x101000, - 'O_NOFOLLOW': 0x8000, - 'O_CREAT': 0x40, - 'O_TRUNC': 0x200, - 'O_EXCL': 0x80, - 'O_NOCTTY': 0x100, - 'O_DIRECTORY': 0x4000, - 'O_BINARY': None, - 'O_LARGEFILE': 0x20000 -} - -linux_mips_open_flags = { - 'O_RDONLY': 0x0, - 'O_WRONLY': 0x1, - 'O_RDWR': 0x2, - 'O_NONBLOCK': 0x80, - 'O_APPEND': 0x8, - 'O_ASYNC': 0x1000, - 'O_SYNC': 0x4010, - 'O_NOFOLLOW': 0x20000, - 'O_CREAT': 0x100, - 'O_TRUNC': 0x200, - 'O_EXCL': 0x400, - 'O_NOCTTY': 0x800, - 'O_DIRECTORY': 0x10000, - 'O_BINARY' : None, - 'O_LARGEFILE': 0x2000 -} - -linux_riscv_open_flags = { - 'O_RDONLY': 0x0, - 'O_WRONLY': 0x1, - 'O_RDWR': 0x2, - 'O_NONBLOCK': 0x800, - 'O_APPEND': 0x400, - 'O_ASYNC': 0x2000, - 'O_SYNC': 0x101000, - 'O_NOFOLLOW': 0x20000, - 'O_CREAT': 0x40, - 'O_TRUNC': 0x200, - 'O_EXCL': 0x80, - 'O_NOCTTY': 0x100, - 'O_DIRECTORY': 0x10000, - 'O_BINARY' : None, - 'O_LARGEFILE': None, -} - -linux_ppc_open_flags = { - 'O_RDONLY': 0x0, - 'O_WRONLY': 0x1, - 'O_RDWR': 0x2, - 'O_NONBLOCK': 0x800, - 'O_APPEND': 0x400, - 'O_ASYNC': 0x2000, - 'O_SYNC': 0x101000, - 'O_NOFOLLOW': 0x8000, - 'O_CREAT': 0x40, - 'O_TRUNC': 0x200, - 'O_EXCL': 0x80, - 'O_NOCTTY': 0x100, - 'O_DIRECTORY': 0x4000, - 'O_BINARY' : None, - 'O_LARGEFILE': 0x10000, -} - -freebsd_x86_open_flags = { - 'O_RDONLY': 0x0, - 'O_WRONLY': 0x1, - 'O_RDWR': 0x2, - 'O_NONBLOCK': 0x4, - 'O_APPEND': 0x8, - 'O_ASYNC': 0x40, - 'O_SYNC': 0x80, - 'O_NOFOLLOW': 0x100, - 'O_CREAT': 0x200, - 'O_TRUNC': 0x400, - 'O_EXCL': 0x800, - 'O_NOCTTY': 0x8000, - 'O_DIRECTORY': 0x20000, - 'O_BINARY' : None, - 'O_LARGEFILE': None -} - -windows_x86_open_flags = { - 'O_RDONLY': 0x0, - 'O_WRONLY': 0x1, - 'O_RDWR': 0x2, - 'O_NONBLOCK': None, - 'O_APPEND': 0x8, - 'O_ASYNC': None, - 'O_SYNC': None, - 'O_NOFOLLOW': None, - 'O_CREAT': 0x100, - 'O_TRUNC': 0x200, - 'O_EXCL': 0x400, - 'O_NOCTTY': None, - 'O_DIRECTORY': None, - 'O_BINARY': 0x8000, - 'O_LARGEFILE': None -} - -qnx_arm64_open_flags = { - 'O_RDONLY' : 0x00000, - 'O_WRONLY' : 0x00001, - 'O_RDWR' : 0x00002, - 'O_APPEND' : 0x00008, - 'O_SYNC' : 0x00020, - 'O_NONBLOCK' : 0x00080, - 'O_CREAT' : 0x00100, - 'O_TRUNC' : 0x00200, - 'O_EXCL' : 0x00400, - 'O_NOCTTY' : 0x00800, - 'O_LARGEFILE' : 0x08000, - 'O_ASYNC' : 0x10000, - 'O_NOFOLLOW' : None, - 'O_DIRECTORY' : None, - 'O_BINARY' : None -} - +class linux_mips_socket_options(Enum): + SO_DEBUG = 0x01 + SO_REUSEADDR = 0x04 + SO_KEEPALIVE = 0x08 + SO_DONTROUTE = 0x10 + SO_BINDTODEVICE = 0x19 + SO_BROADCAST = 0x20 + SO_LINGER = 0x80 + SO_OOBINLINE = 0x00 + SO_REUSEPORT = 0x00 + SO_SNDBUF = 0x01 + SO_RCVBUF = 0x02 + SO_SNDLOWAT = 0x03 + SO_RCVLOWAT = 0x04 + SO_SNDTIMEO_OLD = 0x05 + SO_RCVTIMEO_OLD = 0x06 + SO_TIMESTAMP_OLD = 0x1d + # SO_TIMESTAMPNS_OLD = 0x23 + # SO_TIMESTAMPING_OLD = 0x25 + SO_TIMESTAMP_NEW = 0x3f + SO_TIMESTAMPNS_NEW = 0x40 + SO_TIMESTAMPING_NEW = 0x41 + SO_RCVTIMEO_NEW = 0x42 + SO_SNDTIMEO_NEW = 0x43 + + +class linux_mips_socket_ip_options(Enum): + IP_TOS = 0x0001 + IP_TTL = 0x0002 + IP_HDRINCL = 0x0003 + IP_OPTIONS = 0x0004 + IP_ROUTER_ALERT = 0x0005 + IP_RECVOPTS = 0x0006 + IP_RETOPTS = 0x0007 + IP_PKTINFO = 0x0008 + IP_MTU_DISCOVER = 0x000a + IP_RECVERR = 0x000b + IP_RECVTTL = 0x000c + IP_RECVTOS = 0x000d + IP_MTU = 0x000e + IP_FREEBIND = 0x000f + IP_PASSSEC = 0x0012 + IP_TRANSPARENT = 0x0013 + IP_RECVORIGDSTADDR = 0x0014 + IP_NODEFRAG = 0x0016 + IP_BIND_ADDRESS_NO_PORT = 0x0018 + IP_MULTICAST_IF = 0x0020 + IP_MULTICAST_TTL = 0x0021 + IP_MULTICAST_LOOP = 0x0022 + IP_ADD_MEMBERSHIP = 0x0023 + IP_DROP_MEMBERSHIP = 0x0024 + IP_UNBLOCK_SOURCE = 0x0025 + IP_BLOCK_SOURCE = 0x0026 + IP_ADD_SOURCE_MEMBERSHIP = 0x0027 + IP_DROP_SOURCE_MEMBERSHIP = 0x0028 + IP_MSFILTER = 0x0029 + IP_MULTICAST_ALL = 0x0031 + SO_SNDTIMEO_OLD = 0x1005 + SO_RCVTIMEO_OLD = 0x1006 + SO_TIMESTAMP_OLD = 0x001d + # SO_TIMESTAMPNS_OLD = 0x0023 + # SO_TIMESTAMPING_OLD = 0x0025 + SO_TIMESTAMP_NEW = 0x003f + SO_TIMESTAMPNS_NEW = 0x0040 + SO_TIMESTAMPING_NEW = 0x0041 + SO_RCVTIMEO_NEW = 0x0042 + SO_SNDTIMEO_NEW = 0x0043 + + + +class QlPrettyFlag(Flag): + """Subclass the Flag type to provide a more adequate string representation. + """ + + def __str__(self) -> str: + _, _, s = super().__str__().partition('.') + + return s.replace('|', ' | ') + +################################ +# open flags # +################################ + +class macos_x86_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = 0x000004 + O_APPEND = 0x000008 + O_ASYNC = 0x000040 + O_SYNC = 0x000080 + O_NOFOLLOW = 0x000100 + O_CREAT = 0x000200 + O_TRUNC = 0x000400 + O_EXCL = 0x000800 + O_NOCTTY = 0x020000 + O_DIRECTORY = 0x100000 + O_BINARY = None + O_LARGEFILE = None + + +class linux_x86_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = 0x000800 + O_APPEND = 0x000400 + O_ASYNC = 0x002000 + O_SYNC = 0x101000 + O_NOFOLLOW = 0x020000 + O_CREAT = 0x000040 + O_TRUNC = 0x000200 + O_EXCL = 0x000080 + O_NOCTTY = 0x000100 + O_DIRECTORY = 0x010000 + O_BINARY = None + O_LARGEFILE = None + + +class linux_arm_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = 0x000800 + O_APPEND = 0x000400 + O_ASYNC = 0x002000 + O_SYNC = 0x101000 + O_NOFOLLOW = 0x008000 + O_CREAT = 0x000040 + O_TRUNC = 0x000200 + O_EXCL = 0x000080 + O_NOCTTY = 0x000100 + O_DIRECTORY = 0x004000 + O_BINARY = None + O_LARGEFILE = 0x020000 + + +class linux_mips_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = 0x000080 + O_APPEND = 0x000008 + O_ASYNC = 0x001000 + O_SYNC = 0x004010 + O_NOFOLLOW = 0x020000 + O_CREAT = 0x000100 + O_TRUNC = 0x000200 + O_EXCL = 0x000400 + O_NOCTTY = 0x000800 + O_DIRECTORY = 0x010000 + O_BINARY = None + O_LARGEFILE = 0x002000 + + +class linux_riscv_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = 0x000800 + O_APPEND = 0x000400 + O_ASYNC = 0x002000 + O_SYNC = 0x101000 + O_NOFOLLOW = 0x020000 + O_CREAT = 0x000040 + O_TRUNC = 0x000200 + O_EXCL = 0x000080 + O_NOCTTY = 0x000100 + O_DIRECTORY = 0x010000 + O_BINARY = None + O_LARGEFILE = None + + +class linux_ppc_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = 0x000800 + O_APPEND = 0x000400 + O_ASYNC = 0x002000 + O_SYNC = 0x101000 + O_NOFOLLOW = 0x008000 + O_CREAT = 0x000040 + O_TRUNC = 0x000200 + O_EXCL = 0x000080 + O_NOCTTY = 0x000100 + O_DIRECTORY = 0x004000 + O_BINARY = None + O_LARGEFILE = 0x010000 + + +class freebsd_x86_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = 0x000004 + O_APPEND = 0x000008 + O_ASYNC = 0x000040 + O_SYNC = 0x000080 + O_NOFOLLOW = 0x000100 + O_CREAT = 0x000200 + O_TRUNC = 0x000400 + O_EXCL = 0x000800 + O_NOCTTY = 0x008000 + O_DIRECTORY = 0x20000 + O_BINARY = None + O_LARGEFILE = None + + +class windows_x86_open_flags(QlPrettyFlag): + O_RDONLY = 0x000000 + O_WRONLY = 0x000001 + O_RDWR = 0x000002 + O_NONBLOCK = None + O_APPEND = 0x000008 + O_ASYNC = None + O_SYNC = None + O_NOFOLLOW = None + O_CREAT = 0x000100 + O_TRUNC = 0x000200 + O_EXCL = 0x000400 + O_NOCTTY = None + O_DIRECTORY = None + O_BINARY = 0x008000 + O_LARGEFILE = None + + +class qnx_arm_open_flags(QlPrettyFlag): + O_RDONLY = 0x00000 + O_WRONLY = 0x00001 + O_RDWR = 0x00002 + O_NONBLOCK = 0x00080 + O_APPEND = 0x00008 + O_ASYNC = 0x10000 + O_SYNC = 0x00020 + O_NOFOLLOW = None + O_CREAT = 0x00100 + O_TRUNC = 0x00200 + O_EXCL = 0x00400 + O_NOCTTY = 0x00800 + O_DIRECTORY = None + O_BINARY = None + O_LARGEFILE = 0x08000 + + +################################ +# mmap flags # +################################ # see: https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/mman-common.h class linux_mmap_flags(Flag): @@ -731,15 +722,27 @@ class qnx_mmap_flags(Flag): # define this alias for compatibility with other os flags MAP_UNINITIALIZED = MAP_NOINIT + +class qnx_mmap_prot_flags(QlPrettyFlag): + PROT_NONE = 0x00000000 + PROT_READ = 0x00000001 + PROT_WRITE = 0x00000002 + PROT_EXEC = 0x00000004 + + # not supported by unicorn + PROT_GROWSDOWN = 0x01000000 + PROT_GROWSUP = 0x02000000 + + # fcntl flags -F_DUPFD = 0 -F_GETFD = 1 -F_SETFD = 2 -F_GETFL = 3 -F_SETFL = 4 -F_GETLK = 5 -F_SETLK = 6 -F_SETLKW = 7 +F_DUPFD = 0 +F_GETFD = 1 +F_SETFD = 2 +F_GETFL = 3 +F_SETFL = 4 +F_GETLK = 5 +F_SETLK = 6 +F_SETLKW = 7 FD_CLOEXEC = 1 diff --git a/qiling/os/posix/const_mapping.py b/qiling/os/posix/const_mapping.py index 97deeaa77..2832ae83b 100644 --- a/qiling/os/posix/const_mapping.py +++ b/qiling/os/posix/const_mapping.py @@ -3,26 +3,17 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from typing import Mapping, TypeVar +from __future__ import annotations +from typing import TYPE_CHECKING, Dict, Mapping, Type, Union -from qiling import Qiling from qiling.const import QL_ARCH, QL_OS +from qiling.os.posix.const import * -from .const import * +if TYPE_CHECKING: + from qiling import Qiling -KT = TypeVar('KT') -VT = TypeVar('VT') - -def __invert_dict(d: Mapping[KT, VT]) -> Mapping[VT, KT]: - return {v: k for k, v in d.items()} - - -def _constant_mapping(bits: int, consts_map: Mapping[str, int]) -> str: - return __invert_dict(consts_map)[bits] - - -def _flags_mapping(value: int, flags_map: Mapping[str, int]) -> str: +def flags_mapping(value: int, flags_map: Mapping[str, int]) -> str: names = [] for name, flag in flags_map.items(): @@ -36,105 +27,110 @@ def _flags_mapping(value: int, flags_map: Mapping[str, int]) -> str: return ' | '.join(names) -def ql_open_flag_mapping(ql: Qiling, flags: int) -> int: - def flag_mapping(flags, mapping_name, mapping_from, mapping_to, host_os): - ret = 0 +def get_open_flags_class(archtype: QL_ARCH, ostype: QL_OS) -> Union[Type[Flag], None]: + """Retrieve the appropriate open flags class for given architecture and OS. + + Args: + archtype: architecture type + otype: operating system type + + Returns: appropriate flags class, or `None` if the specified arch and OS combination + is not supported + """ + + flags_by_os: Dict[QL_OS, Dict[QL_ARCH, Type[Flag]]] = { + QL_OS.LINUX: { + QL_ARCH.X86: linux_x86_open_flags, + QL_ARCH.X8664: linux_x86_open_flags, + QL_ARCH.ARM: linux_arm_open_flags, + QL_ARCH.ARM64: linux_arm_open_flags, + QL_ARCH.MIPS: linux_mips_open_flags, + QL_ARCH.RISCV: linux_riscv_open_flags, + QL_ARCH.RISCV64: linux_riscv_open_flags, + QL_ARCH.PPC: linux_ppc_open_flags + }, + + QL_OS.FREEBSD: { + QL_ARCH.X86: freebsd_x86_open_flags, + QL_ARCH.X8664: freebsd_x86_open_flags + }, + + QL_OS.MACOS: { + QL_ARCH.X86: macos_x86_open_flags, + QL_ARCH.X8664: macos_x86_open_flags + }, + + QL_OS.WINDOWS: { + QL_ARCH.X86: windows_x86_open_flags, + QL_ARCH.X8664: windows_x86_open_flags + }, + + QL_OS.QNX: { + QL_ARCH.ARM: qnx_arm_open_flags, + QL_ARCH.ARM64: qnx_arm_open_flags + } + } - for n in mapping_name: - if mapping_from[n] is None or mapping_to[n] is None: - continue + cls = None - if (flags & mapping_from[n]) == mapping_from[n]: - ret = ret | mapping_to[n] + if ostype in flags_by_os: + flags_by_arch = flags_by_os[ostype] - if host_os is QL_OS.WINDOWS: - ret = ret | mapping_to['O_BINARY'] + if archtype in flags_by_arch: + cls = flags_by_arch[archtype] - return ret + return cls - f = {} - t = {} - host_os = ql.host.os - virt_os = ql.os.type +def ql_open_flag_mapping(ql: Qiling, flags: int) -> int: + """Convert emulated OS 'open' flags to the hosting OS flags. + """ - if host_os is None: - return flags + archtype = ql.host.arch + ostype = ql.host.os - if virt_os == QL_OS.LINUX: - if ql.arch.type in (QL_ARCH.X86, QL_ARCH.X8664): - f = linux_x86_open_flags - elif ql.arch.type in (QL_ARCH.ARM, QL_ARCH.ARM64): - f = linux_arm_open_flags - elif ql.arch.type == QL_ARCH.MIPS: - f = linux_mips_open_flags - elif ql.arch.type in (QL_ARCH.RISCV, QL_ARCH.RISCV64): - f = linux_riscv_open_flags - elif ql.arch.type == QL_ARCH.PPC: - f = linux_ppc_open_flags - - elif virt_os == QL_OS.MACOS: - if ql.arch.type in (QL_ARCH.X86, QL_ARCH.X8664): - f = macos_x86_open_flags - elif virt_os == QL_OS.FREEBSD: - f = freebsd_x86_open_flags - elif virt_os == QL_OS.WINDOWS: - f = windows_x86_open_flags - elif virt_os == QL_OS.QNX: - f = qnx_arm64_open_flags - - t = { - QL_OS.LINUX: linux_x86_open_flags, - QL_OS.MACOS: macos_x86_open_flags, - QL_OS.FREEBSD: freebsd_x86_open_flags, - QL_OS.WINDOWS: windows_x86_open_flags - }.get(host_os, {}) - - if f == t: + if archtype is None or ostype is None: return flags - return flag_mapping(flags, open_flags_name, f, t, host_os) + host_flags = get_open_flags_class(archtype, ostype) + if host_flags is None: + raise NotImplementedError(f'flags were not defined for hosting {archtype.name} {ostype.name}') -def mmap_flag_mapping(flags): - mmap_flags = { - 'MAP_SHARED' : 0x00000001, - 'MAP_PRIVATE' : 0x00000002, - 'MAP_FIXED' : 0x00000010, - 'MAP_ANONYMOUS' : 0x00000020, + archtype = ql.arch.type + ostype = ql.os.type - # QNX (openqnx) - # lib/c/public/sys/mman.h - 'MAP_NOINIT' : 0x00004000, - 'MAP_PHYS' : 0x00010000, - 'MAP_NOX64K' : 0x00020000, - 'MAP_BELOW16M' : 0x00040000, - 'MAP_ANON' : 0x00080000, - 'MAP_SYSRAM' : 0x01000000 - } + emul_flags = get_open_flags_class(archtype, ostype) - return _flags_mapping(flags, mmap_flags) + if emul_flags is None: + raise NotImplementedError(f'flags were not defined for emulated {archtype.name} {ostype.name}') + # both hosting and emulated os are using the same flags set; no need to convert + if emul_flags is host_flags: + return flags -def mmap_prot_mapping(prots: int) -> str: - if prots == 0: - return 'PROT_NONE' + ret = 0 - mmap_prots = { - 'PROT_READ' : 0b001, - 'PROT_WRITE': 0b010, - 'PROT_EXEC' : 0b100, + # convert emulated os flags to hosting os flags. + # flags names are consistent across all classes, even if they are not supported, to maintain compatibility + for ef in emul_flags: + # test whether flag i set, excluding unsupported flags and 0 values + if ef and flags & ef.value: + hf = host_flags[ef.name or ''] - # not supported by unicorn - 'PROT_GROWSDOWN' : 0x01000000, - 'PROT_GROWSUP' : 0x02000000 - } + # if flag is also supported on the host, set it + if hf: + ret |= hf.value - return _flags_mapping(prots, mmap_prots) + # NOTE: not sure why this one is needed + if ql.host.os is QL_OS.WINDOWS: + ret |= host_flags['O_BINARY'].value + return ret -def socket_type_mapping(t: int, archtype: QL_ARCH) -> str: - socket_type_map = { + +def socket_type_mapping(value: int, archtype: QL_ARCH) -> str: + socket_types: Type[Enum] = { QL_ARCH.X86: linux_x86_socket_types, QL_ARCH.X8664: linux_x86_socket_types, QL_ARCH.ARM: linux_arm_socket_types, @@ -143,23 +139,23 @@ def socket_type_mapping(t: int, archtype: QL_ARCH) -> str: }[archtype] # https://code.woboq.org/linux/linux/net/socket.c.html#1363 - return _constant_mapping(t & SOCK_TYPE_MASK, socket_type_map) + return socket_types(value & SOCK_TYPE_MASK).name -def socket_domain_mapping(p: int, archtype: QL_ARCH, ostype: QL_OS) -> str: - socket_domain_map = { +def socket_domain_mapping(value: int, archtype: QL_ARCH, ostype: QL_OS) -> str: + socket_domain: Type[Enum] = { QL_ARCH.X86: linux_x86_socket_domain, - QL_ARCH.X8664: macos_x86_socket_domain if ostype == QL_OS.MACOS else linux_x86_socket_domain, + QL_ARCH.X8664: macos_x86_socket_domain if ostype is QL_OS.MACOS else linux_x86_socket_domain, QL_ARCH.ARM: linux_arm_socket_domain, QL_ARCH.ARM64: linux_arm_socket_domain, QL_ARCH.MIPS: linux_mips_socket_domain }[archtype] - return _constant_mapping(p, socket_domain_map) + return socket_domain(value).name -def socket_tcp_option_mapping(t: int, archtype: QL_ARCH) -> str: - socket_option_map = { +def socket_tcp_option_mapping(value: int, archtype: QL_ARCH) -> str: + socket_option: Type[Enum] = { QL_ARCH.X86: linux_socket_tcp_options, QL_ARCH.X8664: linux_socket_tcp_options, QL_ARCH.ARM: linux_socket_tcp_options, @@ -167,11 +163,11 @@ def socket_tcp_option_mapping(t: int, archtype: QL_ARCH) -> str: QL_ARCH.MIPS: linux_socket_tcp_options, }[archtype] - return _constant_mapping(t, socket_option_map) + return socket_option(value).name -def socket_level_mapping(t: int, archtype: QL_ARCH) -> str: - socket_level_map = { +def socket_level_mapping(value: int, archtype: QL_ARCH) -> str: + socket_level: Type[Enum] = { QL_ARCH.X86: linux_x86_socket_level, QL_ARCH.X8664: linux_x86_socket_level, QL_ARCH.ARM: linux_arm_socket_level, @@ -179,23 +175,23 @@ def socket_level_mapping(t: int, archtype: QL_ARCH) -> str: QL_ARCH.MIPS: linux_mips_socket_level }[archtype] - return _constant_mapping(t, socket_level_map) + return socket_level(value).name -def socket_ip_option_mapping(t: int, archtype: QL_ARCH, ostype: QL_OS) -> str: - socket_option_map = { +def socket_ip_option_mapping(value: int, archtype: QL_ARCH, ostype: QL_OS) -> str: + socket_ip_option: Type[Enum] = { QL_ARCH.X86: linux_socket_ip_options, - QL_ARCH.X8664: macos_socket_ip_options if ostype == QL_OS.MACOS else linux_socket_ip_options, + QL_ARCH.X8664: macos_socket_ip_options if ostype is QL_OS.MACOS else linux_socket_ip_options, QL_ARCH.ARM: linux_socket_ip_options, - QL_ARCH.ARM64: macos_socket_ip_options if ostype == QL_OS.MACOS else linux_socket_ip_options, + QL_ARCH.ARM64: macos_socket_ip_options if ostype is QL_OS.MACOS else linux_socket_ip_options, QL_ARCH.MIPS: linux_mips_socket_ip_options }[archtype] - return _constant_mapping(t, socket_option_map) + return socket_ip_option(value).name -def socket_option_mapping(t: int, archtype: QL_ARCH) -> str: - socket_option_map = { +def socket_option_mapping(value: int, archtype: QL_ARCH) -> str: + socket_option: Type[Enum] = { QL_ARCH.X86: linux_x86_socket_options, QL_ARCH.X8664: linux_x86_socket_options, QL_ARCH.ARM: linux_arm_socket_options, @@ -203,4 +199,10 @@ def socket_option_mapping(t: int, archtype: QL_ARCH) -> str: QL_ARCH.MIPS: linux_mips_socket_options }[archtype] - return _constant_mapping(t, socket_option_map) + return socket_option(value).name + + +__all__ = [ + 'flags_mapping', 'get_open_flags_class', 'ql_open_flag_mapping', 'socket_type_mapping', 'socket_domain_mapping', + 'socket_tcp_option_mapping', 'socket_level_mapping', 'socket_ip_option_mapping', 'socket_option_mapping' +] diff --git a/qiling/os/posix/syscall/fcntl.py b/qiling/os/posix/syscall/fcntl.py index 5b1f2a9c3..13d60701e 100644 --- a/qiling/os/posix/syscall/fcntl.py +++ b/qiling/os/posix/syscall/fcntl.py @@ -7,9 +7,8 @@ from qiling import Qiling from qiling.const import QL_OS, QL_ARCH -from qiling.exception import QlSyscallError from qiling.os.posix.const import * -from qiling.os.posix.const_mapping import ql_open_flag_mapping +from qiling.os.posix.const_mapping import ql_open_flag_mapping, get_open_flags_class from qiling.os.posix.filestruct import ql_socket from .unistd import virtual_abspath_at, get_opened_fd @@ -33,8 +32,14 @@ def __do_open(ql: Qiling, absvpath: str, flags: int, mode: int) -> int: try: ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(absvpath, flags, mode) - except QlSyscallError: - return -1 + except FileNotFoundError: + return -ENOENT + except FileExistsError: + return -EEXIST + except IsADirectoryError: + return -EISDIR + except PermissionError: + return -EACCES return idx @@ -54,7 +59,7 @@ def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int): vpath = ql.os.utils.read_cstring(path) absvpath = virtual_abspath_at(ql, vpath, fd) - regreturn = -1 if absvpath is None else __do_open(ql, absvpath, flags, mode) + regreturn = absvpath if isinstance(absvpath, int) else __do_open(ql, absvpath, flags, mode) ql.log.debug(f'openat({fd:d}, "{vpath}", {flags:#x}, 0{mode:o}) = {regreturn:d}') @@ -63,36 +68,14 @@ def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int): def ql_syscall_creat(ql: Qiling, filename: int, mode: int): vpath = ql.os.utils.read_cstring(filename) - - # FIXME: this is broken - flags = posix_open_flags["O_WRONLY"] | posix_open_flags["O_CREAT"] | posix_open_flags["O_TRUNC"] - mode &= 0xffffffff - - idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) - - if idx == -1: - regreturn = -ENOMEM - else: - if ql.arch.type == QL_ARCH.ARM: - mode = 0 - - try: - flags = ql_open_flag_mapping(ql, flags) - ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(vpath, flags, mode) - except QlSyscallError as e: - regreturn = -e.errno - else: - regreturn = idx - - hpath = ql.os.path.virtual_to_host_path(vpath) absvpath = ql.os.path.virtual_abspath(vpath) - ql.log.debug(f'creat("{absvpath}", {mode:#o}) = {regreturn}') + flags_class = get_open_flags_class(ql.arch.type, ql.os.type) + flags = sum(getattr(flags_class, f) for f in ('O_WRONLY', 'O_CREAT', 'O_TRUNC')) - if regreturn >= 0 and regreturn != 2: - ql.log.debug(f'File found: {hpath:s}') - else: - ql.log.debug(f'File not found {hpath:s}') + regreturn = __do_open(ql, absvpath, flags, mode) + + ql.log.debug(f'creat("{absvpath}", 0{mode:o}) = {regreturn}') return regreturn @@ -101,7 +84,7 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int): f = get_opened_fd(ql.os, fd) if f is None: - return -1 + return -EBADF if cmd == F_DUPFD: if arg not in range(NR_OPEN): @@ -131,7 +114,7 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int): regreturn = 0 else: - regreturn = -1 + regreturn = -EINVAL return regreturn diff --git a/qiling/os/posix/syscall/mman.py b/qiling/os/posix/syscall/mman.py index 4990b3c51..81d53564f 100755 --- a/qiling/os/posix/syscall/mman.py +++ b/qiling/os/posix/syscall/mman.py @@ -12,7 +12,7 @@ from qiling.const import QL_ARCH, QL_OS from qiling.exception import QlMemoryMappedError from qiling.os.filestruct import ql_file -from qiling.os.posix.const_mapping import * +from qiling.os.posix.const import * def ql_syscall_munmap(ql: Qiling, addr: int, length: int): @@ -129,7 +129,7 @@ class mmap_flags(IntFlag): if flags & (mmap_flags.MAP_FIXED | mmap_flags.MAP_FIXED_NOREPLACE): # on non-QNX systems, base must be aligned to page boundary if addr & (pagesize - 1) and ql.os.type != QL_OS.QNX: - return -1 # errno: EINVAL + return -EINVAL # if not, use the base address as a hint but always above or equal to # the value specified in /proc/sys/vm/mmap_min_addr (here: mmap_address) @@ -146,7 +146,7 @@ class mmap_flags(IntFlag): if flags & mmap_flags.MAP_FIXED_NOREPLACE: if not ql.mem.is_available(lbound, mapping_size): - return -1 # errno: EEXIST + return -EEXIST elif flags & mmap_flags.MAP_FIXED: ql.log.debug(f'{api_name}: unmapping memory between {lbound:#x}-{ubound:#x} to make room for fixed mapping') @@ -161,15 +161,15 @@ class mmap_flags(IntFlag): label = '[mmap anonymous]' else: - fd = ql.unpacks(ql.pack(fd)) + fd = ql.os.utils.as_signed(fd, 32) if fd not in range(NR_OPEN): - return -1 # errno: EBADF + return -EBADF f: Optional[ql_file] = ql.os.fd[fd] if f is None: - return -1 # errno: EBADF + return -EBADF # set mapping properties for future unmap f._is_map_shared = bool(flags & mmap_flags.MAP_SHARED) @@ -193,7 +193,7 @@ class mmap_flags(IntFlag): ql.mem.map(lbound, mapping_size, info=label) except QlMemoryMappedError: ql.log.debug(f'{api_name}: out of memory') - return -1 # errono: ENOMEM + return -ENOMEM else: if data: ql.mem.write(addr, data) diff --git a/qiling/os/posix/syscall/msg.py b/qiling/os/posix/syscall/msg.py index 8f2f53b97..5bfe71fa2 100644 --- a/qiling/os/posix/syscall/msg.py +++ b/qiling/os/posix/syscall/msg.py @@ -40,7 +40,7 @@ def __perms(ql: Qiling, msq: QlMsqId, flag: int) -> int: # is there some bit set in requested_mode but not in granted_mode? if request_mode & ~granted_mode & 0o007: - return -1 # EACCES + return -EACCES return 0 @@ -53,7 +53,7 @@ def __create_msq(key: int, flags: int) -> int: """ if len(ql.os.msq) >= MSGMNI: - return -1 # ENOSPC + return -ENOSPC mode = flags & ((1 << 9) - 1) @@ -77,16 +77,16 @@ def __create_msq(key: int, flags: int) -> int: msqid = __create_msq(key, msgflg) else: - return -1 # ENOENT + return -ENOENT # a message queue with the specified key exists else: # the user asked to create a new one? if msgflg & (IPC_CREAT | IPC_EXCL): - return -1 # EEXIST + return -EEXIST if __perms(ql, msq, msgflg): - return -1 # EACCES + return -EACCES return msqid @@ -95,11 +95,11 @@ def ql_syscall_msgsnd(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgflg: int msq = ql.os.msq.get_by_id(msqid) if msq is None: - return -1 # EINVAL + return -EINVAL # Check if the user has write permissions for the message queue if __perms(ql, msq, 0o222): # S_IWUGO - return -1 # EACCES + return -EACCES msg_type = ql.mem.read_ptr(msgp) msg_text = ql.mem.read(msgp + ql.arch.pointersize, msgsz) @@ -109,7 +109,7 @@ def ql_syscall_msgsnd(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgflg: int break if msgflg & IPC_NOWAIT: - return -1 # EAGAIN + return -EAGAIN msq.queue.append(QlMsgBuf(msg_type, bytes(msg_text))) @@ -120,15 +120,15 @@ def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int msq = ql.os.msq.get_by_id(msqid) if msq is None: - return -1 # EINVAL + return -EINVAL if msgflg & MSG_COPY: if msgflg & MSG_EXCEPT or not (msgflg & IPC_NOWAIT): - return -1 # EINVAL + return -EINVAL # Check if the user has read permissions for the message queue if __perms(ql, msq, 0o444): # S_IRUGO - return -1 # EACCES + return -EACCES while True: msg = __find_msg(msq, msgtyp, msgflg) @@ -137,17 +137,17 @@ def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int break if msgflg & MSG_COPY: - return -1 # ENOMSG + return -ENOMSG if msgflg & IPC_NOWAIT: - return -1 # ENOMSG + return -ENOMSG if not (msgflg & MSG_COPY): msq.queue.remove(msg) if msgsz < len(msg.mtext): if not (msgflg & MSG_NOERROR): - return -1 # E2BIG + return -E2BIG else: sz = msgsz else: diff --git a/qiling/os/posix/syscall/prctl.py b/qiling/os/posix/syscall/prctl.py index 3cc0e4456..6f515d38a 100644 --- a/qiling/os/posix/syscall/prctl.py +++ b/qiling/os/posix/syscall/prctl.py @@ -5,6 +5,7 @@ from qiling import Qiling from qiling.arch.x86_const import IA32_FS_BASE_MSR, IA32_GS_BASE_MSR +from qiling.os.posix.const import EINVAL def ql_syscall_arch_prctl(ql: Qiling, code: int, addr: int): @@ -29,7 +30,7 @@ def ql_syscall_arch_prctl(ql: Qiling, code: int, addr: int): if code not in handlers: ql.log.debug(f'prctl code {code:#x} not implemented') - return -1 # EINVAL + return -EINVAL handlers[code]() diff --git a/qiling/os/posix/syscall/random.py b/qiling/os/posix/syscall/random.py index 3914da3d9..f0f5cc0a0 100644 --- a/qiling/os/posix/syscall/random.py +++ b/qiling/os/posix/syscall/random.py @@ -6,15 +6,15 @@ import os from qiling import Qiling +from qiling.os.posix.const import EFAULT def ql_syscall_getrandom(ql: Qiling, buf: int, buflen: int, flags: int): - try: - data = os.urandom(buflen) - ql.mem.write(buf, data) - except: - retval = -1 - else: - ql.log.debug(f'getrandom() CONTENT: {data.hex(" ")}') - retval = len(data) + if not ql.mem.is_mapped(buf, buflen): + return -EFAULT - return retval + data = os.urandom(buflen) + ql.mem.write(buf, data) + + ql.log.debug(f'getrandom() CONTENT: {data.hex(" ")}') + + return len(data) diff --git a/qiling/os/posix/syscall/resource.py b/qiling/os/posix/syscall/resource.py index 6d26cdbaf..4841758d7 100644 --- a/qiling/os/posix/syscall/resource.py +++ b/qiling/os/posix/syscall/resource.py @@ -20,16 +20,16 @@ def setrlimit(self, resource, rlim): def __getrlimit_common(ql: Qiling, res: int, rlim: int) -> int: RLIMIT_STACK = 3 + if res == RLIMIT_STACK: - if ql.arch.bits == 64: - stack_size = int(ql.os.profile.get("OS64", "stack_size"), 16) - elif ql.arch.bits == 32: - stack_size = int(ql.os.profile.get("OS32", "stack_size"), 16) + stack_size = ql.os.profile.getint(f"OS{ql.arch.bits}", "stack_size") rlimit = (stack_size, -1) + else: rlimit = resource.getrlimit(res) - - ql.mem.write(rlim, ql.packs(rlimit[0]) + ql.packs(rlimit[1])) + + ql.mem.write_ptr(rlim + 0 * ql.arch.pointersize, rlimit[0], signed=True) + ql.mem.write_ptr(rlim + 1 * ql.arch.pointersize, rlimit[1], signed=True) return 0 @@ -41,7 +41,11 @@ def ql_syscall_getrlimit(ql: Qiling, res: int, rlim: int): def ql_syscall_setrlimit(ql: Qiling, res: int, rlim: int): # maybe we can nop the setrlimit - tmp_rlim = (ql.unpack32s(ql.mem.read(rlim, 4)), ql.unpack32s(ql.mem.read(rlim + 4, 4))) + tmp_rlim = ( + ql.mem.read_ptr(rlim + 0 * 4, 4, signed=True), + ql.mem.read_ptr(rlim + 1 * 4, 4, signed=True) + ) + resource.setrlimit(res, tmp_rlim) return 0 @@ -51,7 +55,10 @@ def ql_syscall_prlimit64(ql: Qiling, pid: int, res: int, new_limit: int, old_lim if pid == 0 and new_limit == 0: try: rlim = resource.getrlimit(res) - ql.mem.write(old_limit, ql.packs(rlim[0]) + ql.packs(rlim[1])) + + ql.mem.write_ptr(old_limit + 0 * ql.arch.pointersize, rlim[0], signed=True) + ql.mem.write_ptr(old_limit + 1 * ql.arch.pointersize, rlim[1], signed=True) + return 0 except: return -1 diff --git a/qiling/os/posix/syscall/sendfile.py b/qiling/os/posix/syscall/sendfile.py index 6d4b81ca7..fa8656e1c 100644 --- a/qiling/os/posix/syscall/sendfile.py +++ b/qiling/os/posix/syscall/sendfile.py @@ -3,8 +3,14 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from qiling import Qiling -from qiling.os.posix.const import NR_OPEN +from __future__ import annotations + +from typing import TYPE_CHECKING, IO, Optional +from qiling.os.posix.const import EBADF, NR_OPEN + + +if TYPE_CHECKING: + from qiling import Qiling def ql_syscall_sendfile64(ql: Qiling, out_fd: int, in_fd: int, offset: int, count: int): @@ -16,23 +22,29 @@ def ql_syscall_sendfile(ql: Qiling, out_fd: int, in_fd: int, offset: int, count: # https://man7.org/linux/man-pages/man2/sendfile.2.html if in_fd not in range(NR_OPEN) or out_fd not in range(NR_OPEN): - return -1 + return -EBADF - ifile = ql.os.fd[in_fd] - ofile = ql.os.fd[out_fd] + ifile: Optional[IO] = ql.os.fd[in_fd] + ofile: Optional[IO] = ql.os.fd[out_fd] if ifile is None or ofile is None: - return -1 + return -EBADF - ifile_pos = ifile.tell() - offset = ql.mem.read_ptr(offset) if offset else ifile_pos + if offset: + ifile_pos = ifile.tell() + + # read offset from memory and seek it + goto = ql.mem.read_ptr(offset) + ifile.seek(goto) - ifile.lseek(offset) buf = ifile.read(count) if offset: - current_offset = ifile.tell() - ql.mem.write_ptr(offset, current_offset) - ifile.lseek(ifile_pos) + # write updated offset to memory + where = ifile.tell() + ql.mem.write_ptr(offset, where) + + # retain old location + ifile.seek(ifile_pos) return ofile.write(buf) diff --git a/qiling/os/posix/syscall/shm.py b/qiling/os/posix/syscall/shm.py index 4ea880607..5578feeae 100644 --- a/qiling/os/posix/syscall/shm.py +++ b/qiling/os/posix/syscall/shm.py @@ -21,7 +21,7 @@ def __create_shm(key: int, size: int, flags: int) -> int: """ if len(ql.os.shm) >= SHMMNI: - return -1 # ENOSPC + return -ENOSPC mode = flags & ((1 << 9) - 1) @@ -54,13 +54,13 @@ def __create_shm(key: int, size: int, flags: int) -> int: shmid = __create_shm(key, size, shmflg) else: - return -1 # ENOENT + return -ENOENT # a shm with the specified key exists else: # the user asked to create a new one? if shmflg & (IPC_CREAT | IPC_EXCL): - return -1 # EEXIST + return -EEXIST # check whether the user has permissions to access this shm # FIXME: should probably use ql.os.cuid instead, but we don't support it yet @@ -68,7 +68,7 @@ def __create_shm(key: int, size: int, flags: int) -> int: return shmid else: - return -1 # EACCES + return -EACCES return shmid @@ -78,7 +78,7 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): # a shm with the specified key does not exist if shm is None: - return -1 # EINVAL + return -EINVAL if shmaddr == 0: # system may choose any suitable page-aligned address @@ -100,7 +100,7 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): else: # shmaddr is expected to be aligned if shmaddr & (ql.mem.pagesize - 1): - return -1 # EINVAL + return -EINVAL attaddr = shmaddr @@ -114,11 +114,11 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): # user asked to attached the seg as readable; is it allowed? if (perms & UC_PROT_READ) and not (shm.mode & SHM_R): - return -1 # EACCES + return -EACCES # user asked to attached the seg as writable; is it allowed? if (perms & UC_PROT_WRITE) and not (shm.mode & SHM_W): - return -1 # EACCES + return -EACCES # TODO: if segment is already attached, there is no need to map another memory for it. # if we do, data changes will not be reflected between the segment attachments. we could @@ -129,7 +129,7 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): # attach the segment at shmaddr ql.mem.map(attaddr, shm.segsz, perms, '[shm]') except QlMemoryMappedError: - return -1 # EINVAL + return -EINVAL # track attachment shm.attach.append(attaddr) @@ -143,7 +143,7 @@ def ql_syscall_shmdt(ql: Qiling, shmaddr: int): shm = ql.os.shm.get_by_attaddr(shmaddr) if shm is None: - return -1 # EINVAL + return -EINVAL shm.attach.remove(shmaddr) diff --git a/qiling/os/posix/syscall/socket.py b/qiling/os/posix/syscall/socket.py index c0774b590..ea6ee93ba 100644 --- a/qiling/os/posix/syscall/socket.py +++ b/qiling/os/posix/syscall/socket.py @@ -3,21 +3,27 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from __future__ import annotations + import ipaddress import socket -from typing import Optional, Tuple +from typing import TYPE_CHECKING, Tuple, Union -from qiling import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.os.posix.const_mapping import socket_type_mapping, socket_level_mapping, socket_domain_mapping, socket_ip_option_mapping, socket_tcp_option_mapping, socket_option_mapping -from qiling.os.posix.const import * +from qiling.os.posix.const import NR_OPEN, EMFILE, EBADF, EAFNOSUPPORT, EINVAL, ENOTSOCK from qiling.os.posix.filestruct import ql_socket from qiling.os.posix.structs import * +if TYPE_CHECKING: + from qiling import Qiling + from qiling.os.posix.posix import QlOsPosix + + AF_UNIX = 1 AF_INET = 2 -AF_INET6 = 10 +AF_INET6 = 10 # TODO: this is not true for macos SOCK_STREAM = 1 SOCK_DGRAM = 2 @@ -97,7 +103,7 @@ def __host_socket_type(vsock_type: int, arch_type: QL_ARCH) -> int: try: vsock_type_name = socket_type_mapping(vsock_type, arch_type) - except KeyError: + except ValueError: raise NotImplementedError(f'Could not convert emulated socket type {vsock_type} to a socket type name') try: @@ -114,7 +120,7 @@ def __host_socket_level(vsock_level: int, arch_type: QL_ARCH) -> int: try: vsock_level_name = socket_level_mapping(vsock_level, arch_type) - except KeyError: + except ValueError: raise NotImplementedError(f'Could not convert emulated socket level {vsock_level} to a socket level name') try: @@ -144,7 +150,7 @@ def __host_socket_option(vsock_level: int, vsock_opt: int, arch_type: QL_ARCH, o if vsock_opt_name.endswith(('_NEW', '_OLD')): vsock_opt_name = vsock_opt_name[:-4] - except KeyError: + except ValueError: raise NotImplementedError(f'Could not convert emulated socket option {vsock_opt} to a socket option name') try: @@ -155,6 +161,28 @@ def __host_socket_option(vsock_level: int, vsock_opt: int, arch_type: QL_ARCH, o return hsock_opt +def get_opened_socket(os: QlOsPosix, fd: int) -> Union[ql_socket, int]: + """Retrieve opened socket by its fd index. In case of a error, the + appropriate error number is returned. + """ + + # fd out of range? + if fd not in range(NR_OPEN): + return -EBADF + + sock = os.fd[fd] + + # not an opened file? + if sock is None: + return -EBADF + + # not a socket? + if not isinstance(sock, ql_socket): + return -ENOTSOCK + + return sock + + def ql_syscall_socket(ql: Qiling, domain: int, socktype: int, protocol: int): idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) @@ -192,7 +220,7 @@ def ql_syscall_socketpair(ql: Qiling, domain: int, socktype: int, protocol: int, idx1 = next(unpopulated_fd, -1) idx2 = next(unpopulated_fd, -1) - regreturn = -1 + regreturn = -EMFILE if (idx1 != -1) and (idx2 != -1): # ql_socket.socketpair should use host platform based socket type @@ -227,13 +255,10 @@ def ql_syscall_socketpair(ql: Qiling, domain: int, socktype: int, protocol: int, def ql_syscall_connect(ql: Qiling, sockfd: int, addr: int, addrlen: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock data = ql.mem.read(addr, addrlen) @@ -243,9 +268,6 @@ def ql_syscall_connect(ql: Qiling, sockfd: int, addr: int, addrlen: int): sockaddr = make_sockaddr(abits, endian) sockaddr_obj = sockaddr.from_buffer(data) - dest = None - regreturn = -1 - if sock.family != sockaddr_obj.sa_family: return -1 @@ -276,25 +298,22 @@ def ql_syscall_connect(ql: Qiling, sockfd: int, addr: int, addrlen: int): ql.log.debug(f'Connecting to {host}:{port}') dest = (host, port) - if dest is not None: - try: - sock.connect(dest) - except (ConnectionError, FileNotFoundError): - regreturn = -1 - else: - regreturn = 0 + else: + return -EAFNOSUPPORT - return regreturn + try: + sock.connect(dest) + except (ConnectionError, FileNotFoundError) as ex: + return -ex.errno + + return 0 def ql_syscall_getsockopt(ql: Qiling, sockfd: int, level: int, optname: int, optval_addr: int, optlen_addr: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock vsock_level = level hsock_level = __host_socket_level(vsock_level, ql.arch.type) @@ -306,15 +325,15 @@ def ql_syscall_getsockopt(ql: Qiling, sockfd: int, level: int, optname: int, opt ql.log.debug(f'Converted emulated socket option {vsock_opt} to host socket option {hsock_opt}') - optlen = min(ql.unpack32s(ql.mem.read(optlen_addr, 4)), 1024) + optlen = min(ql.mem.read_ptr(optlen_addr, 4, signed=True), 1024) if optlen < 0: - return -1 + return -EINVAL try: optval = sock.getsockopt(hsock_level, hsock_opt, optlen) - except (ConnectionError, OSError): - return -1 + except (ConnectionError, OSError) as ex: + return -ex.errno ql.mem.write(optval_addr, optval) @@ -322,13 +341,10 @@ def ql_syscall_getsockopt(ql: Qiling, sockfd: int, level: int, optname: int, opt def ql_syscall_setsockopt(ql: Qiling, sockfd: int, level: int, optname: int, optval_addr: int, optlen: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock if optval_addr == 0: sock.setsockopt(level, optname, None, optlen) @@ -348,20 +364,17 @@ def ql_syscall_setsockopt(ql: Qiling, sockfd: int, level: int, optname: int, opt try: sock.setsockopt(hsock_level, hsock_opt, optval) - except (ConnectionError, OSError): - return -1 + except (ConnectionError, OSError) as ex: + return -ex.errno return 0 def ql_syscall_shutdown(ql: Qiling, sockfd: int, how: int): - if sockfd not in range(NR_OPEN): - return -1 - - sock: Optional[ql_socket] = ql.os.fd[sockfd] + sock = get_opened_socket(ql.os, sockfd) - if sock is None: - return -1 + if isinstance(sock, int): + return sock try: sock.shutdown(how) @@ -372,13 +385,10 @@ def ql_syscall_shutdown(ql: Qiling, sockfd: int, how: int): def ql_syscall_bind(ql: Qiling, sockfd: int, addr: int, addrlen: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock data = ql.mem.read(addr, addrlen) @@ -390,9 +400,6 @@ def ql_syscall_bind(ql: Qiling, sockfd: int, addr: int, addrlen: int): sa_family = sockaddr_obj.sa_family - dest = None - regreturn = -1 - if sa_family == AF_UNIX: hpath, vpath = ql_unix_socket_path(ql, data[2:]) @@ -431,25 +438,22 @@ def ql_syscall_bind(ql: Qiling, sockfd: int, addr: int, addrlen: int): ql.log.debug(f'Binding socket to {host}:{port}') dest = (host, port) - if dest is not None: - try: - sock.bind(dest) - except (ConnectionError, FileNotFoundError): - regreturn = -1 - else: - regreturn = 0 + else: + return -EAFNOSUPPORT - return regreturn + try: + sock.bind(dest) + except (OSError, ConnectionError, FileNotFoundError) as ex: + return -ex.errno + + return 0 def ql_syscall_getsockname(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock addrlen = ql.mem.read_ptr(addrlenptr) if addrlenptr else 0 @@ -508,13 +512,10 @@ def ql_syscall_getsockname(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): def ql_syscall_getpeername(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): - if sockfd not in range(NR_OPEN): - return -1 - - sock: Optional[ql_socket] = ql.os.fd[sockfd] + sock = get_opened_socket(ql.os, sockfd) - if sock is None: - return -1 + if isinstance(sock, int): + return sock addrlen = ql.mem.read_ptr(addrlenptr) if addrlenptr else 0 @@ -573,30 +574,24 @@ def ql_syscall_getpeername(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): def ql_syscall_listen(ql: Qiling, sockfd: int, backlog: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock try: sock.listen(backlog) - except ConnectionError: - return -1 + except ConnectionError as ex: + return -ex.errno return 0 def ql_syscall_accept(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock try: conn, address = sock.accept() @@ -609,7 +604,7 @@ def ql_syscall_accept(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) if idx == -1: - return -1 + return -EMFILE ql.os.fd[idx] = conn @@ -668,13 +663,10 @@ def ql_syscall_accept(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): def ql_syscall_recv(ql: Qiling, sockfd: int, buf: int, length: int, flags: int): - if sockfd not in range(NR_OPEN): - return -1 - - sock: Optional[ql_socket] = ql.os.fd[sockfd] + sock = get_opened_socket(ql.os, sockfd) - if sock is None: - return -1 + if isinstance(sock, int): + return sock content = sock.recv(length, flags) @@ -688,13 +680,10 @@ def ql_syscall_recv(ql: Qiling, sockfd: int, buf: int, length: int, flags: int): def ql_syscall_send(ql: Qiling, sockfd: int, buf: int, length: int, flags: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock content = ql.mem.read(buf, length) @@ -707,13 +696,10 @@ def ql_syscall_send(ql: Qiling, sockfd: int, buf: int, length: int, flags: int): def ql_syscall_recvmsg(ql: Qiling, sockfd: int, msg_addr: int, flags: int): - if sockfd not in range(NR_OPEN): - return -1 - - sock: Optional[ql_socket] = ql.os.fd[sockfd] + sock = get_opened_socket(ql.os, sockfd) - if sock is None: - return -1 + if isinstance(sock, int): + return sock abits = ql.arch.bits endian = ql.arch.endian @@ -760,13 +746,10 @@ def ql_syscall_recvmsg(ql: Qiling, sockfd: int, msg_addr: int, flags: int): def ql_syscall_recvfrom(ql: Qiling, sockfd: int, buf: int, length: int, flags: int, addr: int, addrlen: int): - if sockfd not in range(NR_OPEN): - return -1 - - sock: Optional[ql_socket] = ql.os.fd[sockfd] + sock = get_opened_socket(ql.os, sockfd) - if sock is None: - return -1 + if isinstance(sock, int): + return sock # For x8664, recvfrom() is called finally when calling recv() in TCP communications # calling recvfrom with a NULL addr argument is identical to calling recv, which is normally used only on a connected socket @@ -836,13 +819,10 @@ def ql_syscall_recvfrom(ql: Qiling, sockfd: int, buf: int, length: int, flags: i def ql_syscall_sendto(ql: Qiling, sockfd: int, buf: int, length: int, flags: int, addr: int, addrlen: int): - if sockfd not in range(NR_OPEN): - return -1 + sock = get_opened_socket(ql.os, sockfd) - sock: Optional[ql_socket] = ql.os.fd[sockfd] - - if sock is None: - return -1 + if isinstance(sock, int): + return sock # if sendto is used on a connection-mode socket, the arguments addr and addrlen are ignored. # also, calling sendto(sockfd, buf, length, flags, NULL, 0) is equivalent to send(sockfd, buf, length, flags) diff --git a/qiling/os/posix/syscall/stat.py b/qiling/os/posix/syscall/stat.py index d4e1be375..5b153100a 100644 --- a/qiling/os/posix/syscall/stat.py +++ b/qiling/os/posix/syscall/stat.py @@ -10,7 +10,7 @@ from qiling import Qiling from qiling.const import QL_OS, QL_ARCH, QL_ENDIAN -from qiling.os.posix.const import NR_OPEN, EBADF, ENOENT, AT_FDCWD, AT_EMPTY_PATH +from qiling.os.posix.const import EIO, NR_OPEN, EBADF, AT_FDCWD, AT_EMPTY_PATH from qiling.os.posix.stat import Stat, Lstat # Caveat: Never use types like ctypes.c_long whose size differs across platforms. @@ -1138,7 +1138,7 @@ def get_stat_struct(ql: Qiling): return LinuxARM64EBStat() elif ql.arch.type in (QL_ARCH.RISCV, QL_ARCH.RISCV64): return LinuxRISCVStat() - elif ql.archtype == QL_ARCH.PPC: + elif ql.arch.type == QL_ARCH.PPC: return LinuxPPCStat() elif ql.os.type == QL_OS.QNX: if ql.arch.type == QL_ARCH.ARM64: @@ -1233,97 +1233,95 @@ def ql_syscall_chmod(ql: Qiling, filename: int, mode: int): try: os.chmod(hpath, mode) - except OSError: - regreturn = -1 + except OSError as ex: + ret = -ex.errno else: - regreturn = 0 + ret = 0 - ql.log.debug(f'chmod("{vpath}", 0{mode:o}) = {regreturn}') + ql.log.debug(f'chmod("{vpath}", 0{mode:o}) = {ret}') - return regreturn + return ret def ql_syscall_fchmod(ql: Qiling, fd: int, mode: int): if fd not in range(NR_OPEN): - return -1 + return -EBADF f = ql.os.fd[fd] if f is None: - return -1 + return -EBADF try: os.fchmod(f.fileno(), mode) - except OSError: - regreturn = -1 + except OSError as ex: + ret = -ex.errno else: - regreturn = 0 + ret = 0 - ql.log.debug(f'fchmod({fd}, 0{mode:o}) = {regreturn}') + ql.log.debug(f'fchmod({fd}, 0{mode:o}) = {ret}') - return regreturn + return ret def ql_syscall_fstatat64(ql: Qiling, dirfd: int, path: int, buf_ptr: int, flags: int): dirfd, real_path = transform_path(ql, dirfd, path, flags) try: - buf = pack_stat64_struct(ql, Stat(real_path, dirfd)) + stat = Stat(real_path, dirfd) + except OSError as ex: + ret = -ex.errno + else: + buf = pack_stat64_struct(ql, stat) ql.mem.write(buf_ptr, buf) - regreturn = 0 - except: - regreturn = -1 + ret = 0 - return regreturn + return ret -def ql_syscall_newfstatat(ql: Qiling, dirfd: int, path: int, buf_ptr: int, flags: int): +def ql_syscall_newfstatat(ql: Qiling, dirfd: int, path: int, buf: int, flags: int): dirfd, real_path = transform_path(ql, dirfd, path, flags) try: - buf = pack_stat_struct(ql, Stat(real_path, dirfd)) - ql.mem.write(buf_ptr, buf) + stat = Stat(real_path, dirfd) + except OSError as ex: + ret = -ex.errno + else: + data = pack_stat_struct(ql, stat) + ql.mem.write(buf, data) - regreturn = 0 - except: - regreturn = -1 + ret = 0 + + return ret - return regreturn -def ql_syscall_fstat64(ql: Qiling, fd: int, buf_ptr: int): +def __do_fstat(ql: Qiling, fd: int, buf: int, method: Callable) -> int: if fd not in range(NR_OPEN): - return -1 + return -EBADF f = ql.os.fd[fd] if f is None or not hasattr(f, "fstat"): - return -1 + return -EBADF - fstat = f.fstat() + try: + fstat = f.fstat() + except OSError: + return -EIO if fstat != -1: - buf = pack_stat64_struct(ql, fstat) - ql.mem.write(buf_ptr, buf) + data = method(ql, fstat) + ql.mem.write(buf, data) return 0 -def ql_syscall_fstat(ql: Qiling, fd: int, buf_ptr: int): - if fd not in range(NR_OPEN): - return -1 +def ql_syscall_fstat64(ql: Qiling, fd: int, buf: int): + return __do_fstat(ql, fd, buf, pack_stat64_struct) - f = ql.os.fd[fd] - if f is None or not hasattr(f, "fstat"): - return -1 - - fstat = f.fstat() - - if fstat != -1: - buf = pack_stat_struct(ql, fstat) - ql.mem.write(buf_ptr, buf) - - return 0 +def ql_syscall_fstat(ql: Qiling, fd: int, buf: int): + return __do_fstat(ql, fd, buf, pack_stat_struct) # int stat(const char *path, struct stat *buf); @@ -1485,12 +1483,14 @@ def ql_syscall_mknodat(ql: Qiling, dirfd: int, path: int, mode: int, dev: int): try: os.mknod(real_path, mode, dev, dir_fd=dirfd) - regreturn = 0 - except: - regreturn = -1 + except OSError as ex: + ret = -ex.errno + else: + ret = 0 - ql.log.debug("mknodat(%d, %s, 0%o, %d) = %d" % (dirfd, real_path, mode, dev, regreturn)) - return regreturn + ql.log.debug(f'mknodat({dirfd}, "{real_path}", 0{mode:o}, {dev}) = {ret}') + + return ret def ql_syscall_mkdir(ql: Qiling, pathname: int, mode: int): @@ -1501,16 +1501,15 @@ def ql_syscall_mkdir(ql: Qiling, pathname: int, mode: int): raise PermissionError(f'unsafe path: {hpath}') try: - if not os.path.exists(hpath): - os.mkdir(hpath, mode) - except OSError: - regreturn = -1 + os.mkdir(hpath, mode) + except OSError as ex: + ret = -ex.errno else: - regreturn = 0 + ret = 0 - ql.log.debug(f'mkdir("{vpath}", 0{mode:o}) = {regreturn}') + ql.log.debug(f'mkdir("{vpath}", 0{mode:o}) = {ret}') - return regreturn + return ret def ql_syscall_rmdir(ql: Qiling, pathname: int): @@ -1521,16 +1520,15 @@ def ql_syscall_rmdir(ql: Qiling, pathname: int): raise PermissionError(f'unsafe path: {hpath}') try: - if os.path.exists(hpath): - os.rmdir(hpath) - except OSError: - regreturn = -1 + os.rmdir(hpath) + except OSError as ex: + ret = -ex.errno else: - regreturn = 0 + ret = 0 - ql.log.debug(f'rmdir("{vpath}") = {regreturn}') + ql.log.debug(f'rmdir("{vpath}") = {ret}') - return regreturn + return ret def ql_syscall_fstatfs(ql: Qiling, fd: int, buf: int): @@ -1542,10 +1540,6 @@ def ql_syscall_fstatfs(ql: Qiling, fd: int, buf: int): except: regreturn = -1 - if data: - ql.log.debug("fstatfs() CONTENT:") - ql.log.debug(str(data)) - return regreturn def ql_syscall_statfs(ql: Qiling, path: int, buf: int): @@ -1562,4 +1556,6 @@ def ql_syscall_statfs(ql: Qiling, path: int, buf: int): def ql_syscall_umask(ql: Qiling, mode: int): oldmask = os.umask(mode) + ql.log.debug(f'umask(0{mode:o}) = 0{oldmask:o}') + return oldmask diff --git a/qiling/os/posix/syscall/syscall.py b/qiling/os/posix/syscall/syscall.py index 2a3c10922..d269df3bd 100644 --- a/qiling/os/posix/syscall/syscall.py +++ b/qiling/os/posix/syscall/syscall.py @@ -19,7 +19,7 @@ def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, p def __call_shmat(*args: int) -> int: if version == 1: - return -1 # EINVAL + return -EINVAL return ql_syscall_shmat(ql, args[0], args[3], args[1]) @@ -28,17 +28,17 @@ def __call_shmdt(*args: int) -> int: def __call_shmget(*args: int) -> int: return ql_syscall_shmget(ql, args[0], args[1], args[2]) - + def __call_msgget(*args: int) -> int: return ql_syscall_msgget(ql, args[0], args[1]) def __call_msgsnd(*args: int) -> int: return ql_syscall_msgsnd(ql, args[0], args[3], args[1], args[2]) - + def __call_msgrcv(*args: int) -> int: if version == 0: if args[3] == 0: - return -1 # EINVAL + return -EINVAL msgp = ql.mem.read_ptr(args[3]) msgtyp = ql.mem.read_ptr(args[3] + ql.arch.pointersize) @@ -59,7 +59,7 @@ def __call_msgrcv(*args: int) -> int: } if call not in ipc_call: - return -1 # ENOSYS + return -ENOSYS return ipc_call[call](first, second, third, ptr, fifth) diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index 3c9b91472..62eab143c 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -9,7 +9,7 @@ import itertools import pathlib -from typing import TYPE_CHECKING, Iterator, Optional +from typing import TYPE_CHECKING, IO, Iterator, Optional, Union from qiling import Qiling from qiling.const import QL_ARCH, QL_OS @@ -155,16 +155,17 @@ def ql_syscall_kill(ql: Qiling, pid: int, sig: int): return 0 -def get_opened_fd(os: QlOsPosix, fd: int): +def get_opened_fd(os: QlOsPosix, fd: int) -> Optional[IO]: + """Retrieve a file instance by its file descriptor id. + """ + if fd not in range(NR_OPEN): - # TODO: set errno to EBADF - return None + return None # EBADF f = os.fd[fd] if f is None: - # TODO: set errno to EBADF - return None + return None # EBADF return f @@ -173,7 +174,7 @@ def ql_syscall_fsync(ql: Qiling, fd: int): f = get_opened_fd(ql.os, fd) if f is None: - regreturn = -1 + regreturn = -EBADF else: try: @@ -201,7 +202,16 @@ def ql_syscall_fdatasync(ql: Qiling, fd: int): return regreturn -def virtual_abspath_at(ql: Qiling, vpath: str, dirfd: int) -> Optional[str]: +def virtual_abspath_at(ql: Qiling, vpath: str, dirfd: int) -> Union[int, str]: + """Resolve the virtual absolute path based on the specified dirfd. + + Args: + vpath: relative virtual path to resolve + dirfd: base directory file descriptor + + Returns: the resolved absolute path, or an error code if could not resolve it + """ + if ql.os.path.is_virtual_abspath(vpath): return vpath @@ -223,14 +233,12 @@ def __as_signed(value: int, nbits: int) -> int: f = get_opened_fd(ql.os, dirfd) if f is None or not hasattr(f, 'name'): - # EBADF - return None + return -EBADF hpath = f.name if not os.path.isdir(hpath): - # ENOTDIR - return None + return -ENOTDIR basedir = ql.os.path.host_to_virtual_path(hpath) @@ -241,8 +249,8 @@ def ql_syscall_faccessat(ql: Qiling, dirfd: int, filename: int, mode: int): vpath = ql.os.utils.read_cstring(filename) vpath_at = virtual_abspath_at(ql, vpath, dirfd) - if vpath_at is None: - regreturn = -1 + if isinstance(vpath_at, int): + regreturn = vpath_at else: hpath = ql.os.path.virtual_to_host_path(vpath_at) @@ -250,7 +258,7 @@ def ql_syscall_faccessat(ql: Qiling, dirfd: int, filename: int, mode: int): if not ql.os.path.is_safe_host_path(hpath): raise PermissionError(f'unsafe path: {hpath}') - regreturn = 0 if os.path.exists(hpath) else -1 + regreturn = 0 if os.path.exists(hpath) else -ENOENT ql.log.debug(f'faccessat({dirfd:d}, "{vpath}", {mode:d}) = {regreturn}') @@ -258,12 +266,12 @@ def ql_syscall_faccessat(ql: Qiling, dirfd: int, filename: int, mode: int): def ql_syscall_lseek(ql: Qiling, fd: int, offset: int, origin: int): - offset = ql.unpacks(ql.pack(offset)) + offset = ql.os.utils.as_signed(offset, 32) f = get_opened_fd(ql.os, fd) if f is None: - regreturn = -1 + regreturn = -EBADF else: try: @@ -277,13 +285,12 @@ def ql_syscall_lseek(ql: Qiling, fd: int, offset: int, origin: int): def ql_syscall__llseek(ql: Qiling, fd: int, offset_high: int, offset_low: int, result: int, whence: int): - # treat offset as a signed value - offset = ql.unpack64s(ql.pack64((offset_high << 32) | offset_low)) + offset = ql.os.utils.as_signed((offset_high << 32) | offset_low, 64) f = get_opened_fd(ql.os, fd) if f is None: - regreturn = -1 + regreturn = -EBADF else: try: @@ -324,7 +331,7 @@ def ql_syscall_access(ql: Qiling, path: int, mode: int): if not ql.os.path.is_safe_host_path(hpath): raise PermissionError(f'unsafe path: {hpath}') - regreturn = 0 if os.path.exists(hpath) else -1 + regreturn = 0 if os.path.exists(hpath) else -ENOENT ql.log.debug(f'access("{vpath}", 0{mode:o}) = {regreturn}') @@ -335,7 +342,7 @@ def ql_syscall_close(ql: Qiling, fd: int): f = get_opened_fd(ql.os, fd) if f is None: - regreturn = -1 + regreturn = -EBADF else: f.close() @@ -351,70 +358,81 @@ def ql_syscall_pread64(ql: Qiling, fd: int, buf: int, length: int, offt: int): f = get_opened_fd(ql.os, fd) if f is None: - regreturn = -1 + return -EBADF - else: - # https://chromium.googlesource.com/linux-syscall-support/+/2c73abf02fd8af961e38024882b9ce0df6b4d19b - # https://chromiumcodereview.appspot.com/10910222 - if ql.arch.type == QL_ARCH.MIPS: - offt = ql.mem.read_ptr(ql.arch.regs.arch_sp + 0x10, 8) + if not ql.mem.is_mapped(buf, length): + return -EFAULT - try: - pos = f.tell() - f.seek(offt) + # https://chromium.googlesource.com/linux-syscall-support/+/2c73abf02fd8af961e38024882b9ce0df6b4d19b + # https://chromiumcodereview.appspot.com/10910222 + if ql.arch.type is QL_ARCH.MIPS: + offt = ql.mem.read_ptr(ql.arch.regs.arch_sp + 0x10, 8) - data = f.read(length) - f.seek(pos) - except OSError: - regreturn = -1 - else: - ql.mem.write(buf, data) + try: + pos = f.tell() + f.seek(offt) + + data = f.read(length) + f.seek(pos) + except OSError: + regreturn = -1 + else: + ql.mem.write(buf, data) - regreturn = len(data) + regreturn = len(data) return regreturn -def ql_syscall_read(ql: Qiling, fd, buf: int, length: int): +def ql_syscall_read(ql: Qiling, fd: int, buf: int, length: int): f = get_opened_fd(ql.os, fd) if f is None: - return -1 + return -EBADF + + if not ql.mem.is_mapped(buf, length): + return -EFAULT + + if not hasattr(f, 'read'): + ql.log.debug(f'read failed since fd {fd:d} does not have a read method') + return -EBADF try: data = f.read(length) - ql.mem.write(buf, data) - except: - regreturn = -EBADF - else: - ql.log.debug(f'read() CONTENT: {data!r}') - regreturn = len(data) + except ConnectionError: + ql.log.debug('read failed due to a connection error') + return -EIO - return regreturn + ql.mem.write(buf, data) + ql.log.debug(f'read() CONTENT: {bytes(data)}') + + return len(data) def ql_syscall_write(ql: Qiling, fd: int, buf: int, count: int): f = get_opened_fd(ql.os, fd) if f is None: - return -1 + return -EBADF - try: - data = ql.mem.read(buf, count) - except: - regreturn = -1 - else: - ql.log.debug(f'write() CONTENT: {bytes(data)}') + if not ql.mem.is_mapped(buf, count): + return -EFAULT - if hasattr(f, 'write'): - f.write(data) + if not hasattr(f, 'write'): + ql.log.debug(f'write failed since fd {fd:d} does not have a write method') + return -EBADF - regreturn = count - else: - ql.log.warning(f'write failed since fd {fd:d} does not have a write method') - regreturn = -1 + data = ql.mem.read(buf, count) - return regreturn + try: + f.write(data) + except ConnectionError: + ql.log.debug('write failed due to a connection error') + return -EIO + + ql.log.debug(f'write() CONTENT: {bytes(data)}') + + return count def __do_readlink(ql: Qiling, absvpath: str, outbuf: int) -> int: @@ -442,7 +460,7 @@ def __do_readlink(ql: Qiling, absvpath: str, outbuf: int) -> int: target = '' if target is None: - return -1 + return -ENOENT cstr = target.encode('utf-8') @@ -467,7 +485,7 @@ def ql_syscall_readlinkat(ql: Qiling, dirfd: int, pathname: int, buf: int, bufsi vpath = ql.os.utils.read_cstring(pathname) absvpath = virtual_abspath_at(ql, vpath, dirfd) - regreturn = -1 if absvpath is None else __do_readlink(ql, absvpath, buf) + regreturn = absvpath if isinstance(absvpath, int) else __do_readlink(ql, absvpath, buf) ql.log.debug(f'readlinkat({dirfd:d}, "{vpath}", {buf:#x}, {bufsize:#x}) = {regreturn}') @@ -500,7 +518,7 @@ def ql_syscall_chdir(ql: Qiling, path_name: int): regreturn = 0 else: - regreturn = -1 + regreturn = -ENOENT ql.log.debug(f'chdir("{absvpath}") = {regreturn}') @@ -627,7 +645,7 @@ def ql_syscall_dup(ql: Qiling, oldfd: int): f = get_opened_fd(ql.os, oldfd) if f is None: - return -1 + return -EBADF newfd = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) @@ -645,10 +663,10 @@ def ql_syscall_dup2(ql: Qiling, oldfd: int, newfd: int): f = get_opened_fd(ql.os, oldfd) if f is None: - return -1 + return -EBADF if newfd not in range(NR_OPEN): - return -1 + return -EBADF newslot = ql.os.fd[newfd] @@ -665,13 +683,16 @@ def ql_syscall_dup2(ql: Qiling, oldfd: int, newfd: int): def ql_syscall_dup3(ql: Qiling, oldfd: int, newfd: int, flags: int): O_CLOEXEC = 0o2000000 + if oldfd == newfd: + return -EINVAL + f = get_opened_fd(ql.os, oldfd) if f is None: - return -1 + return -EBADF if newfd not in range(NR_OPEN): - return -1 + return -EBADF newslot = ql.os.fd[newfd] @@ -707,7 +728,7 @@ def ql_syscall_pipe(ql: Qiling, pipefd: int): idx2 = next(unpopulated_fd, -1) if (idx1 == -1) or (idx2 == -1): - return -1 + return -EMFILE ql.os.fd[idx1] = rd ql.os.fd[idx2] = wd @@ -762,7 +783,7 @@ def ql_syscall_truncate(ql: Qiling, path: int, length: int): def ql_syscall_ftruncate(ql: Qiling, fd: int, length: int): f = get_opened_fd(ql.os, fd) - regreturn = -1 if f is None else __do_truncate(ql, f.name, length) + regreturn = -EBADF if f is None else __do_truncate(ql, f.name, length) ql.log.debug(f'ftruncate({fd}, {length:#x}) = {regreturn}') @@ -821,7 +842,7 @@ def ql_syscall_unlinkat(ql: Qiling, dirfd: int, pathname: int, flags: int): vpath = ql.os.utils.read_cstring(pathname) absvpath = virtual_abspath_at(ql, vpath, dirfd) - regreturn = -1 if absvpath is None else __do_unlink(ql, absvpath) + regreturn = absvpath if isinstance(absvpath, int) else __do_unlink(ql, absvpath) ql.log.debug(f'unlinkat({dirfd}, "{vpath}") = {regreturn}') diff --git a/qiling/os/posix/syscall/wait.py b/qiling/os/posix/syscall/wait.py index 51102f877..a936e3b54 100644 --- a/qiling/os/posix/syscall/wait.py +++ b/qiling/os/posix/syscall/wait.py @@ -9,19 +9,15 @@ from qiling.os.posix.const import ECHILD def ql_syscall_wait4(ql: Qiling, pid: int, wstatus: int, options: int, rusage: int): - # convert to signed (pid_t is 32bit) - pid = ql.unpack32s(ql.pack32(pid)) - # python expects options to be a signed 32bit int - options = ql.unpack32s(ql.pack32(options)) + pid = ql.os.utils.as_signed(pid, 32) + options = ql.os.utils.as_signed(options, 32) try: spid, status, _ = os.wait4(pid, options) - - if wstatus: - ql.mem.write_ptr(wstatus, status, 4) - - retval = spid except ChildProcessError: - retval = -ECHILD + return -ECHILD + + if wstatus: + ql.mem.write_ptr(wstatus, status, 4) - return retval + return spid diff --git a/qiling/os/qnx/message.py b/qiling/os/qnx/message.py index 3c82f5390..2f189347b 100644 --- a/qiling/os/qnx/message.py +++ b/qiling/os/qnx/message.py @@ -10,7 +10,8 @@ from qiling.os.qnx.const import IO_FLAG_MASK, PAGESIZE, S_IFMT from qiling.os.qnx.helpers import get_message_body from qiling.os.qnx.types import file_access, file_stats, file_types, file_open_flags, file_sharing_modes, io_connect_eflag, io_connect_ioflag, io_connect_subtypes, lseek_whence, mem_ctrl_subtypes, mmap_flags, pathconf_names, sysconf_conditions, sysconf_consts, sysconf_names, sysconf_subtypes -from qiling.os.posix.const_mapping import _flags_mapping, mmap_prot_mapping +from qiling.os.posix.const import qnx_mmap_prot_flags +from qiling.os.posix.const_mapping import flags_mapping from qiling.os.posix.syscall import ql_syscall_close, ql_syscall_fstat, ql_syscall_lseek, ql_syscall_mmap, ql_syscall_open, ql_syscall_read, ql_syscall_write # TODO: move this to qiling.os.qnx.const? @@ -56,7 +57,7 @@ def ql_qnx_msg_io_connect(ql: Qiling, coid, smsg, sparts, rmsg, rparts, *args, * ioflag_hi = ioflag & (~IO_FLAG_MASK) real_mode = mode & (~S_IFMT) # ql.log.debug(f'msg_io_connect(subtype = {subtype}, file_type = {file_type}, ioflag = 0x{ioflag:x}, mode = 0x{mode:x}, sflag = 0x{sflag:x}, access = {access}, extra_len = {extra_len})') - ql.log.debug(f'msg_io_connect(subtype = {io_connect_subtypes[subtype]}, file_type = {file_types[file_type]}, ioflag = {_flags_mapping(ioflag_lo, io_connect_ioflag) + _flags_mapping(ioflag_hi, file_open_flags)}, mode = 0x{real_mode:x}, type = {_flags_mapping((mode & S_IFMT), file_stats)}, sflag = {file_sharing_modes[sflag]})') + ql.log.debug(f'msg_io_connect(subtype = {io_connect_subtypes[subtype]}, file_type = {file_types[file_type]}, ioflag = {flags_mapping(ioflag_lo, io_connect_ioflag) + flags_mapping(ioflag_hi, file_open_flags)}, mode = 0x{real_mode:x}, type = {flags_mapping((mode & S_IFMT), file_stats)}, sflag = {file_sharing_modes[sflag]})') # convert _IO_FLAG_? to O_? flag and then to O_? flags of host system ioflag -= 1 #ioflag = ql_open_flag_mapping(ql, ioflag) @@ -216,7 +217,7 @@ def ql_qnx_msg_mem_map(ql: Qiling, coid, smsg, sparts, rmsg, rparts, *args, **kw if fd > 0: fd = ql.os.connections[fd].fd - ql.log.debug(f'mem_map(addr = 0x{addr:x}, len = 0x{len:x}, prot = {mmap_prot_mapping(prot)}, flags = {_flags_mapping(flags, mmap_flags)}, fd = {fd}, preload = 0x{preload:x}, align = 0x{align:x}, offset = 0x{offset:x})') + ql.log.debug(f'mem_map(addr = 0x{addr:x}, len = 0x{len:x}, prot = {qnx_mmap_prot_flags(prot)}, flags = {flags_mapping(flags, mmap_flags)}, fd = {fd}, preload = 0x{preload:x}, align = 0x{align:x}, offset = 0x{offset:x})') # map memory ret = ql_syscall_mmap(ql, addr, len, prot, flags, fd, offset) # struct _mem_map_replay in services/system/public/sys/memmsg.h diff --git a/qiling/os/qnx/syscall.py b/qiling/os/qnx/syscall.py index 8d4ace443..645bf2203 100644 --- a/qiling/os/qnx/syscall.py +++ b/qiling/os/qnx/syscall.py @@ -14,7 +14,7 @@ def time_ns(): from qiling import Qiling from qiling.utils import ql_get_module_function -from qiling.os.posix.const_mapping import _flags_mapping +from qiling.os.posix.const_mapping import flags_mapping from qiling.os.qnx.helpers import get_message_body, QnxConn, ux32s from qiling.os.qnx.map_msgtype import map_msgtype from qiling.os.qnx.structs import * @@ -25,7 +25,7 @@ def time_ns(): def ql_syscall_channel_create(ql: Qiling, flags, *args, **kw): # TODO: Can we ignore the flags? - ql.log.debug(f'syscall_channel_create(flags = {_flags_mapping(flags, channel_create_flags)})') + ql.log.debug(f'syscall_channel_create(flags = {flags_mapping(flags, channel_create_flags)})') # return new Channel Id regreturn = ql.os.channel_id ql.os.channel_id += 1 diff --git a/qiling/os/utils.py b/qiling/os/utils.py index a9241ee6f..eaddb64da 100644 --- a/qiling/os/utils.py +++ b/qiling/os/utils.py @@ -23,6 +23,25 @@ class QlOsUtils: def __init__(self, ql: Qiling): self.ql = ql + @staticmethod + def as_signed(value: int, nbits: int) -> int: + """Transform an unsigned integer value into its 2's complement signed value + equivalent. This method has no effect on signed integers. + + Args: + value: an unsigned integer to transform + nbits: value bit size + + Returns: a signed integer + """ + + # truncate value to specified bit size + value &= (1 << nbits) - 1 + + msb = 1 << (nbits - 1) + + return -(value & ~(msb - 1)) | value + def read_string(self, address: int, encoding: str, maxlen: int = 0) -> str: """Read a null-terminated string from memory. @@ -244,4 +263,4 @@ def __update_ellipsis(self, args: Iterable[int]) -> Callable[[MutableMapping], N def __do_update(params: MutableMapping) -> None: params.update((f'{QlOsUtils.ELLIPSIS_PREF}{i}', a) for i, a in enumerate(args)) - return __do_update \ No newline at end of file + return __do_update diff --git a/qiling/os/windows/dlls/kernel32/fileapi.py b/qiling/os/windows/dlls/kernel32/fileapi.py index 81a41d562..c737fc9e8 100644 --- a/qiling/os/windows/dlls/kernel32/fileapi.py +++ b/qiling/os/windows/dlls/kernel32/fileapi.py @@ -696,9 +696,10 @@ def _CreateFileMapping(ql: Qiling, address: int, params): dwMaximumSizeLow = params['dwMaximumSizeLow'] lpName = params['lpName'] + hFile = ql.os.utils.as_signed(hFile, ql.arch.bits) req_size = (dwMaximumSizeHigh << 32) | dwMaximumSizeLow - if hFile == ql.unpack(ql.packs(INVALID_HANDLE_VALUE)): + if hFile == INVALID_HANDLE_VALUE: fmobj = FileMappingMem() else: diff --git a/tests/test_elf_multithread.py b/tests/test_elf_multithread.py index cefc82643..be48773f1 100644 --- a/tests/test_elf_multithread.py +++ b/tests/test_elf_multithread.py @@ -64,8 +64,8 @@ def test_elf_linux_cloexec_x8664(self): os.remove(filename) self.assertGreaterEqual(len(contents), 4) - self.assertIn('Operation not permitted', contents[-2]) - self.assertIn('Operation not permitted', contents[-1]) + self.assertIn('Bad file descriptor', contents[-2]) + self.assertIn('Bad file descriptor', contents[-1]) def test_multithread_elf_linux_x86(self): logged: List[str] = [] diff --git a/tests/test_pe_sys.py b/tests/test_pe_sys.py index 08a5b97d8..ec4fb6f03 100644 --- a/tests/test_pe_sys.py +++ b/tests/test_pe_sys.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -8,6 +8,8 @@ from unicorn import UcError +from qiling.os.stats import QlWinNullStats + sys.path.append("..") from qiling import Qiling from qiling.const import QL_STOP, QL_VERBOSE @@ -181,6 +183,9 @@ def hook_third_stop_address(ql: Qiling, stops: List[bool]): ql = Qiling(["../examples/rootfs/x86_windows/bin/sality.dll"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) + # discard strings and api calls stats to gain a bit of speedup + ql.os.stats = QlWinNullStats() + # emulate some Windows API ql.os.set_api("CreateThread", hook_CreateThread) ql.os.set_api("CreateFileA", hook_CreateFileA) diff --git a/tests/test_tendaac15_httpd.py b/tests/test_tendaac15_httpd.py index fd8632b98..cbc7ac821 100644 --- a/tests/test_tendaac15_httpd.py +++ b/tests/test_tendaac15_httpd.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# Built on top of Unicorn emulator (www.unicorn-engine.org) +# Built on top of Unicorn emulator (www.unicorn-engine.org) # 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip @@ -11,83 +11,99 @@ # 5. rm -rf webroot && mv webroot_ro webroot # # notes: we are using rootfs in this example, so rootfs = squashfs-root -# +# -import http.client, json, os, socket, sys, time, threading, unittest +import http.client +import json +import os +import socket +import sys +import time +import threading +import unittest sys.path.append("..") + from qiling import Qiling from qiling.const import QL_VERBOSE + class ELFTest(unittest.TestCase): - def test_tenda_ac15_arm(self): + def test_tenda_ac15_arm(self): def nvram_listener(): server_address = '../examples/rootfs/arm_tendaac15/var/cfm_socket' - data = "" - - try: - os.unlink(server_address) - except OSError: - if os.path.exists(server_address): - raise - - # Create UDS socket - sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) - sock.bind(server_address) - sock.listen(1) - - while True: - connection, client_address = sock.accept() - try: - while True: - data += str(connection.recv(1024)) - - if "lan.webiplansslen" in data: - connection.send('192.168.170.169'.encode()) - else: - break - data = "" - finally: - connection.close() - - def patcher(ql): - br0_addr = ql.mem.search("br0".encode() + b'\x00') + + try: + os.unlink(server_address) + except OSError: + if os.path.exists(server_address): + raise + + # Create UDS socket + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(server_address) + sock.listen(1) + + data = bytearray() + + while True: + connection, _ = sock.accept() + + try: + while True: + data += connection.recv(1024) + + if b"lan.webiplansslen" in data: + connection.send(b'192.168.170.169') + else: + break + + data.clear() + finally: + connection.close() + + def patcher(ql: Qiling): + br0_addr = ql.mem.search(b'br0\x00') + for addr in br0_addr: ql.mem.write(addr, b'lo\x00') def my_tenda(): ql = Qiling(["../examples/rootfs/arm_tendaac15/bin/httpd"], "../examples/rootfs/arm_tendaac15", verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper("/dev/urandom","/dev/urandom") + ql.add_fs_mapper("/dev/urandom", "/dev/urandom") ql.hook_address(patcher, ql.loader.elf_entry) ql.run() - del ql if __name__ == "__main__": + threads = [ + threading.Thread(target=nvram_listener, daemon=True), + threading.Thread(target=my_tenda, daemon=True) + ] - threadLock = threading.Lock() - threads = [] + for th in threads: + th.start() - nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) - mytenda_therad = threading.Thread(target=my_tenda, daemon=True) - - nvram_listener_therad.start() - mytenda_therad.start() - - threads.append(nvram_listener_therad) - threads.append(mytenda_therad) - time.sleep(5) - conn = http.client.HTTPConnection('localhost', 8080, timeout=10) - headers = {'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded'} - web_data = {'page': 'CCCCAAAA', 'entrys':'sync'} + headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/x-www-form-urlencoded' + } + + web_data = { + 'page': 'CCCCAAAA', + 'entrys': 'sync' + } + json_data = json.dumps(web_data) + conn = http.client.HTTPConnection('localhost', 8080, timeout=10) conn.request('POST', '/goform/addressNat', json_data, headers) response = conn.getresponse() - self.assertIn("Please update your documents to reflect the new location.", response.read().decode()) - + self.assertIn(b"Please update your documents to reflect the new location.", response.read()) + + if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main()