#include "libsyscall_intercept_hook_point.h"
#include <errno.h>
#include <stdbool.h>
#include <sched.h>
#include <syscall.h>
#include <stdlib.h>
#define FORK_MAX_COUNT 16
static bool
specifies_new_stack(long syscall_number, long arg0, long arg1)
{
(void) arg0;
return syscall_number == SYS_clone && (arg1 != 0);
}
static bool
is_syscall_fork(long syscall_number, long arg0)
{
if (syscall_number == SYS_fork || syscall_number == SYS_vfork)
return true;
if (syscall_number == SYS_clone && (arg0 & CLONE_THREAD) == 0)
return true;
return false;
}
static int fork_counter;
static int fork_counter_max = FORK_MAX_COUNT;
static long
example_fork_hook(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5)
{
long result;
result = syscall_no_intercept(syscall_number,
arg0, arg1, arg2, arg3, arg4, arg5);
if (fork_counter > 4 && result > 0) {
result += 16;
}
return result;
}
static int
hook(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5,
long *result)
{
(void) arg2;
(void) arg3;
(void) arg4;
(void) arg5;
if (!is_syscall_fork(syscall_number, arg0))
return 1;
if (fork_counter >= fork_counter_max) {
static const char msg[] = "fork count has exceeded maximum.\n";
syscall_no_intercept(SYS_write, 2, msg, sizeof(msg));
*result = -EAGAIN;
return 0;
}
++fork_counter;
if (specifies_new_stack(syscall_number, arg0, arg1)) {
return 1;
} else {
*result = example_fork_hook(syscall_number,
arg0, arg1, arg2, arg3, arg4, arg5);
return 0;
}
}
static __attribute__((constructor)) void
start(void)
{
const char *e = getenv("ALLOW_FORK_MAX");
if (e != NULL)
fork_counter_max = atoi(e);
intercept_hook_point = &hook;
}