Skip to content

Commit f912611

Browse files
committed
Initial signal support
1 parent 1730d8a commit f912611

File tree

4 files changed

+199
-10
lines changed

4 files changed

+199
-10
lines changed

qiling/os/posix/const.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
# File Open Limits
1818
NR_OPEN = 1024
1919

20+
# number of signals
21+
NSIG = 32
22+
2023
SOCK_TYPE_MASK = 0x0f
2124

2225
class linux_x86_socket_types(Enum):

qiling/os/posix/posix.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from qiling.const import QL_ARCH, QL_INTERCEPT
1111
from qiling.exception import QlErrorSyscallNotFound
1212
from qiling.os.os import QlOs
13-
from qiling.os.posix.const import NR_OPEN, errors
13+
from qiling.os.posix.const import NR_OPEN, NSIG, errors
1414
from qiling.os.posix.msq import QlMsq
1515
from qiling.os.posix.shm import QlShm
1616
from qiling.os.posix.syscall.abi import QlSyscallABI, arm, intel, mips, ppc, riscv
@@ -49,7 +49,6 @@ class QlOsPosix(QlOs):
4949

5050
def __init__(self, ql: Qiling):
5151
super().__init__(ql)
52-
self.sigaction_act = [0] * 256
5352

5453
conf = self.profile['KERNEL']
5554
self.uid = self.euid = conf.getint('uid')
@@ -92,6 +91,11 @@ def __init__(self, ql: Qiling):
9291

9392
self._shm = QlShm()
9493
self._msq = QlMsq()
94+
self._sig = [None] * NSIG
95+
96+
# a bitmap representing the blocked signals. a set bit at index i means signal i is blocked.
97+
# note that SIGKILL and SIGSTOP cannot be blocked.
98+
self.blocked_signals = 0
9599

96100
def __get_syscall_mapper(self, archtype: QL_ARCH):
97101
qlos_path = f'.os.{self.type.name.lower()}.map_syscall'
@@ -264,3 +268,7 @@ def shm(self):
264268
@property
265269
def msq(self):
266270
return self._msq
271+
272+
@property
273+
def sig(self):
274+
return self._sig

qiling/os/posix/syscall/signal.py

Lines changed: 170 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,189 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6-
from qiling import Qiling
6+
from __future__ import annotations
7+
8+
import ctypes
9+
from typing import TYPE_CHECKING, Type
10+
11+
from qiling.const import QL_ARCH
12+
from qiling.os import struct
13+
from qiling.os.posix.const import NSIG
14+
15+
# TODO: MIPS differs in too many details around signals; MIPS implementation is better extracted out
16+
17+
if TYPE_CHECKING:
18+
from qiling import Qiling
19+
from qiling.arch.arch import QlArch
20+
21+
22+
@struct.cache
23+
def __make_sigset(arch: QlArch):
24+
native_type = struct.get_native_type(arch.bits)
25+
26+
sigset_type = {
27+
QL_ARCH.X86: native_type,
28+
QL_ARCH.X8664: native_type,
29+
QL_ARCH.ARM: native_type,
30+
QL_ARCH.ARM64: native_type,
31+
QL_ARCH.MIPS: ctypes.c_uint32 * (128 // (4 * 8)),
32+
QL_ARCH.CORTEX_M: native_type
33+
}
34+
35+
if arch.type not in sigset_type:
36+
raise NotImplementedError(f'sigset definition is missing for {arch.type.name}')
37+
38+
return sigset_type[arch.type]
39+
40+
41+
@struct.cache
42+
def __make_sigaction(arch: QlArch) -> Type[struct.BaseStruct]:
43+
native_type = struct.get_native_type(arch.bits)
44+
Struct = struct.get_aligned_struct(arch.bits, arch.endian)
45+
46+
sigset_type = __make_sigset(arch)
47+
48+
# # FIXME: untill python 3.11 ctypes Union does not support an endianess that is different from
49+
# the hosting paltform. if a LE system is emulating a BE one or vice versa, this will fail. to
50+
# work around that we avoid using a union and refer to the inner field as 'sa_handler' regardless.
51+
#
52+
# Union = struct.get_aligned_union(arch.bits)
53+
#
54+
# class sighandler_union(Union):
55+
# _fields_ = (
56+
# ('sa_handler', native_type),
57+
# ('sa_sigaction', native_type)
58+
# )
59+
60+
# <WORKAROUND> see FIXME above
61+
class sighandler_union(Struct):
62+
_fields_ = (
63+
('sa_handler', native_type),
64+
)
65+
# </WORKAROUND>
66+
67+
# see: https://elixir.bootlin.com/linux/v5.19.17/source/arch/arm/include/uapi/asm/signal.h
68+
class arm_sigaction(Struct):
69+
_anonymous_ = ('_u',)
70+
71+
_fields_ = (
72+
('_u', sighandler_union),
73+
('sa_mask', sigset_type),
74+
('sa_flags', native_type),
75+
('sa_restorer', native_type)
76+
)
77+
78+
# see: https://elixir.bootlin.com/linux/v5.19.17/source/arch/x86/include/uapi/asm/signal.h
79+
class x86_sigaction(Struct):
80+
_anonymous_ = ('_u',)
81+
82+
_fields_ = (
83+
('_u', sighandler_union),
84+
('sa_mask', sigset_type),
85+
('sa_flags', native_type),
86+
('sa_restorer', native_type)
87+
)
88+
89+
class x8664_sigaction(Struct):
90+
_fields_ = (
91+
('sa_handler', native_type),
92+
('sa_flags', native_type),
93+
('sa_restorer', native_type),
94+
('sa_mask', sigset_type)
95+
)
96+
97+
# see: https://elixir.bootlin.com/linux/v5.19.17/source/arch/mips/include/uapi/asm/signal.h
98+
class mips_sigaction(Struct):
99+
_fields_ = (
100+
('sa_flags', ctypes.c_uint32),
101+
('sa_handler', native_type),
102+
('sa_mask', sigset_type)
103+
)
104+
105+
sigaction_struct = {
106+
QL_ARCH.X86: x86_sigaction,
107+
QL_ARCH.X8664: x8664_sigaction,
108+
QL_ARCH.ARM: arm_sigaction,
109+
QL_ARCH.ARM64: arm_sigaction,
110+
QL_ARCH.MIPS: mips_sigaction,
111+
QL_ARCH.CORTEX_M: arm_sigaction
112+
}
113+
114+
if arch.type not in sigaction_struct:
115+
raise NotImplementedError(f'sigaction definition is missing for {arch.type.name}')
116+
117+
return sigaction_struct[arch.type]
118+
7119

8120
def ql_syscall_rt_sigaction(ql: Qiling, signum: int, act: int, oldact: int):
121+
SIGKILL = 9
122+
SIGSTOP = 23 if ql.arch.type is QL_ARCH.MIPS else 19
123+
124+
if signum not in range(NSIG) or signum in (SIGKILL, SIGSTOP):
125+
return -1 # EINVAL
126+
127+
sigaction = __make_sigaction(ql.arch)
128+
9129
if oldact:
10-
arr = ql.os.sigaction_act[signum] or [0] * 5
11-
data = b''.join(ql.pack32(key) for key in arr)
130+
old = ql.os.sig[signum] or sigaction()
12131

13-
ql.mem.write(oldact, data)
132+
old.save_to(ql.mem, oldact)
14133

15134
if act:
16-
ql.os.sigaction_act[signum] = [ql.mem.read_ptr(act + 4 * i, 4) for i in range(5)]
135+
ql.os.sig[signum] = sigaction.load_from(ql.mem, act)
17136

18137
return 0
19138

20139

21-
def ql_syscall_rt_sigprocmask(ql: Qiling, how: int, nset: int, oset: int, sigsetsize: int):
22-
# SIG_BLOCK = 0x0
23-
# SIG_UNBLOCK = 0x1
140+
def __sigprocmask(ql: Qiling, how: int, newset: int, oldset: int):
141+
SIG_BLOCK = 0
142+
SIG_UNBLOCK = 1
143+
SIG_SETMASK = 2
144+
145+
SIGKILL = 9
146+
SIGSTOP = 19
147+
148+
if oldset:
149+
ql.mem.write_ptr(newset, ql.os.blocked_signals)
150+
151+
if newset:
152+
set_mask = ql.mem.read_ptr(newset)
153+
154+
if how == SIG_BLOCK:
155+
ql.os.blocked_signals |= set_mask
156+
157+
elif how == SIG_UNBLOCK:
158+
ql.os.blocked_signals &= ~set_mask
159+
160+
elif how == SIG_SETMASK:
161+
ql.os.blocked_signals = set_mask
24162

163+
else:
164+
return -1 # EINVAL
165+
166+
# silently drop attempts to block SIGKILL and SIGSTOP
167+
ql.os.blocked_signals &= ~((1 << SIGKILL) | (1 << SIGSTOP))
168+
169+
return 0
170+
171+
172+
def __sigprocmask_mips(ql: Qiling, how: int, newset: int, oldset: int):
173+
SIG_BLOCK = 1
174+
SIG_UNBLOCK = 2
175+
SIG_SETMASK = 3
176+
177+
SIGKILL = 9
178+
SIGSTOP = 23
179+
180+
# TODO: to implement
25181
return 0
26182

27183

184+
def ql_syscall_rt_sigprocmask(ql: Qiling, how: int, newset: int, oldset: int):
185+
impl = __sigprocmask_mips if ql.arch.type is QL_ARCH.MIPS else __sigprocmask
186+
187+
return impl(ql, how, newset, oldset)
188+
189+
28190
def ql_syscall_signal(ql: Qiling, sig: int, sighandler: int):
29191
return 0

qiling/os/posix/syscall/unistd.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ def ql_syscall_capset(ql: Qiling, hdrp: int, datap: int):
152152

153153

154154
def ql_syscall_kill(ql: Qiling, pid: int, sig: int):
155+
if sig not in range(NSIG):
156+
return -1 # EINVAL
157+
158+
if pid > 0 and pid != ql.os.pid:
159+
return -1 # ESRCH
160+
161+
sigaction = ql.os.sig[sig]
162+
163+
# sa_handler is:
164+
# SIG_DFL for the default action.
165+
# SIG_IGN to ignore this signal.
166+
# handler pointer
167+
168+
# if sa_flags & SA_SIGINFO:
169+
# call sa_sigaction instead of sa_handler
170+
155171
return 0
156172

157173

0 commit comments

Comments
 (0)