Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit 154f91f

Browse files
committed
Introduce signal intercepting example
It is a nice first attempt to demonstrate the idea, far from complete. To give it a try, start the dummy program which installs a signal handler: LD_LIBRARY_PATH=./examples LD_PRELOAD=libsignal_interceptor.so ./examples/signaller Send it a USR! signal, and see what happens.
1 parent e15d384 commit 154f91f

File tree

3 files changed

+269
-0
lines changed

3 files changed

+269
-0
lines changed

examples/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,8 @@ target_link_libraries(fork_ban PRIVATE syscall_intercept_shared)
3939

4040
add_library(syscall_logger SHARED syscall_logger.c syscall_desc.c)
4141
target_link_libraries(syscall_logger PRIVATE syscall_intercept_shared)
42+
43+
add_library(signal_interceptor SHARED signal_interceptor.c)
44+
target_link_libraries(signal_interceptor PRIVATE syscall_intercept_shared)
45+
46+
add_executable(signaller signaller.c)

examples/signal_interceptor.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright 2017, Intel Corporation
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
*
11+
* * Redistributions in binary form must reproduce the above copyright
12+
* notice, this list of conditions and the following disclaimer in
13+
* the documentation and/or other materials provided with the
14+
* distribution.
15+
*
16+
* * Neither the name of the copyright holder nor the names of its
17+
* contributors may be used to endorse or promote products derived
18+
* from this software without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
33+
#include "libsyscall_intercept_hook_point.h"
34+
35+
#include <limits.h>
36+
#include <signal.h>
37+
#include <stdbool.h>
38+
#include <stdint.h>
39+
#include <string.h>
40+
#include <sys/syscall.h>
41+
42+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
43+
44+
volatile bool should_be_busy;
45+
46+
static __thread bool reentrance_guard_flag;
47+
48+
typedef void sig_handler_func(int, siginfo_t *, void *);
49+
50+
struct sig_snapshot {
51+
sig_handler_func *handler;
52+
int sig;
53+
siginfo_t *info;
54+
void *arg;
55+
};
56+
57+
static __thread struct sig_snapshot deferred_queue[0x1000];
58+
59+
static __thread size_t deferred_queue_usage;
60+
61+
static void
62+
deferr_signal_handler(sig_handler_func *handler_addr,
63+
int sig, siginfo_t *info, void *arg)
64+
{
65+
if (deferred_queue_usage == ARRAY_SIZE(deferred_queue))
66+
return; /* signal ignored */
67+
68+
static const char busy_msg[] = "Sorry, I'm busy!\n";
69+
syscall_no_intercept(SYS_write, 2, busy_msg, strlen(busy_msg));
70+
71+
/* XXX Another signal can arrive here, and that makes me a sad panda. */
72+
deferred_queue[deferred_queue_usage].handler = handler_addr;
73+
deferred_queue[deferred_queue_usage].sig = sig;
74+
deferred_queue[deferred_queue_usage].info = info;
75+
deferred_queue[deferred_queue_usage].arg = arg;
76+
deferred_queue_usage++;
77+
}
78+
79+
/* Assume 32 is a hard limit on signal number in the Linux kernel. */
80+
static sig_handler_func *requested_signal_handlers[32 + 1];
81+
82+
static void
83+
signal_hook(int sig, siginfo_t *info, void *arg)
84+
{
85+
if (sig < 0 || (size_t)sig >= ARRAY_SIZE(requested_signal_handlers))
86+
return; /* Shoud never happen, in theory */
87+
88+
sig_handler_func *handler = requested_signal_handlers[sig];
89+
if (reentrance_guard_flag)
90+
deferr_signal_handler(handler, sig, info, arg);
91+
else
92+
handler(sig, info, arg);
93+
}
94+
95+
static int
96+
hook_rt_sigaction(int sig, const struct sigaction *action,
97+
struct sigaction *original_action,
98+
size_t sigsetsize, long *result)
99+
{
100+
if (sig < 0 || (size_t)sig >= ARRAY_SIZE(requested_signal_handlers))
101+
return 1;
102+
103+
if (action->sa_handler == SIG_IGN || action->sa_handler == SIG_DFL)
104+
return 1;
105+
106+
struct sigaction hooked_sigaction = *action;
107+
hooked_sigaction.sa_sigaction = signal_hook;
108+
*result = syscall_no_intercept(SYS_rt_sigaction,
109+
sig, &hooked_sigaction, original_action,
110+
sigsetsize);
111+
if (*result == 0) {
112+
original_action->sa_sigaction = requested_signal_handlers[sig];
113+
requested_signal_handlers[sig] = action->sa_sigaction;
114+
}
115+
return 0;
116+
}
117+
118+
static int
119+
hook_write(int fd, const char *buf, size_t count)
120+
{
121+
static const char msg[] = "BLOCKING_SYSCALL\n";
122+
if (fd != 1)
123+
return 1;
124+
if (count != strlen(msg))
125+
return 1;
126+
if (memcmp(buf, msg, strlen(msg)) != 0)
127+
return 1;
128+
129+
should_be_busy = true;
130+
131+
while (should_be_busy) {
132+
should_be_busy = should_be_busy || !should_be_busy;
133+
/* set it to false in a debugger to finish this write syscall */
134+
}
135+
136+
return 1;
137+
}
138+
139+
static int
140+
syscall_hook(long syscall_number,
141+
long arg0, long arg1, long arg2, long arg3, long arg4, long arg5,
142+
long *result)
143+
{
144+
(void) arg4;
145+
(void) arg5;
146+
147+
switch (syscall_number) {
148+
case SYS_rt_sigaction:
149+
return hook_rt_sigaction((int)arg0,
150+
(const void *)(uintptr_t)arg1,
151+
(void *)(uintptr_t)arg2,
152+
(size_t)arg3,
153+
result);
154+
case SYS_write:
155+
return hook_write((int)arg0, (const char *)arg1, (size_t)arg2);
156+
}
157+
158+
return 1;
159+
}
160+
161+
static void
162+
run_deferred_signals(void)
163+
{
164+
while (deferred_queue_usage > 0) {
165+
struct sig_snapshot *sig =
166+
deferred_queue + (--deferred_queue_usage);
167+
sig->handler(sig->sig, sig->info, sig->arg);
168+
}
169+
}
170+
171+
static int
172+
guarded_syscall_hook(long syscall_number,
173+
long arg0, long arg1, long arg2, long arg3, long arg4, long arg5,
174+
long *result)
175+
{
176+
bool is_first_level_entrance = !reentrance_guard_flag;
177+
178+
if (is_first_level_entrance)
179+
reentrance_guard_flag = true;
180+
181+
int r = syscall_hook(syscall_number,
182+
arg0, arg1, arg2, arg3, arg4, arg5, result);
183+
184+
if (is_first_level_entrance) {
185+
reentrance_guard_flag = false;
186+
run_deferred_signals();
187+
}
188+
189+
return r;
190+
}
191+
192+
static __attribute__((constructor)) void
193+
start(void)
194+
{
195+
intercept_hook_point = guarded_syscall_hook;
196+
}

examples/signaller.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2017, Intel Corporation
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
*
11+
* * Redistributions in binary form must reproduce the above copyright
12+
* notice, this list of conditions and the following disclaimer in
13+
* the documentation and/or other materials provided with the
14+
* distribution.
15+
*
16+
* * Neither the name of the copyright holder nor the names of its
17+
* contributors may be used to endorse or promote products derived
18+
* from this software without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
33+
#ifdef NDEBUG
34+
#undef NDEBUG
35+
#endif
36+
37+
#include <assert.h>
38+
#include <err.h>
39+
#include <signal.h>
40+
#include <string.h>
41+
#include <unistd.h>
42+
43+
static void
44+
usr1_handler(int sig)
45+
{
46+
static const char msg[] = "USR1 handler\n";
47+
(void) sig;
48+
assert(sig == SIGUSR1);
49+
50+
if (write(1, msg, strlen(msg)) != (ssize_t)strlen(msg)) {
51+
/* if write failed, let's not try to `write` an error message */
52+
_exit(2);
53+
}
54+
}
55+
56+
int
57+
main(void)
58+
{
59+
if (signal(SIGUSR1, usr1_handler) == SIG_ERR)
60+
err(1, "signal");
61+
62+
if (raise(SIGUSR1) != 0)
63+
err(1, "raise");
64+
65+
static const char msg[] = "BLOCKING_SYSCALL\n";
66+
if (write(1, msg, strlen(msg)) != (ssize_t)strlen(msg))
67+
_exit(2);
68+
}

0 commit comments

Comments
 (0)