mirror of
https://github.com/qilingframework/qiling.git
synced 2026-10-12 02:21:40 +00:00
Merge pull request #1363 from chinggg/ipc-msg
feat(os): add posix message queue syscalls
This commit is contained in:
@@ -1025,6 +1025,15 @@ SHMMNI = 4096 # max num of segs system wide
|
||||
HUGETLB_FLAG_ENCODE_SHIFT = 26
|
||||
HUGETLB_FLAG_ENCODE_MASK = 0x3f
|
||||
|
||||
# see: https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/linux/msg.h
|
||||
MSG_NOERROR = 0o10000 # no error if message is too big
|
||||
MSG_EXCEPT = 0o20000 # recv any msg except of specified type
|
||||
MSG_COPY = 0o40000 # copy (not remove) all queue messages
|
||||
|
||||
MSGMNI = 32000 # <= IPCMNI, max # of msg queue identifiers
|
||||
MSGMAX = 8192 # <= INT_MAX, max size of message (bytes)
|
||||
MSGMNB = 16384 # <= INT_MAX, default max size of a message queue
|
||||
|
||||
# ipc syscall
|
||||
SEMOP = 1
|
||||
SEMGET = 2
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
from collections import deque
|
||||
from inspect import signature, Parameter
|
||||
from typing import Dict, TextIO, Tuple, Union, Callable, IO, List, Optional
|
||||
|
||||
@@ -26,7 +27,7 @@ from qiling.cc import QlCC, intel, arm, mips, riscv, ppc
|
||||
from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT
|
||||
from qiling.exception import QlErrorSyscallNotFound
|
||||
from qiling.os.os import QlOs
|
||||
from qiling.os.posix.const import NR_OPEN, errors
|
||||
from qiling.os.posix.const import MSGMNB, NR_OPEN, errors
|
||||
from qiling.utils import ql_get_module, ql_get_module_function
|
||||
|
||||
SYSCALL_PREF: str = f'ql_syscall_'
|
||||
@@ -136,6 +137,53 @@ class QlShm:
|
||||
return next((shmobj for shmobj in self.__shm.values() if shmobj.attach.count(shmaddr) > 0), None)
|
||||
|
||||
|
||||
class QlMsgBuf:
|
||||
def __init__(self, mtype: int, mtext: bytes) -> None:
|
||||
self.mtype = mtype
|
||||
self.mtext = mtext
|
||||
|
||||
|
||||
# vaguely reflects a msqid64_ds structure
|
||||
class QlMsqId:
|
||||
def __init__(self, key: int, uid: int, gid: int, mode: int) -> None:
|
||||
# ipc64_perm
|
||||
self.key = key
|
||||
self.uid = uid
|
||||
self.gid = gid
|
||||
self.mode = mode
|
||||
|
||||
self.queue = deque(maxlen=MSGMNB)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.queue)
|
||||
|
||||
|
||||
class QlMsq:
|
||||
def __init__(self) -> None:
|
||||
self.__msq: Dict[int, QlMsqId] = {}
|
||||
self.__id: int = 0x0F000000
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.__msq)
|
||||
|
||||
def add(self, msq: QlMsqId) -> int:
|
||||
msqid = self.__id
|
||||
self.__msq[msqid] = msq
|
||||
|
||||
self.__id += 0x1000
|
||||
|
||||
return msqid
|
||||
|
||||
def remove(self, msqid: int) -> None:
|
||||
del self.__msq[msqid]
|
||||
|
||||
def get_by_key(self, key: int) -> Tuple[int, Optional[QlMsqId]]:
|
||||
return next(((msqid, msqobj) for msqid, msqobj in self.__msq.items() if msqobj.key == key), (-1, None))
|
||||
|
||||
def get_by_id(self, msqid: int) -> Optional[QlMsqId]:
|
||||
return self.__msq.get(msqid, None)
|
||||
|
||||
|
||||
class QlOsPosix(QlOs):
|
||||
|
||||
def __init__(self, ql: Qiling):
|
||||
@@ -203,6 +251,7 @@ class QlOsPosix(QlOs):
|
||||
self.stderr = self._stderr
|
||||
|
||||
self._shm = QlShm()
|
||||
self._msq = QlMsq()
|
||||
|
||||
def __get_syscall_mapper(self, archtype: QL_ARCH):
|
||||
qlos_path = f'.os.{self.type.name.lower()}.map_syscall'
|
||||
@@ -397,4 +446,8 @@ class QlOsPosix(QlOs):
|
||||
|
||||
@property
|
||||
def shm(self):
|
||||
return self._shm
|
||||
return self._shm
|
||||
|
||||
@property
|
||||
def msq(self):
|
||||
return self._msq
|
||||
|
||||
@@ -6,6 +6,7 @@ from .fcntl import *
|
||||
from .futex import *
|
||||
from .ioctl import *
|
||||
from .mman import *
|
||||
from .msg import *
|
||||
from .net import *
|
||||
from .personality import *
|
||||
from .poll import *
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
from typing import Optional
|
||||
from qiling import Qiling
|
||||
from qiling.os.posix.const import *
|
||||
from qiling.os.posix.posix import QlMsqId, QlMsgBuf
|
||||
|
||||
|
||||
def __find_msg(msq: QlMsqId, msgtyp: int, msgflg: int) -> Optional[QlMsgBuf]:
|
||||
# peek at a specific queue item
|
||||
if msgflg & MSG_COPY:
|
||||
if msgtyp >= len(msq.queue):
|
||||
return -1 # ENOMSG
|
||||
|
||||
return msg.queue[msgtyp]
|
||||
|
||||
if msgtyp == 0:
|
||||
predicate = lambda msg: True
|
||||
|
||||
elif msgtype > 0:
|
||||
if msgflg & MSG_EXCEPT:
|
||||
predicate = lambda msg: msg.mtype != msgtyp
|
||||
else:
|
||||
predicate = lambda msg: msg.mtype == msgtyp
|
||||
|
||||
elif msgtype < 0:
|
||||
predicate = lambda msg: msg.mtype <= -msgtyp
|
||||
|
||||
return next((msg for msg in msq.queue if predicate(msg)), None)
|
||||
|
||||
|
||||
def __perms(ql: Qiling, msq: QlMsqId, flag: int) -> int:
|
||||
"""
|
||||
# see: https://elixir.bootlin.com/linux/v5.19.17/source/ipc/util.c#L553
|
||||
# check whether the user has permissions to access this message queue
|
||||
# FIXME: should probably also use cuid and (c)gid, but we don't support it yet
|
||||
# TODO: other ipc mechanisms like shm can also reuse this
|
||||
"""
|
||||
|
||||
request_mode = (flag >> 6) | (flag >> 3) | flag
|
||||
granted_mode = msq.mode
|
||||
|
||||
if ql.os.uid == msq.uid:
|
||||
granted_mode >>= 6
|
||||
|
||||
# is there some bit set in requested_mode but not in granted_mode?
|
||||
if request_mode & ~granted_mode & 0o007:
|
||||
return -1 # EACCES
|
||||
|
||||
return 0
|
||||
|
||||
def ql_syscall_msgget(ql: Qiling, key: int, msgflg: int):
|
||||
def __create_msq(key: int, flags: int) -> int:
|
||||
"""Create a new message queue for the specified key.
|
||||
|
||||
Returns: msqid of the newly created message queue, -1 if an error has occurred
|
||||
"""
|
||||
|
||||
if len(ql.os.msq) >= MSGMNI:
|
||||
return -1 # ENOSPC
|
||||
|
||||
mode = flags & ((1 << 9) - 1)
|
||||
|
||||
msqid = ql.os.msq.add(QlMsqId(key, ql.os.uid, ql.os.gid, mode))
|
||||
|
||||
ql.log.debug(f'created a new msg queue: key = {key:#x}, mode = 0{mode:o}. assigned id: {msqid:#x}')
|
||||
|
||||
return msqid
|
||||
|
||||
# create new message queue
|
||||
if key == IPC_PRIVATE:
|
||||
msqid = __create_msq(key, msgflg)
|
||||
|
||||
else:
|
||||
msqid, msq = ql.os.msq.get_by_key(key)
|
||||
|
||||
# a message queue with the specified key does not exist
|
||||
if msq is None:
|
||||
# the user asked to create a new one?
|
||||
if msgflg & IPC_CREAT:
|
||||
msqid = __create_msq(key, msgflg)
|
||||
|
||||
else:
|
||||
return -1 # 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
|
||||
|
||||
if __perms(ql, msq, msgflg):
|
||||
return -1 # EACCES
|
||||
|
||||
return msqid
|
||||
|
||||
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
|
||||
|
||||
# Check if the user has write permissions for the message queue
|
||||
if __perms(ql, msq, 0o222): # S_IWUGO
|
||||
return -1 # EACCES
|
||||
|
||||
msg_type = ql.mem.read_ptr(msgp)
|
||||
msg_text = ql.mem.read(msgp + ql.arch.pointersize, msgsz)
|
||||
|
||||
while True:
|
||||
if len(msq.queue) < msq.queue.maxlen:
|
||||
break
|
||||
|
||||
if msgflg & IPC_NOWAIT:
|
||||
return -1 # EAGAIN
|
||||
|
||||
msq.queue.append(QlMsgBuf(msg_type, bytes(msg_text)))
|
||||
|
||||
return 0 # Success
|
||||
|
||||
|
||||
def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int, msgflg: int):
|
||||
msq = ql.os.msq.get_by_id(msqid)
|
||||
|
||||
if msq is None:
|
||||
return -1 # EINVAL
|
||||
|
||||
if msgflg & MSG_COPY:
|
||||
if msgflg & MSG_EXCEPT or not (msgflg & IPC_NOWAIT):
|
||||
return -1 # EINVAL
|
||||
|
||||
# Check if the user has read permissions for the message queue
|
||||
if __perms(ql, msq, 0o444): # S_IRUGO
|
||||
return -1 # EACCES
|
||||
|
||||
while True:
|
||||
msg = __find_msg(msq, msgtyp, msgflg)
|
||||
|
||||
if msg is not None:
|
||||
break
|
||||
|
||||
if msgflg & IPC_NOWAIT:
|
||||
return -1 # ENOMSG
|
||||
|
||||
if not (msgflg & MSG_COPY):
|
||||
msq.queue.remove(msg)
|
||||
|
||||
if msgsz < len(msg.mtext):
|
||||
if not (msgflg & MSG_NOERROR):
|
||||
return -1 # E2BIG
|
||||
else:
|
||||
sz = msgsz
|
||||
else:
|
||||
sz = len(msg.mtext)
|
||||
|
||||
ql.mem.write_ptr(msgp, msg.mtype)
|
||||
ql.mem.write(msgp + ql.arch.pointersize, msg.mtext[:sz])
|
||||
|
||||
return sz # Success
|
||||
|
||||
__all__ = [
|
||||
'ql_syscall_msgget',
|
||||
'ql_syscall_msgsnd',
|
||||
'ql_syscall_msgrcv'
|
||||
]
|
||||
@@ -7,6 +7,7 @@ from qiling import Qiling
|
||||
from qiling.os.posix.const import *
|
||||
|
||||
from .shm import *
|
||||
from .msg import *
|
||||
|
||||
|
||||
def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, ptr: int, fifth: int):
|
||||
@@ -27,11 +28,34 @@ def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, p
|
||||
|
||||
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
|
||||
|
||||
msgp = ql.mem.read_ptr(args[3])
|
||||
msgtyp = ql.mem.read_ptr(args[3] + ql.arch.pointersize)
|
||||
|
||||
else:
|
||||
msgp = args[3]
|
||||
msgtyp = args[4]
|
||||
|
||||
return ql_syscall_msgrcv(ql, args[0], msgp, args[1], msgtyp, args[2])
|
||||
|
||||
ipc_call = {
|
||||
SHMAT: __call_shmat,
|
||||
SHMDT: __call_shmdt,
|
||||
SHMGET: __call_shmget
|
||||
SHMGET: __call_shmget,
|
||||
MSGGET: __call_msgget,
|
||||
MSGSND: __call_msgsnd,
|
||||
MSGRCV: __call_msgrcv
|
||||
}
|
||||
|
||||
if call not in ipc_call:
|
||||
|
||||
Reference in New Issue
Block a user