Merge pull request #302 from dkg/syscall-interception

Intercept syscall
This commit is contained in:
Wolfgang Hommel
2021-02-25 06:15:42 +01:00
committed by GitHub
5 changed files with 102 additions and 0 deletions

View File

@@ -44,6 +44,10 @@
# FAKE_PID
# - Intercept getpid()
#
# INTERCEPT_SYSCALL
# - (On GNU/Linux only) intercept glibc's syscall() for known relevant syscalls.
# If enabled, this currently only works to divert the getrandom syscall.
#
# FORCE_MONOTONIC_FIX
# - If the test program hangs forever on
# " pthread_cond_timedwait: CLOCK_MONOTONIC test

View File

@@ -43,6 +43,14 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <limits.h>
#ifdef INTERCEPT_SYSCALL
#ifdef __linux__
#include <stdarg.h>
#include <sys/syscall.h>
#else
#error INTERCEPT_SYSCALL should only be defined on GNU/Linux systems.
#endif
#endif
#include "uthash.h"
@@ -230,6 +238,10 @@ static ssize_t (*real_getrandom) (void *buf, size_t buflen, unsigned
static pid_t (*real_getpid) ();
#endif
#ifdef INTERCEPT_SYSCALL
static long (*real_syscall) (long, ...);
#endif
static int initialized = 0;
/* prototypes */
@@ -2460,6 +2472,10 @@ static void ftpl_init(void)
real_getpid = dlsym(RTLD_NEXT, "getpid");
#endif
#ifdef INTERCEPT_SYSCALL
real_syscall = dlsym(RTLD_NEXT, "syscall");
#endif
#ifdef FAKE_PTHREAD
#ifdef __GLIBC__
@@ -3716,6 +3732,45 @@ pid_t getpid() {
}
#endif
#ifdef INTERCEPT_SYSCALL
/* see https://github.com/wolfcw/libfaketime/issues/301 */
long syscall(long number, ...) {
va_list ap;
va_start(ap, number);
#ifdef FAKE_RANDOM
if (number == __NR_getrandom && getenv("FAKERANDOM_SEED")) {
void *buf;
size_t buflen;
unsigned int flags;
buf = va_arg(ap, void*);
buflen = va_arg(ap, size_t);
flags = va_arg(ap, unsigned int);
va_end(ap);
return getrandom(buf, buflen, flags);
}
#endif
/*
Invocations of C variadic arguments that are smaller than int are
promoted to int. For larger arguments, it's likely that they are
chopped into int-sized pieces.
So the passthrough part of this code is attempting to reverse that
ABI so we can pass the arguments back into syscall().
Note that the Linux kernel appears to have baked-in 6 as the
maximum number of arguments for a syscall beyond the syscall number
itself.
*/
#define vararg_promotion_t int
#define syscall_max_args 6
vararg_promotion_t a[syscall_max_args];
for (int i = 0; i < syscall_max_args; i++)
a[i] = va_arg(ap, vararg_promotion_t);
va_end(ap);
return real_syscall(number, a[0], a[1], a[2], a[3], a[4], a[5]);
}
#endif
/*
* Editor modelines
*

View File

@@ -31,6 +31,9 @@ randomtest: getrandom_test use_lib_random librandom.so
getpidtest: use_lib_getpid libgetpid.so
./pidtest.sh
syscalltest: syscall_test
./syscalltest.sh
lib%.o: lib%.c
${CC} -c -o $@ -fpic ${CFLAGS} $<

11
test/syscall_test.c Normal file
View File

@@ -0,0 +1,11 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main() {
int d = 0;
long r = syscall(__NR_getrandom, &d, sizeof(d), 0);
printf("getrandom(%d, <ptr>, %zd, 0) returned %ld and yielded 0x%08x\n",
__NR_getrandom, sizeof(d), r, d);
return 0;
}

29
test/syscalltest.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
set -e
error=0
run0=$(./syscall_test)
run1=$(LD_PRELOAD="$FTPL" ./syscall_test)
run2=$(FAKERANDOM_SEED=0x0000000000000000 LD_PRELOAD="$FTPL" ./syscall_test)
run3=$(FAKERANDOM_SEED=0x0000000000000000 LD_PRELOAD="$FTPL" ./syscall_test)
run4=$(FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./syscall_test)
if [ "$run0" = "$run1" ] ; then
error=1
printf >&2 'test run without LD_PRELOAD matches run with LD_PRELOAD. This is very unlikely.\n'
fi
if [ "$run1" = "$run2" ] ; then
error=2
printf >&2 'test with LD_PRELOAD but without FAKERANDOM_SEED matches run with LD_PRELOAD and FAKERANDOM_SEED. This is also very unlikely.\n'
fi
if [ "$run2" != "$run3" ]; then
error=1
printf >&2 'test run with same seed produces different outputs.\n'
fi
if [ "$run3" = "$run4" ]; then
error=1
printf >&2 'test runs with different seeds produce the same outputs.\n'
fi