Overhaul testing library constructors

We want to make it easier to test a bunch of different functions that
might be invoked in constructors of other libraries.

It seems conceivable that with these snippets, we could design other
tests that also work across a wide range of intercepted functions.
This commit is contained in:
Daniel Kahn Gillmor
2021-02-25 14:07:17 -05:00
parent 01f6bc76c9
commit 17522c5ba1
16 changed files with 90 additions and 74 deletions

4
.gitignore vendored
View File

@@ -2,10 +2,8 @@
*.so.1
timetest
test/getrandom_test
test/lib*.o
test/lib*.so
test/use_lib_random
test/use_lib_getpid
test/use_lib_*
test/repeat_random
test/getentropy_test
test/syscall_test

View File

@@ -6,6 +6,8 @@ LDFLAGS = -lrt -lpthread
SRC = timetest.c
OBJ = ${SRC:.c=.o}
TESTFUNCS = $(notdir $(basename $(wildcard snippets/*.c)))
all: timetest test
.c.o:
@@ -25,7 +27,7 @@ functest:
%_test: %_test.c
${CC} -o $@ ${CFLAGS} $<
randomtest: getrandom_test use_lib_random librandom.so repeat_random getentropy_test
randomtest: getrandom_test use_lib_getrandom libgetrandom.so repeat_random getentropy_test
./randomtest.sh
getpidtest: use_lib_getpid libgetpid.so
@@ -34,17 +36,23 @@ getpidtest: use_lib_getpid libgetpid.so
syscalltest: syscall_test
./syscalltest.sh
lib%.o: lib%.c
${CC} -c -o $@ -fpic ${CFLAGS} $<
lib%.so: lib%.o
${CC} -o $@ -shared ${CFLAGS} $<
## testing when interception points get called in library constructors:
use_lib_%: use_lib_%.c lib%.so
${CC} -L. -o $@ ${CFLAGS} $< -l$*
test_library_constructors: test_constructors.sh $(foreach f,${TESTFUNCS},use_lib_${f} lib${f}.so)
true $(foreach f,${TESTFUNCS},&& ./test_constructors.sh ${f})
lib%.so: _libtest.c snippets/%.c
sed s/FUNC_NAME/$*/g < _libtest.c | ${CC} -shared -o $@ -fpic ${CFLAGS} -x c -
use_lib_%: _use_lib_test.c snippets/%.c lib%.so
sed s/FUNC_NAME/$*/g < _use_lib_test.c | ${CC} -L. -o $@ ${CFLAGS} -x c - -l$*
## cleanup and metainformation
clean:
@rm -f ${OBJ} timetest getrandom_test lib*.o lib*.so use_lib_random use_lib_getpid syscall_test
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TESTFUNCS},use_lib_${f} lib${f}.so)
distclean: clean
@echo

8
test/_libtest.c Normal file
View File

@@ -0,0 +1,8 @@
#include "snippets/include_headers.h"
#define where "library"
void FUNC_NAME_as_needed() {
printf(" called FUNC_NAME_as_needed() \n");
}
static __attribute__((constructor)) void init_FUNC_NAME() {
#include "snippets/FUNC_NAME.c"
}

7
test/_use_lib_test.c Normal file
View File

@@ -0,0 +1,7 @@
#include "snippets/include_headers.h"
extern void FUNC_NAME_as_needed();
#define where "program"
int main() {
FUNC_NAME_as_needed();
#include "snippets/FUNC_NAME.c"
}

View File

@@ -1,13 +0,0 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void getpid_func() {
printf(" called getpid_func()\n");
}
static __attribute__((constructor)) void getpid_init() {
pid_t pid = getpid();
printf(" getpid() yielded %d\n", pid);
}

View File

@@ -1,6 +0,0 @@
#ifndef __LIBGETPID_H__
#define __LIBGETPID_H__
extern void getpid_func();
#endif

View File

@@ -1,17 +0,0 @@
#include <stdio.h>
#include <sys/random.h>
void func() {
printf(" called func()\n");
}
static __attribute__((constructor)) void rnd_init() {
unsigned int targ;
ssize_t ret = getrandom(&targ, sizeof(targ), 0);
if (ret == sizeof(targ)) {
printf(" getrandom() yielded 0x%08x\n", targ);
} else {
printf(" getrandom() failed with only %zd\n", ret);
}
}

View File

@@ -1,6 +0,0 @@
#ifndef __LIBRANDOM_H__
#define __LIBRANDOM_H__
extern void func();
#endif

View File

@@ -35,12 +35,12 @@ for iface in getrandom getentropy; do
done
printf 'testing shared object with getrandom() in library constructor\n'
LD_LIBRARY_PATH=. ./use_lib_random
LD_LIBRARY_PATH=. ./use_lib_getrandom
printf 'now with LD_PRELOAD and FAKERANDOM_SEED\n'
FAKERANDOM_SEED=0x0000000000000000 LD_PRELOAD="$FTPL" LD_LIBRARY_PATH=. ./use_lib_random
FAKERANDOM_SEED=0x0000000000000000 LD_PRELOAD="$FTPL" LD_LIBRARY_PATH=. ./use_lib_getrandom
# this demonstrates the crasher from https://github.com/wolfcw/libfaketime/issues/295
printf 'now with LD_PRELOAD without FAKERANDOM_SEED\n'
LD_PRELOAD="$FTPL" LD_LIBRARY_PATH=. ./use_lib_random
LD_PRELOAD="$FTPL" LD_LIBRARY_PATH=. ./use_lib_getrandom
FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./repeat_random 3 5 > repeat3x5

32
test/snippets/README Normal file
View File

@@ -0,0 +1,32 @@
Bulk testing of function interception
=====================================
Faketime intercepts some C library functions. We want to make it
easier to apply certain generic tests across many different functions.
Including a new function
------------------------
To test a function FOO, supply a C snippet in this directory named
<FOO.c>. This should be a small bit of code that exercises the
function FOO. It should be self-contained, and it should produce some
kind of description of what happened to stdout. Take a look at
getpid.c for a simple example.
The data sent to stdout should include the const char* "where" value
(which is an indication of which test framework is using the snippet).
And it should ideally be stable when the associated variable
(e.g. FAKETIME, FAKETIME_FAKEPID, or FAKERANDOM_SEED) is set, and
likely to vary otherwise, especially across a delay of a second or
more.
If the snippet needs to additional #include headers, please add them
in include_headers.h. These #includes will be used by every snippet,
so try to keep it minimal.
Testing across functions
------------------------
If you want to test something systemically, autogenerate code that
uses each snippet. See test_library_constructors in ../Makefile for
an example.

2
test/snippets/getpid.c Normal file
View File

@@ -0,0 +1,2 @@
pid_t pid = getpid();
printf("[%s] getpid() yielded %d\n", where, pid);

View File

@@ -0,0 +1,7 @@
unsigned int targ;
ssize_t ret = getrandom(&targ, sizeof(targ), 0);
if (ret == sizeof(targ)) {
printf("[%s] getrandom() yielded 0x%08x\n", where, targ);
} else {
printf("[%s] getrandom() failed with only %zd\n", where, ret);
}

View File

@@ -0,0 +1,4 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/random.h>

10
test/test_constructors.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
function="$1"
printf 'Testing library init for %s (no LD_PRELOAD)\n' "$function"
LD_LIBRARY_PATH=. "./use_lib_$function"
printf 'Testing library init for %s (LD_PRELOAD)\n' "$function"
LD_LIBRARY_PATH=. LD_PRELOAD="$FTPL" "./use_lib_$function"

View File

@@ -1,12 +0,0 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include "libgetpid.h"
int main() {
pid_t pid;
getpid_func();
pid = getpid();
printf(" getpid() -> %d\n", pid);
return 0;
}

View File

@@ -1,6 +0,0 @@
#include "librandom.h"
int main() {
func();
return 0;
}