Skip to content

Commit

Permalink
Introduce signal intercepting example
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
GBuella committed Sep 12, 2017
1 parent 0542c9a commit 722410d
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 0 deletions.
5 changes: 5 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ target_link_libraries(fork_ban PRIVATE syscall_intercept_shared)

add_library(syscall_logger SHARED syscall_logger.c syscall_desc.c)
target_link_libraries(syscall_logger PRIVATE syscall_intercept_shared)

add_library(signal_interceptor SHARED signal_interceptor.c)
target_link_libraries(signal_interceptor PRIVATE syscall_intercept_shared)

add_executable(signaller signaller.c)
196 changes: 196 additions & 0 deletions examples/signal_interceptor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* Copyright 2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "libsyscall_intercept_hook_point.h"

#include <limits.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/syscall.h>

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

volatile bool should_be_busy;

static __thread bool reentrance_guard_flag;

typedef void sig_handler_func(int, siginfo_t *, void *);

struct sig_snapshot {
sig_handler_func *handler;
int sig;
siginfo_t *info;
void *arg;
};

static __thread struct sig_snapshot deferred_queue[0x1000];

static __thread size_t deferred_queue_usage;

static void
deferr_signal_handler(sig_handler_func *handler_addr,
int sig, siginfo_t *info, void *arg)
{
if (deferred_queue_usage == ARRAY_SIZE(deferred_queue))
return; /* signal ignored */

static const char busy_msg[] = "Sorry, I'm busy!\n";
syscall_no_intercept(SYS_write, 2, busy_msg, strlen(busy_msg));

/* XXX Another signal can arrive here, and that makes me a sad panda. */
deferred_queue[deferred_queue_usage].handler = handler_addr;
deferred_queue[deferred_queue_usage].sig = sig;
deferred_queue[deferred_queue_usage].info = info;
deferred_queue[deferred_queue_usage].arg = arg;
deferred_queue_usage++;
}

/* Assume 32 is a hard limit on signal number in the Linux kernel. */
static sig_handler_func *requested_signal_handlers[32 + 1];

static void
signal_hook(int sig, siginfo_t *info, void *arg)
{
if (sig < 0 || (size_t)sig >= ARRAY_SIZE(requested_signal_handlers))
return; /* Shoud never happen, in theory */

sig_handler_func *handler = requested_signal_handlers[sig];
if (reentrance_guard_flag)
deferr_signal_handler(handler, sig, info, arg);
else
handler(sig, info, arg);
}

static int
hook_rt_sigaction(int sig, const struct sigaction *action,
struct sigaction *original_action,
size_t sigsetsize, long *result)
{
if (sig < 0 || (size_t)sig >= ARRAY_SIZE(requested_signal_handlers))
return 1;

if (action->sa_handler == SIG_IGN || action->sa_handler == SIG_DFL)
return 1;

struct sigaction hooked_sigaction = *action;
hooked_sigaction.sa_sigaction = signal_hook;
*result = syscall_no_intercept(SYS_rt_sigaction,
sig, &hooked_sigaction, original_action,
sigsetsize);
if (*result == 0) {
original_action->sa_sigaction = requested_signal_handlers[sig];
requested_signal_handlers[sig] = action->sa_sigaction;
}
return 0;
}

static int
hook_write(int fd, const char *buf, size_t count)
{
static const char msg[] = "BLOCKING_SYSCALL\n";
if (fd != 1)
return 1;
if (count != strlen(msg))
return 1;
if (memcmp(buf, msg, strlen(msg)) != 0)
return 1;

should_be_busy = true;

while (should_be_busy) {
should_be_busy = should_be_busy || !should_be_busy;
/* set it to false in a debugger to finish this write syscall */
}

return 1;
}

static int
syscall_hook(long syscall_number,
long arg0, long arg1, long arg2, long arg3, long arg4, long arg5,
long *result)
{
(void) arg4;
(void) arg5;

switch (syscall_number) {
case SYS_rt_sigaction:
return hook_rt_sigaction((int)arg0,
(const void *)(uintptr_t)arg1,
(void *)(uintptr_t)arg2,
(size_t)arg3,
result);
case SYS_write:
return hook_write((int)arg0, (const char *)arg1, (size_t)arg2);
}

return 1;
}

static void
run_deferred_signals(void)
{
while (deferred_queue_usage > 0) {
struct sig_snapshot *sig =
deferred_queue + (--deferred_queue_usage);
sig->handler(sig->sig, sig->info, sig->arg);
}
}

static int
guarded_syscall_hook(long syscall_number,
long arg0, long arg1, long arg2, long arg3, long arg4, long arg5,
long *result)
{
bool is_first_level_entrance = !reentrance_guard_flag;

if (is_first_level_entrance)
reentrance_guard_flag = true;

int r = syscall_hook(syscall_number,
arg0, arg1, arg2, arg3, arg4, arg5, result);

if (is_first_level_entrance) {
reentrance_guard_flag = false;
run_deferred_signals();
}

return r;
}

static __attribute__((constructor)) void
start(void)
{
intercept_hook_point = guarded_syscall_hook;
}
68 changes: 68 additions & 0 deletions examples/signaller.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifdef NDEBUG
#undef NDEBUG
#endif

#include <assert.h>
#include <err.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

static void
usr1_handler(int sig)
{
static const char msg[] = "USR1 handler\n";
(void) sig;
assert(sig == SIGUSR1);

if (write(1, msg, strlen(msg)) != (ssize_t)strlen(msg)) {
/* if write failed, let's not try to `write` an error message */
_exit(2);
}
}

int
main(void)
{
if (signal(SIGUSR1, usr1_handler) == SIG_ERR)
err(1, "signal");

if (raise(SIGUSR1) != 0)
err(1, "raise");

static const char msg[] = "BLOCKING_SYSCALL\n";
if (write(1, msg, strlen(msg)) != (ssize_t)strlen(msg))
_exit(2);
}

0 comments on commit 722410d

Please sign in to comment.