103 Commits

Author SHA1 Message Date
Wolfgang Hommel
46a0f84c1e Intecept pthread_cond_clockwait (addresses #353) 2022-02-20 21:51:28 +01:00
Wolfgang Hommel
985d666d73 Honor x/i flags also with frozen faketime stamps (closes #360) 2022-02-20 21:22:01 +01:00
Wolfgang Hommel
9dcaf53fd7 faketime wrapper complains when env vars are set unless comp/w SILENT (closes #307) 2022-02-20 20:40:19 +01:00
Wolfgang Hommel
02bc1fccae Version bump to 0.9.10 (prepares for #366) 2022-02-20 17:53:54 +01:00
Wolfgang Hommel
2c02fc08ef Further dyld interposing for macOS Monterey support (addresses #357) 2022-02-20 17:39:17 +01:00
Wolfgang Hommel
2d5126411b Merge pull request #363 from sirainen/new-calls
Add fstat(), stat() and lstat() calls
2022-02-18 20:56:42 +01:00
Wolfgang Hommel
ee4f57d8a5 Additional dyld interposing for macOS Monterey support (addresses #357) 2022-02-16 21:27:08 +01:00
Timo Sirainen
f09c98a89f Add fstat(), stat() and lstat() calls 2022-02-16 12:01:35 +02:00
Timo Sirainen
527da8441b Implement all stat-like functions with STAT_HANDLER() and STAT64_HANDLER() macros 2022-02-16 11:58:42 +02:00
Timo Sirainen
79defa361e Check missing real_* functions using CHECK_MISSING_REAL() macro 2022-02-16 11:58:05 +02:00
Timo Sirainen
6d7c42e2df Fix disabling all *stat*() faking during initialization
Only __xstat() variant was handling the dont_fake variable.
2022-02-16 11:58:04 +02:00
Timo Sirainen
a7e536bcca Rename real_*stat* variables to correspond to the actual function names 2022-02-16 11:55:30 +02:00
Wolfgang Hommel
5466cd8a5f Merge branch 'macos' 2022-02-06 21:40:50 +01:00
Wolfgang Hommel
61490dc09a Change dyld interposing for basic macOS Monterey support (addresses #357) 2022-02-06 21:39:29 +01:00
Wolfgang Hommel
db47664840 Merge pull request #368 from dkg/clean-strptime
Avoid spurious "Success" error message.
2022-02-05 09:22:53 +01:00
Daniel Kahn Gillmor
bc24e278ff Avoid spurious "Success" error message.
strptime(3) doesn't set errno, so when it was failing, calling perror()
meant producing messages like:

Failed to parse FAKETIME timestamp: Success

Rather than use perror(), just send the warning message directly to
stderr.

This was first reported in https://bugs.debian.org/939789
2022-02-04 19:04:45 -05:00
Wolfgang Hommel
b0b9432ea4 Merge pull request #367 from dkg/manpage-formatting
formatting cleanups
2022-02-04 23:23:54 +01:00
Daniel Kahn Gillmor
84fc285923 stackoverflow uses https 2022-02-04 16:47:44 -05:00
Daniel Kahn Gillmor
806c05f49d manpage: Minor cleanup to faketime.1
- close quotes correctly in "Relative time offset"
- github uses https
- e.g. and i.e. should be set off from what follows with a comma
2022-02-04 16:40:57 -05:00
Daniel Kahn Gillmor
fe6eeae423 manpage: structure source with one sentence per line
Using this structure makes diffs easier to read, when changes are due.

The underlying formatting produced by groff ends up basically the same
(though some versions of groff may adjust to have two spaces after a
sentence-ending period instead of one).
2022-02-04 16:37:27 -05:00
Wolfgang Hommel
f26242b655 Merge pull request #352 from luochunbei/master 2021-10-10 14:23:30 +02:00
luochunbei
e0ca33132d add explicit data type conversion to avoid integer overflow 2021-10-10 14:39:51 +08:00
Wolfgang Hommel
cbf1d729ed Merge pull request #350 from a1346054/fixes
Simple maintenance improvements
2021-09-22 06:26:19 +02:00
a1346054
543f6b5040 Trim excess whitespace 2021-09-21 21:03:50 +00:00
a1346054
aa9eb1006d Fix codestyle deviations 2021-09-21 21:03:14 +00:00
a1346054
14cf8d7ba8 Fix spelling 2021-09-21 20:46:28 +00:00
Wolfgang Hommel
f4ae29fb91 Merge pull request #348 from GranBurguesa/patch-1
fix do/while guard for DONT_FAKE_TIME macro
2021-09-17 19:34:53 +02:00
GranBurguesa
a9142e0e9a fix do/while guard for DONT_FAKE_TIME macro
the newer version gcc warns `this ‘while’ clause does not guard... [-Werror=misleading-indentation]`. looks like the author just omitted the `do` and the `while(0) counts as a separate statement.

in practice this isn't causing any actual problem now afaict.
2021-09-17 10:41:55 -04:00
Wolfgang Hommel
b7fff74716 Merge pull request #344 from sliquister/fake-stateless
Add a build variable to opt-out of behaviors that reduce reliability
2021-08-01 20:44:14 +02:00
Valentin Gatien-Baron
e26859e5ca add a build variable to opt-out of some behaviors
Specifically behaviors that increase the chance that a wrapped program
will not behave like an unwrapped program does, thus causing
reliability issues.
2021-08-01 08:41:17 -04:00
Valentin Gatien-Baron
3155e0ee38 try to clarify the help of a couple of compilatoin variables 2021-08-01 08:02:59 -04:00
Valentin Gatien-Baron
078a4e4060 group cpp variables according to whether they are set by default 2021-08-01 07:58:06 -04:00
Wolfgang Hommel
9043941fa9 Merge pull request #342 from sliquister/timespec_get
wrap timespec_get
2021-07-30 22:54:00 +02:00
Valentin Gatien-Baron
973111d78a wrap timespec_get 2021-07-30 13:46:24 -04:00
Wolfgang Hommel
4bab3179ce Unlock mutex before exiting in case of error (fixes #340) 2021-07-17 19:44:20 +02:00
Wolfgang Hommel
2090f5e548 Fix in __xstat regarding dont_fake handling 2021-06-22 21:51:28 +02:00
Wolfgang Hommel
f88c8d4221 Do not cache '%' in parse_ft_string (addresses #337) 2021-06-22 21:47:57 +02:00
Wolfgang Hommel
9a73db074b Merge pull request #328 from jelly/gzip_reproducible
Do not store the timestamp in the gzip
2021-05-11 18:42:09 +02:00
Jelle van der Waa
932c138112 Do not store the timestamp in the gzip
To make libfaketime reproducible don't embed the timestamp in the gzip
header.

Motivation: https://reproducible-builds.org
2021-05-11 17:03:01 +02:00
Wolfgang Hommel
9e27b2ed8b Merge pull request #320 from sliquister/master
add support for timerfd_{set,get}time
2021-03-31 20:05:02 +02:00
Valentin Gatien-Baron
c9f292ee39 add support for timerfd_{set,get}time 2021-03-30 13:02:24 -04:00
Wolfgang Hommel
d37421dbe7 Merge pull request #319 from jimklimov/install-doc
Makefile: define PREFIX same as in sub-Makefiles to install "doc" to …
2021-03-28 21:09:34 +02:00
Jim Klimov
89161a0cdf Makefile: define PREFIX same as in sub-Makefiles to install "doc" to reasonable path 2021-03-28 21:01:38 +03:00
Wolfgang Hommel
f87c2f8915 Merge pull request #318 from jimklimov/date-prog-sun
faketime.c: default to GNU date as "gdate" on Sun-related OSes
2021-03-28 19:35:41 +02:00
Wolfgang Hommel
ce1d39c98f Merge pull request #317 from jimklimov/date-prog-arg
faketime.c: allow user to select their implementation of GNU date
2021-03-28 19:35:10 +02:00
Wolfgang Hommel
262d1d574f Merge pull request #316 from jimklimov/eol
src/sunos_endian.h: No newline at end of file
2021-03-28 19:32:01 +02:00
Jim Klimov
06d49adc12 faketime.c: default to GNU date as "gdate" on Sun-related OSes 2021-03-28 20:17:07 +03:00
Jim Klimov
1686664c97 faketime.c: allow user to select their implementation of GNU date 2021-03-28 20:14:27 +03:00
Jim Klimov
5217bcd13d src/sunos_endian.h: No newline at end of file
For pedantic compilers this is actually a fatal error, since per
(older?) C standards the file should end with an EOL.
2021-03-28 18:54:26 +03:00
Wolfgang Hommel
8ae4c9bc0e Merge pull request #313 from dkg/test-variadic-promotion
Test variadic promotion
2021-03-06 09:46:07 +01:00
Daniel Kahn Gillmor
6733dc3a8d tests: Confirm variadic argument promotion assumptions when INTERCEPT_SYSCALL
The test suite should not succeed if INTERCEPT_SYSCALL is defined but
the variadic argument promotion test fails.

OTOH, if we're not asking for INTERCEPT_SYSCALL, we don't care about
the results of that test.
2021-03-05 22:48:47 -05:00
Daniel Kahn Gillmor
008d33fdf2 Test assumptions about variadic re-packing
This test uses the same style of re-packing variadic arguments through
two layers of variadic calls, and compares that call chain against one
direct variadic call.

The outer function uses the same kind of re-packing used in
src/libfaketime.c's syscall (leading to real_syscall), but the inner
functions use different assumptions about the types of each argument.

This is not an entirely comprehensive test, because we only define two
different inner function signatures.  If some particular syscall is
breaking when intercepted, consider adding something like its expected
function signature in test/variadic/inner.c, and invoke it in
test/variadic/main.c.

Note that we don't test any floating point types (those types are
typically passed in registers in x86-64, not on the stack, and are
also not used for any syscall that i'm aware of).
2021-03-05 22:48:47 -05:00
Daniel Kahn Gillmor
5a0071f952 Centralize assumptions about variadic argument re-packing
By stating these assumptions in src/faketime_common.h, we can reuse
them in the tests as well as in the code.
2021-03-05 21:46:18 -05:00
Daniel Kahn Gillmor
51f1248593 tests: use CFLAGS from the environment.
This makes the test build process use the same sort of CFLAGS as the rest of the code.
2021-03-05 21:45:23 -05:00
Daniel Kahn Gillmor
e70b143733 Prepare to add new tests depending on the definitions
We want to be able to conditionally add tests.  This sets up to be
able to do that cleanly.
2021-03-05 21:45:23 -05:00
Wolfgang Hommel
e1073c8733 Promote syscall passthrough arguments to long instead of int (#310) 2021-03-04 19:24:24 +01:00
Wolfgang Hommel
01b0b4bb56 Merge pull request #312 from dkg/avoid-diversion
Pass through syscall(__NR_clock_gettime) if FAKERANDOM is unset
2021-03-03 06:36:26 +01:00
Daniel Kahn Gillmor
5f5756ccd9 Pass through syscall(__NR_clock_gettime) if FAKERANDOM is unset
If FAKERANDOM is unset, we were still intercepting syscall() and
passing it through to clock_gettime, rather than letting it fall
through to real_syscall.

That would have the effect of diverting syscall(__NR_clock_gettime,…)
into the libc invocation of clock_gettime(…) (via real_clock_gettime).
While that probably does the same thing, it's probably a mistake to do
such a diversion when FAKETIME is unset.
2021-03-02 20:01:18 -05:00
Wolfgang Hommel
bca9f1bf90 Merge pull request #311 from dkg/more-testing
More snippet testing and better documentation
2021-03-02 21:44:56 +01:00
Daniel Kahn Gillmor
d3f3ee38c6 Add syscall_clock_gettime_heap snippet
This invokes clock_gettime, but uses a timespec from the heap instead
of the stack.

It appears to be successful for me on x86-64 GNU/Linux.

This rules out one possible cause of the error reported in #310: I was
worried that an address from the range occupied by the heap might
somehow be corrupted by the syscall variadic argument de-mangling, but
that looks like it is not the case.
2021-03-02 10:33:07 -05:00
Daniel Kahn Gillmor
a3f9410e51 Add clock_gettime_heap snippet
This invokes clock_gettime, but uses a timespec from the heap instead
of the stack.
2021-03-02 10:26:20 -05:00
Daniel Kahn Gillmor
a92d6ffe7c add snippet testing clock_gettime(CLOCK_REALTIME) 2021-03-02 10:23:11 -05:00
Daniel Kahn Gillmor
253774c8d8 added new simple snippet "time.c" 2021-03-01 21:47:18 -05:00
Daniel Kahn Gillmor
986e6e1cdc Clarify test/Makefile and snippet testing documentation
Hopefully this makes it easier for future development work to augment
the snippet-based testing.
2021-03-01 21:40:57 -05:00
Daniel Kahn Gillmor
0bfb72b627 tests: normalize "where" variable to include framework prefix and snippet name 2021-03-01 21:08:00 -05:00
Daniel Kahn Gillmor
5a1bd98979 parallelize library_contructors test 2021-03-01 21:05:22 -05:00
Daniel Kahn Gillmor
7e62881c8f Name "snippets" explicitly
Earlier, this code was conceived of to test a "function" specifically,
but some future snippet could test multiple function calls, or a
subset of a function call (e.g. snippets/syscall_clock_gettime.c
already only tests one particular syscall diversion number).

Normalizing on the name "snippet" should make it easier to understand
the code going forward.
2021-03-01 15:06:22 -05:00
Wolfgang Hommel
0e6b1b2460 Merge pull request #309 from dkg/faketime-pid
faketime: add -p option to wrapper for setting PID
2021-02-26 20:46:27 +01:00
Wolfgang Hommel
1297568caf Merge pull request #306 from dkg/cleanup-tests
Overhaul recently-added tests (new additional snippet-driven testing framework)
2021-02-26 20:28:38 +01:00
Daniel Kahn Gillmor
940502b3de Added snippet for syscall(__NR_clock_gettime)
Closes: #176
2021-02-25 23:33:30 -05:00
Daniel Kahn Gillmor
26b4b395e9 Include a check for getentropy interception
This snippet applies to both the library constructors and variable
data test frameworks.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
0b0cc29d2e test/randomtest.sh: avoid touching the filesystem 2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
a5885f1479 Drop more duplicative tests
Now that we have the snippet-driven test_variable_data suite, most of
the other longer hand-written tests are duplicative.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
0872c6c0c0 Add test_variable_data framework that reuses the snippets
Most of these snippets are likely to have some env var that causes the
data to hold constant, while the data will otherwise be likely to vary
over time.

This framework offers a way to test those snippets, by dropping the
variable and an example value in the test/snippets/FOO.variable
one-line file.

Note that the test/snippets/syscall.c snippet is *not* expected to
vary over time (or to differ when any given variable is set), so we
simply don't add any test/snippets/syscall.variable file to avoid it
being tested in this way.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
a51a38d0ae Handle when another library uses a syscall in a constructor
Without this fix, the test_library_constructors test was failing on
use_lib_syscall.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
f47223ff12 Include snippet for syscall() interception in library constructors 2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
7b1d0958b5 Drop duplicate library constructor preload tests
These tests are already taken care of with the snippet-driven library
constructor tests.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
17522c5ba1 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.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
5e62eafcc2 faketime: add -p option to wrapper for setting PID
I had to decide what to do if FAKE_PID wasn't defined during the
build. I decided that since the wrapper can't be sure it is preloading
the same library that it was built with (someone could somehow mix and
match the library and the wrapper tool), it should just warn and pass
along the value anyway.

This reserves the option space, but shouldn't annoy people too much if
they are running it on a system that doesn't have FAKE_PID enabled.

I note that this happens regardless of whether it is a "direct"
invocation or not.  I don't fully understand all the tradeoffs here,
so I would appreciate another set of eyes reviewing this choice.

Closes: #308
2021-02-25 19:37:38 -05:00
Daniel Kahn Gillmor
01f6bc76c9 clean up after syscall_test properly 2021-02-25 18:12:04 -05:00
Daniel Kahn Gillmor
f329eee8c5 Send test output to stdout, not stderr
debian autopkgtest instances (and maybe other test systems) will
report a failure if messages are sent to stderr.

Since these messages are diagnostic messages for the test suite, and
not indicators of actual failure, they should go to stdout, not
stderr.
2021-02-25 18:11:52 -05:00
Wolfgang Hommel
c89582fc1f divert syscall() to clock_gettime() (#176 #302) 2021-02-25 21:22:41 +01:00
Wolfgang Hommel
9a38e5d775 Merge pull request #305 from dkg/fix-shm
Use real_getpid instead of getpid in ft_shm_create() under FAKE_PID
2021-02-25 19:29:11 +01:00
Daniel Kahn Gillmor
7f4e5c378a Use real_getpid instead of getpid in ft_shm_create() under FAKE_PID
This addresses part of the concerns raised in #297
2021-02-25 10:50:57 -05:00
Wolfgang Hommel
9337bccfcb Merge pull request #304 from dkg/cover-getentropy
better testing for interception of randomness from the kernel, including getentropy()
2021-02-25 06:27:35 +01:00
Wolfgang Hommel
3668fd9b0f Merge pull request #302 from dkg/syscall-interception
Intercept syscall
2021-02-25 06:15:42 +01:00
Daniel Kahn Gillmor
3a81c6becd if FAKE_RANDOM is present, try to intercept getentropy as well.
Closes: #303
2021-02-24 16:38:15 -05:00
Daniel Kahn Gillmor
3db9d20828 Test getentropy
We want to ensure that tools that call getentropy() are also
controlled appropriately.
2021-02-24 16:03:57 -05:00
Daniel Kahn Gillmor
20e74b1b02 clean up randomtest.sh, make more flexible 2021-02-24 15:58:54 -05:00
Daniel Kahn Gillmor
00d6edf90c Test repeated invocations of getrandom()
A single program that invokes getrandom() repeatedly should end up
with the same stream of bytes, regardless of how it chunks up the
reading from the entropy source.

This test already passses.  I'm including it because it seems
like a useful confirmation.
2021-02-24 15:24:45 -05:00
Daniel Kahn Gillmor
811283e683 Intercept syscall
This is an attempt at an implementation to address #301.

Some things worth noting:

 - I am not particularly confident in my reverse of the variadic C
   ABI. While the code appears to work for me on x86_64, I could
   imagine some variations between platforms that I'm not
   understanding.

 - This works to intercept the invocation of syscall as seen in
   test/syscalltest.sh, as long as it was compiled with -DFAKE_RANDOM

 - defining -DINTERCEPT_SYSCALL on non-Linux platforms should result
   in a compile-time error.

 - This does *not* work to intercept the syscall sent by `openssl
   rand`, for some reason I don't yet understand.  Perhaps openssl has
   some platform-specific syscall mechanism that doesn't route them
   through libc's syscall() shim?
2021-02-24 14:45:38 -05:00
Wolfgang Hommel
a8283c646d Merge pull request #300 from dkg/improve-tests
Test getpid() against a library that invokes getpid() in its constructor
2021-02-24 17:54:30 +01:00
Daniel Kahn Gillmor
2ca0b719e3 test getpid() against library with constructor that calls it
This is an attempt to ensure that an external library invocation of
getpid doesn't trigger a crash (e.g. #295) or an infinite loop
(e.g. #297).
2021-02-24 11:15:31 -05:00
Daniel Kahn Gillmor
f6ddc32695 Genericize build rules for testing external libraries with constructor
This paves the way for testing other interceptions like getpid() with
shared objects that do devious things in their consturctors.
2021-02-24 11:15:01 -05:00
Daniel Kahn Gillmor
8de66f799f randomtest.sh requires librandom.so to be present
In some configurations, GNU make might treat librandom.so as an
ephemeral/intermediate build artifact and destroy it before
randomtest.sh is run.  This ensures the shared object is present when
needed.
2021-02-24 11:14:37 -05:00
Wolfgang Hommel
63fe6f0be5 Merge pull request #298 from dkg/fakepid
Enable intercepting getpid()
2021-02-24 13:53:45 +01:00
Wolfgang Hommel
062abac575 Merge pull request #299 from dkg/fix-getrandom
Ensure that real_getrandom is initialized properly
2021-02-24 06:34:46 +01:00
Daniel Kahn Gillmor
004222585e Enable intercepting getpid()
I went with the runtime environment variable being FAKETIME_FAKEPID
since it seems less likely to collide with anything else.

Closes: #297
2021-02-23 22:19:08 -05:00
Daniel Kahn Gillmor
9c59e24d33 Ensure that real_getrandom is initialized properly
This avoids potential failure if another library calls getrandom()
within its constructor before we are loaded.

For me, it lets "make randomtest" succeed in tests/

Closes: #295
2021-02-23 22:15:24 -05:00
Wolfgang Hommel
46dc625642 Merge pull request #296 from dkg/test-getrandom-library-init
test getrandom() in library initialization without FAKERANDOM_SEED
2021-02-23 22:08:43 +01:00
Daniel Kahn Gillmor
8f2c856d8e test getrandom() in library initialization without FAKERANDOM_SEED
Running "make randomtest" should demonstrates the segfault described
in https://github.com/wolfcw/libfaketime/issues/295
2021-02-23 11:14:37 -05:00
Wolfgang Hommel
b4a822cd6a Merge pull request #294 from dkg/improve-FAKE_RANDOM-tests
Improve tests for FAKE_RANDOM
2021-02-23 06:24:57 +01:00
Daniel Kahn Gillmor
54994ceb0d Improve tests for FAKE_RANDOM
Previously, we had failed to test code with getrandom() against
LD_PRELOAD when FAKERANDOM_SEED was unset.

We also want to try calling getrandom twice in a single process to
make sure that works OK.
2021-02-22 22:49:05 -05:00
47 changed files with 1336 additions and 468 deletions

View File

@@ -6,7 +6,7 @@ on:
- master
- develop
schedule:
- cron: '30 9 * * *'
- cron: '30 9 * * *'
jobs:
build:

8
.gitignore vendored
View File

@@ -2,9 +2,15 @@
*.so.1
timetest
test/getrandom_test
test/lib*.so
test/use_lib_*
test/run_*
test/repeat_random
test/getentropy_test
test/syscall_test
test/variadic_promotion
src/libfaketime.dylib.1
src/libfaketime.1.dylib
src/core
src/faketime

View File

@@ -16,6 +16,6 @@ script:
- if [ "$TRAVIS_ARCH" = ppc64le ]; then
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX -DFORCE_PTHREAD_NONVER" make;
else
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX" make;
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX" make;
fi
- make test

View File

@@ -2,6 +2,7 @@ INSTALL ?= install
UNAME=$(shell uname)
SELECTOR:=$(shell if test "${UNAME}" = "Darwin" ; then echo "-f Makefile.OSX" ; fi)
PREFIX ?= /usr/local
all:
$(MAKE) $(SELECTOR) -C src all

8
NEWS
View File

@@ -1,3 +1,11 @@
Since 0.9.9:
- improved macOS Monterey support through dyld interposing
- changed interception hooks for stat() and similar functions,
refactored to use a common handler (@sirainen)
- added support for timespec_get, timerfd_{get,set} (@sliquister)
- generic syscall() interception for selected syscalls (@dkg)
- improved testing system (@dkg)
Since 0.9.8:
- When compiled with the CFLAG FAKE_RANDOM set,
libfaketime will intercept calls to getrandom()

4
README
View File

@@ -1,5 +1,5 @@
libfaketime, version 0.9.9 (February 2021)
==========================================
libfaketime, version 0.9.10 (February 2022)
===========================================
Content of this file:

View File

@@ -6,7 +6,7 @@ all:
install:
$(INSTALL) -Dm0644 faketime.1 "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
gzip -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
gzip -nf "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
uninstall:
rm -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1.gz"

View File

@@ -1,4 +1,4 @@
.TH FAKETIME "1" "February 2021" "faketime 0.9.9" wolfcw
.TH FAKETIME "1" "February 2022" "faketime 0.9.10" wolfcw
.SH NAME
faketime \- manipulate the system time for a given command
.SH SYNOPSIS
@@ -7,11 +7,11 @@ faketime \- manipulate the system time for a given command
.SH DESCRIPTION
.\" \fIfaketime\fR will trick the given program into seeing the specified timestamp as its starting date and time.
.PP
The given command will be tricked into believing that the current system time is the one specified in the timestamp. Filesystem timestamps will also be
reported relative to this timestamp. The wall clock will continue to run from this date and time unless specified otherwise (see advanced options).
Actually, faketime is a simple wrapper for libfaketime, which uses the LD_PRELOAD mechanism to load a small library which intercepts system calls to
functions such as \fItime(2)\fR and \fIfstat(2)\fR. This wrapper exposes only a subset of libfaketime's functionality; please refer to the README file
that came with faketime for more details and advanced options, or have a look at http://github.com/wolfcw/libfaketime
The given command will be tricked into believing that the current system time is the one specified in the timestamp.
Filesystem timestamps will also be reported relative to this timestamp.
The wall clock will continue to run from this date and time unless specified otherwise (see advanced options).
Actually, faketime is a simple wrapper for libfaketime, which uses the LD_PRELOAD mechanism to load a small library which intercepts system calls to functions such as \fItime(2)\fR and \fIfstat(2)\fR.
This wrapper exposes only a subset of libfaketime's functionality; please refer to the README file that came with faketime for more details and advanced options, or have a look at https://github.com/wolfcw/libfaketime
.SH OPTIONS
.TP
\fB\-\-help\fR
@@ -23,11 +23,17 @@ show version information and quit.
\fB\-m\fR
use the multi-threading variant of libfaketime.
.TP
\fB\-p <PID>\fR
pretend that the program's process ID is PID. (only available if built with FAKE_PID)
.TP
\fB\-f\fR
use the advanced timestamp specification format.
.TP
\fB\--exclude-monotonic\fR
Do not fake time when the program makes a call to clock_gettime with a CLOCK_MONOTONIC clock.
.TP
\fB\--date-prog <PATH>\fR
Use a specific GNU-date compatible implementation of the helper used to transform "timestamp format" strings into programmatically usable dates, instead of a compile-time default guess for the generic target platform.
.SH EXAMPLES
.nf
@@ -41,41 +47,53 @@ In this single case all spawned processes will use the same global clock without
(Please note that it depends on your locale settings whether . or , has to be used for fractional offsets)
.fi
.SH ADVANCED TIMESTAMP FORMAT
The simple timestamp format used by default applies the \fB/bin/date -d\fR command to parse user-friendly specifications such as 'last friday'. When using
the faketime option \fB\-f\fR, the timestamp specified on the command line is directly passed to libfaketime, which enables a couple of additional features
such as speeding the clock up or slowing it down for the target program. It is strongly recommended that you have a look at the libfaketime documentation. Summary:
The simple timestamp format used by default applies the \fB/bin/date -d\fR command to parse user-friendly specifications such as 'last friday'.
When using the faketime option \fB\-f\fR, the timestamp specified on the command line is directly passed to libfaketime, which enables a couple of additional features such as speeding the clock up or slowing it down for the target program.
It is strongly recommended that you have a look at the libfaketime documentation.
Summary:
.TP
Freeze clock at absolute timestamp: \fB"YYYY-MM-DD hh:mm:ss"\fR
If you want to specify an absolute point in time, exactly this format must be used. Please note that freezing the clock is usually not what you want and may break the application. Only use if you know what you're doing!
If you want to specify an absolute point in time, exactly this format must be used.
Please note that freezing the clock is usually not what you want and may break the application.
Only use if you know what you're doing!
.TP
Relative time offset: \fB"[+/-]123[m/h/d/y]\fR, e.g. "+60m", "+2y"
This is the most often used format and specifies the faked time relatively to the current real time. The first character of the format string \fBmust\fR be a + or a -. The numeric value by default represents seconds, but the modifiers m, h, d, and y can be used to specify minutes, hours, days, or years, respectively. For example, "-2y" means "two years ago". Fractional time offsets can be used, e.g. "+2,5y", which means "two and a half years in the future". Please note that the fraction delimiter depends on your locale settings, so if "+2,5y" does not work, you might want to try "+2.5y".
Relative time offset: \fB"[+/-]123[m/h/d/y]"\fR, e.g., "+60m", "+2y"
This is the most often used format and specifies the faked time relatively to the current real time.
The first character of the format string \fBmust\fR be a + or a -.
The numeric value by default represents seconds, but the modifiers m, h, d, and y can be used to specify minutes, hours, days, or years, respectively.
For example, "-2y" means "two years ago". Fractional time offsets can be used, e.g., "+2,5y", which means "two and a half years in the future".
Please note that the fraction delimiter depends on your locale settings, so if "+2,5y" does not work, you might want to try "+2.5y".
.TP
Start-at timestamps: \fB"@YYYY-MM-DD hh:mm:ss"\fR
The wall clock will start counting at the given timestamp for the program. This can be used for specifying absolute timestamps without freezing the clock.
The wall clock will start counting at the given timestamp for the program.
This can be used for specifying absolute timestamps without freezing the clock.
.SH ADVANCED USAGE
When using relative time offsets or start-at timestamps (see ADVANCED TIMESTAMP FORMAT above and option \fB\-f\fR), the clock speed can be adjusted, i.e. time may run faster or slower for the executed program. For example, \fB"+5y x10"\fR will set the faked time 5 years into the future and make the time pass 10 times as fast (one real second equals 10 seconds measured by the program). Similarly, the flow of time can be slowed, e.g. using \fB"-7d x0,2"\fR, which will set the faked time 7 days in the past and set the clock speed to 20 percent, i.e. it takes five real world seconds for one second measured by the program. Again, depending on your locale, either "x2.0" or "x2,0" may be required regarding the delimiter. You can also make faketime to advance the reported time by a preset interval upon each time() call independently from the system's time using \fB"-7d i2,0"\fR, where
\fB"i"\fR is followed by the increase interval in seconds.
When using relative time offsets or start-at timestamps (see ADVANCED TIMESTAMP FORMAT above and option \fB\-f\fR), the clock speed can be adjusted, i.e., time may run faster or slower for the executed program.
For example, \fB"+5y x10"\fR will set the faked time 5 years into the future and make the time pass 10 times as fast (one real second equals 10 seconds measured by the program).
Similarly, the flow of time can be slowed, e.g., using \fB"-7d x0,2"\fR, which will set the faked time 7 days in the past and set the clock speed to 20 percent, i.e., it takes five real world seconds for one second measured by the program.
Again, depending on your locale, either "x2.0" or "x2,0" may be required regarding the delimiter.
You can also make faketime to advance the reported time by a preset interval upon each time() call independently from the system's time using \fB"-7d i2,0"\fR, where \fB"i"\fR is followed by the increase interval in seconds.
.PP
Faking times for multiple programs or even system-wide can be simplified by using ~/.faketimerc files and /etc/faketimerc. Please refer to the README that came with faketime for warnings and details.
Faking times for multiple programs or even system-wide can be simplified by using ~/.faketimerc files and /etc/faketimerc.
Please refer to the README that came with faketime for warnings and details.
.PP
Faking of filesystem timestamps may be disabled by setting the NO_FAKE_STAT environment variable to a non-empty value.
.SH AUTHOR
Please see the README and NEWS files for contributors.
.SH BUGS
Due to limitations of the LD_PRELOAD mechanism, faketime will not work with suidroot and statically linked programs.
While timestamps and time offsets will work for child processes, speeding the clock up or slowing it down might not
work for child processes spawned by the executed program as expected; a new instance of libfaketime is used for each
child process, which means that the libfaketime start time, which is used in speed adjustments, will also be
re-initialized. Some programs may dynamically load system libraries, such as librt, at run-time and therefore bypass libfaketime. You may report programs that do not work with libfaketime, but only if they are available as open source.
While timestamps and time offsets will work for child processes, speeding the clock up or slowing it down might not work for child processes spawned by the executed program as expected;
a new instance of libfaketime is used for each child process, which means that the libfaketime start time, which is used in speed adjustments, will also be re-initialized.
Some programs may dynamically load system libraries, such as librt, at run-time and therefore bypass libfaketime.
You may report programs that do not work with libfaketime, but only if they are available as open source.
.SH "REPORTING BUGS"
Please use https://github.com/wolfcw/libfaketime/issues
.SH COPYRIGHT
Copyright \(co 2003-2021 by the libfaketime authors.
.PP
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. You may redistribute copies of faketime under the
terms of the GNU General Public License.
There is NO warranty;
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
You may redistribute copies of faketime under the terms of the GNU General Public License.
.br
For more information about these matters, see the file named COPYING.
.SH "SEE ALSO"

View File

@@ -1,30 +1,10 @@
#
# Notes:
#
# * Compilation Defines:
# * Compilation Defines that are set by default:
#
# FAKE_STAT
# - Enables time faking also for files' timestamps.
#
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
# - Enables time faking for the utime* functions. If enabled via
# FAKE_UTIME define instead of FAKE_FILE_TIMESTAMPS, the faking
# defaults to off without FAKE_UTIME in the environment.
#
# NO_ATFILE
# - Disables support for the fstatat() group of functions
#
# PTHREAD_SINGLETHREADED_TIME
# - Define this if you want to single-thread time() ... there ARE
# possible caching side-effects in a multithreaded environment
# without this, but the performance impact may require you to
# try it unsynchronized.
#
# FAKE_INTERNAL_CALLS
# - Also intercept libc internal __functions, e.g. not just time(),
# but also __time(). Enhances compatibility with applications
# that make use of low-level system calls, such as Java Virtual
# Machines.
# - Enables time faking when reading files' timestamps.
#
# FAKE_SLEEP
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
@@ -35,12 +15,58 @@
# FAKE_PTHREAD
# - Intercept pthread_cond_timedwait
#
# FAKE_INTERNAL_CALLS
# - Also intercept libc internal __functions, e.g. not just time(),
# but also __time(). Enhances compatibility with applications
# that make use of low-level system calls, such as Java Virtual
# Machines.
#
# PTHREAD_SINGLETHREADED_TIME (only set in libfaketimeMT.so)
# - Define this if you want to single-thread time() ... there ARE
# possible caching side-effects in a multithreaded environment
# without this, but the performance impact may require you to
# try it unsynchronized.
#
# * Compilation Defines that are unset by default:
#
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
# - Enables time faking for the utime* functions. If enabled via
# FAKE_FILE_TIMESTAMPS, the faking is opt-in at runtime using
# with the FAKE_UTIME environment variable. If enabled via
# FAKE_UTIME, the faking is opt-out at runtime.
#
# NO_ATFILE
# - Disables support for the fstatat() group of functions
#
# FAKE_SETTIME
# - Intercept clock_settime(), settimeofday(), and adjtime()
#
# FAKE_RANDOM
# - Intercept getrandom()
#
# 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.
#
# - note that on unusual architectures, if INTERCEPT_SYSCALL is set, you may
# need to explicitly define variadic_promotion_t (e.g. by putting
# -Dvariadic_promotion_t=int into CFLAGS). See src/faketime_common.h for
# more info.
#
# FAKE_STATELESS
# - Remove support for any functionality that requires sharing state across
# threads of a process, or different processes. This decreases the risk of
# interference with a program's normal execution, at the cost of supporting
# fewer ways of specifying the time.
# Concretely, this currently:
# - disables PTHREAD_SINGLETHREADED_TIME, which can cause deadlocks in
# multithreaded programs that fork due to making clock_gettime not
# async-signal-safe
# - disables all shared-memory across processes
#
# FORCE_MONOTONIC_FIX
# - If the test program hangs forever on
# " pthread_cond_timedwait: CLOCK_MONOTONIC test
@@ -54,6 +80,10 @@
# ld automatically choose the correct library version to use for the
# target binary. Use for Linux platforms with Multi-Arch support only!
#
# SILENT
# - avoid that the faketime wrapper complains when running within a
# libfaketime environment
#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
#

View File

@@ -3,11 +3,31 @@
#
# * Compilation Defines:
#
# MACOS_DYLD_INTERPOSE
# - Use dlyd interposing instead of name-based function interception
# (required since macOS Monterey)
#
# FAKE_SLEEP
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
#
# FAKE_SETTIME
# - Intercept clock_settime(), settimeofday(), and adjtime()
#
# FAKE_PID
# - Enable faked values for getpid() calls through FAKETIME_FAKEPID
#
# FAKE_RANDOM
# - Intercept getentropy(). Dangerous for production use.
# See README about FAKE_RANDOM.
#
# FAKE_STAT
# - Enables time faking also for files' timestamps.
#
# NO_ATFILE
# - Disables support for the fstatat() group of functions
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
# - Enables time faking for the utime* functions. If enabled via
# FAKE_FILE_TIMESTAMPS, the faking is opt-in at runtime using
# with the FAKE_UTIME environment variable. If enabled via
# FAKE_UTIME, the faking is opt-out at runtime. Requires FAKE_STAT.
#
# PTHREAD
# - Define this to enable multithreading support.
@@ -18,9 +38,6 @@
# without this, but the performance impact may require you to
# try it unsynchronized.
#
# FAKE_SLEEP
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
#
@@ -38,8 +55,8 @@ INSTALL ?= install
PREFIX ?= /usr/local
CFLAGS += -DFAKE_SLEEP -DFAKE_INTERNAL_CALLS -DPREFIX='"'${PREFIX}'"' $(FAKETIME_COMPILE_CFLAGS)
LIB_LDFLAGS += -dynamiclib -current_version 0.9.9 -compatibility_version 0.7
CFLAGS += -DFAKE_SLEEP -DFAKE_INTERNAL_CALLS -DPREFIX='"'${PREFIX}'"' $(FAKETIME_COMPILE_CFLAGS) -DMACOS_DYLD_INTERPOSE -DFAKE_SETTIME
LIB_LDFLAGS += -dynamiclib -current_version 0.9.10 -compatibility_version 0.7
SONAME = 1
LIBS = libfaketime.${SONAME}.dylib

View File

@@ -1,7 +1,7 @@
/*
* libfaketime wrapper command
*
* This file is part of libfaketime, version 0.9.9
* This file is part of libfaketime, version 0.9.10
*
* libfaketime is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License v2 as published by the
@@ -48,9 +48,9 @@
#include "faketime_common.h"
const char version[] = "0.9.9";
const char version[] = "0.9.10";
#ifdef __APPLE__
#if (defined __APPLE__) || (defined __sun)
static const char *date_cmd = "gdate";
#else
static const char *date_cmd = "date";
@@ -75,6 +75,10 @@ void usage(const char *name)
" -m : Use the multi-threaded version of libfaketime\n"
" -f : Use the advanced timestamp specification format (see manpage)\n"
" --exclude-monotonic : Prevent monotonic clock from drifting (not the raw monotonic one)\n"
#ifdef FAKE_PID
" -p PID : Pretend that the program's process ID is PID\n"
#endif
" --date-prog PROG : Use specified GNU-compatible implementation of 'date' program\n"
"\n"
"Examples:\n"
"%s 'last friday 5 pm' /bin/date\n"
@@ -107,8 +111,16 @@ int main (int argc, char **argv)
int curr_opt = 1;
bool use_mt = false, use_direct = false;
long offset;
bool fake_pid = false;
const char *pid_val;
while(curr_opt < argc)
#ifndef SILENT
if (getenv("FAKETIME") || getenv("FAKETIME_SHARED") || getenv("FAKETIME_FAKEPID") || getenv("FAKERANDOM_SEED")) {
fprintf(stderr, "faketime: You appear to be running faketime within a libfaketime environment. Proceeding, but check for unexpected results...\n");
}
#endif
while (curr_opt < argc)
{
if (0 == strcmp(argv[curr_opt], "-m"))
{
@@ -116,6 +128,16 @@ int main (int argc, char **argv)
curr_opt++;
continue;
}
if (0 == strcmp(argv[curr_opt], "-p"))
{
fake_pid = true;
pid_val = argv[curr_opt + 1];
curr_opt += 2;
#ifndef FAKE_PID
fprintf(stderr, "faketime: -p argument probably won't work (try rebuilding with -DFAKE_PID)\n");
#endif
continue;
}
else if (0 == strcmp(argv[curr_opt], "-f"))
{
use_direct = true;
@@ -128,6 +150,20 @@ int main (int argc, char **argv)
curr_opt++;
continue;
}
else if (0 == strcmp(argv[curr_opt], "--date-prog"))
{
curr_opt++;
if (curr_opt > argc) {
// At best this avoids a segfault reading beyond the argv[]
// Realistically there would be other args (e.g. program to call)
fprintf(stderr, "faketime: --date-prog requires a further argument\n");
} else {
date_cmd = argv[curr_opt];
curr_opt++;
//fprintf(stderr, "faketime: --date-prog assigned: %s\n", date_cmd);
}
continue;
}
else if ((0 == strcmp(argv[curr_opt], "-v")) ||
(0 == strcmp(argv[curr_opt], "--version")))
{
@@ -169,6 +205,7 @@ int main (int argc, char **argv)
close(1); /* close normal stdout */
(void) (dup(pfds[1]) + 1); /* make stdout same as pfds[1] */
close(pfds[0]); /* we don't need this */
// fprintf(stderr, "faketime: using --date-prog: %s\n", date_cmd);
if (EXIT_SUCCESS != execlp(date_cmd, date_cmd, "-d", argv[curr_opt], "+%s",(char *) NULL))
{
perror("faketime: Running (g)date failed");
@@ -198,6 +235,8 @@ int main (int argc, char **argv)
/* simply pass format string along */
setenv("FAKETIME", argv[curr_opt], true);
}
if (fake_pid)
setenv("FAKETIME_FAKEPID", pid_val, true);
int keepalive_fds[2];
(void) (pipe(keepalive_fds) + 1);
@@ -345,6 +384,7 @@ int main (int argc, char **argv)
if (0 == (child_pid = fork()))
{
close(keepalive_fds[0]); /* only parent needs to read this */
// fprintf(stderr, "faketime: Executing: %s\n", argv[curr_opt]);
if (EXIT_SUCCESS != execvp(argv[curr_opt], &argv[curr_opt]))
{
perror("faketime: Running specified command failed");

View File

@@ -45,7 +45,7 @@ struct ft_shared_s
* When advancing time linearly with each time(), etc. call, the calls are
* counted here */
uint64_t ticks;
/* Index of timstamp to be loaded from file */
/* Index of timestamp to be loaded from file */
uint64_t file_idx;
/* System time Faketime started at */
struct system_time_s start_time;
@@ -58,4 +58,43 @@ struct ft_shared_s
#include <mach/mach_port.h>
#endif
/*
Variadic Argument Re-packing
Functions with variadic arguments typically have most arguments
passed on the stack, but it varies across ABIs.
C specifies that variadic arguments that are smaller than some
standard promotion size are promoted to "int or larger". If your
platform's ABI only promotes to "int" and not "long" (and "int" and
"long" differ on your platform), you should probably add
-Dvariadic_promotion_t=int to CFLAGS.
Note that some ABIs do not put all the variadic arguments on the
stack. For example, x86-64 puts float and double variadic
arguments into floating point registers, according to
https://www.uclibc.org/docs/psABI-x86_64.pdf
The only variadic function faketime cares about intercepting is
syscall. But we don't believe that any syscalls expect float or
double arguments, so we hope all the rest will be on the stack.
tests/variadic/ attempts to confirm this if you are compiling
with -DINTERCEPT_SYSCALL.
If libc were capable of exposing a variadic form of syscall, we
could depend on that and drop this approach, which would be
preferable: https://sourceware.org/bugzilla/show_bug.cgi?id=27508
*/
#ifndef variadic_promotion_t
#define variadic_promotion_t long
#endif
/*
The Linux kernel appears to have baked-in 6 as the maximum number
of arguments for a syscall beyond the syscall number itself.
*/
#ifndef syscall_max_args
#define syscall_max_args 6
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -9,4 +9,4 @@
#define htole64(x) LE_64(x)
#define le64toh(x) LE_64(x)
#endif /* SUN_OS_ENDIAN_H */
#endif /* SUN_OS_ENDIAN_H */

View File

@@ -61,7 +61,7 @@
do \
{ \
int64_t tmp_time; \
tmp_time = (c) * (int64_t) ((tvp)->tv_sec * SEC_TO_##prefix##SEC + \
tmp_time = (c) * (int64_t) ((int64_t) (tvp)->tv_sec * SEC_TO_##prefix##SEC + \
(int64_t) (tvp)->tv_##prefix##sec); \
(result)->tv_##prefix##sec = tmp_time % SEC_TO_##prefix##SEC; \
(result)->tv_sec = (tmp_time - (result)->tv_##prefix##sec) / \

View File

@@ -1,12 +1,21 @@
CC = gcc
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra $(FAKETIME_COMPILE_CFLAGS)
LDFLAGS = -lrt -lpthread
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra $(FAKETIME_COMPILE_CFLAGS)
LDFLAGS += -lrt -lpthread
SRC = timetest.c
OBJ = ${SRC:.c=.o}
all: timetest test
TEST_SNIPPETS = $(notdir $(basename $(wildcard snippets/*.c)))
EXPECTATIONS= $(notdir $(basename $(wildcard snippets/*.variable)))
ALL_TESTS = timetest test
ifneq ($(filter -DINTERCEPT_SYSCALL,${CFLAGS}),)
ALL_TESTS += confirm_variadic_promotion
endif
all: $(ALL_TESTS)
.c.o:
${CC} -c ${CFLAGS} $<
@@ -22,16 +31,48 @@ test: timetest functest
functest:
./testframe.sh functests
getrandom_test: getrandom_test.c
%_test: %_test.c
${CC} -o $@ ${CFLAGS} $<
randomtest: getrandom_test
randomtest: repeat_random
./randomtest.sh
# ensure our variadic argument unpacking/repacking works as expected
confirm_variadic_promotion: variadic_promotion
./variadic_promotion
variadic_promotion: variadic/main.o variadic/outer.o variadic/inner.o
${CC} -o $@ ${CFLAGS} $^
variadic/%.o: variadic/%.c
${CC} -c -o $@ ${CFLAGS} $<
# run snippet tests
snippets: test_variable_data test_library_constructors
## test snippet behavior across env var setting over time:
test_variable_data: test_variable_data.sh $(foreach f,${EXPECTATIONS},run_${f})
./test_variable_data.sh ${EXPECTATIONS}
run_%: _run_test.c snippets/%.c
sed s/SNIPPET_NAME/$*/g < _run_test.c | ${CC} -o $@ ${CFLAGS} -x c -
## test snippets in other library constructors:
test_library_constructors: $(foreach f,${TEST_SNIPPETS},test_lib_${f})
test_lib_%: test_constructors.sh use_lib_% lib%.so
./test_constructors.sh $*
lib%.so: _libtest.c snippets/%.c
sed s/SNIPPET_NAME/$*/g < _libtest.c | ${CC} -shared -o $@ -fpic ${CFLAGS} -x c -
use_lib_%: _use_lib_test.c snippets/%.c lib%.so
sed s/SNIPPET_NAME/$*/g < _use_lib_test.c | ${CC} -L. -o $@ ${CFLAGS} -x c - -l$*
## cleanup and metainformation
clean:
@rm -f ${OBJ} timetest getrandom_test
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o
distclean: clean
@echo
.PHONY: all test clean distclean
.PHONY: all test clean distclean randomtest snippets test_variable_data test_library_constructors

8
test/_libtest.c Normal file
View File

@@ -0,0 +1,8 @@
#include "snippets/include_headers.h"
#define where "libSNIPPET_NAME"
void SNIPPET_NAME_as_needed() {
printf(" called SNIPPET_NAME_as_needed() \n");
}
static __attribute__((constructor)) void init_SNIPPET_NAME() {
#include "snippets/SNIPPET_NAME.c"
}

5
test/_run_test.c Normal file
View File

@@ -0,0 +1,5 @@
#include "snippets/include_headers.h"
#define where "run_SNIPPET_NAME"
int main() {
#include "snippets/SNIPPET_NAME.c"
}

7
test/_use_lib_test.c Normal file
View File

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

View File

@@ -1,25 +0,0 @@
#include <stdio.h>
#include <sys/random.h>
#include <stdlib.h>
int main() {
char *buf = calloc(100, 1);
size_t buflen = 100;
unsigned flags = GRND_NONBLOCK;
fprintf(stdout, "Before getrandom:\n");
for (size_t i=0; i < buflen; i++) { fprintf(stdout, "%hhu ", buf[i]); }
fprintf(stdout, "\n");
int result = getrandom(buf, buflen, flags);
fprintf(stdout, "getrandom() result: %d\n", result);
if (result == -1) perror("getrandom() unsuccessful");
fprintf(stdout, "After getrandom:\n");
for (size_t i=0; i < buflen; i++) { fprintf(stdout, "%hhu ", buf[i]); }
fprintf(stdout, "\n");
free(buf);
return 0;
}

View File

@@ -2,27 +2,17 @@
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
set -e
error=0
./getrandom_test > run0
FAKERANDOM_SEED=0x12345678DEADBEEF LD_PRELOAD="$FTPL" ./getrandom_test > run1
FAKERANDOM_SEED=0x12345678DEADBEEF LD_PRELOAD="$FTPL" ./getrandom_test > run2
FAKERANDOM_SEED=0x0000000000000000 LD_PRELOAD="$FTPL" ./getrandom_test > run3
repeat3x5="$(FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./repeat_random 3 5)"
repeat5x3="$(FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./repeat_random 5 3)"
if diff -u run0 run1 > /dev/null; then
if [ "$repeat3x5" != "$repeat5x3" ]; then
error=1
printf >&2 'test run without a seed produced the same data as a run with a seed!\n'
printf >&2 '5 calls of getrandom(3) got %s\n3 calls of getrandom(5) got %s\n' "$repeat3x5" "$repeat5x3"
fi
if ! diff -u run1 run2; then
error=2
printf >&2 'test runs with identical seeds differed!\n'
fi
if diff -u run2 run3 >/dev/null; then
error=3
printf >&2 'test runs with different seeds produced the same data!\n'
fi
rm -f run0 run1 run2 run3
if [ 0 = $error ]; then
printf 'getrandom interception test successful.\n'

40
test/repeat_random.c Normal file
View File

@@ -0,0 +1,40 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/random.h>
void usage(const char* name) {
fprintf(stderr,
"Usage: %s REPS SIZE\n\n"
"Gather and print REPS blocks of SIZE bytes from getrandom()\n",
name);
}
int main(int argc, const char **argv) {
int reps, size;
unsigned char *buf;
if (argc != 3) {
usage(argv[0]);
return 1;
}
reps = atoi(argv[1]);
size = atoi(argv[2]);
buf = malloc(size);
if (!buf) {
fprintf(stderr, "failure to allocate buffer of size %d\n", size);
return 1;
}
for (int i = 0; i < reps; i++) {
ssize_t resp = getrandom(buf, size, 0);
if (resp != size) {
fprintf(stderr, "tried to get %d bytes, got %zd\n", size, resp);
free(buf);
return 2;
}
for (int j = 0; j < size; j++) {
printf("%02x", buf[j]);
}
}
free(buf);
printf("\n");
return 0;
};

72
test/snippets/README Normal file
View File

@@ -0,0 +1,72 @@
Testing Interception with Snippets
==================================
Faketime intercepts some C library functions and system calls. We
want to make it easier to apply certain generic tests across many
different functions. We do that with snippets of C, which each can be
applied in multiple testing frameworks.
Most snippets are just a minimalist invocation of a single function or
syscall that is likely to be intercepted by libfaketime, though it's
possible to test more complex snippets too.
Including a New Snippet
-----------------------
To cover a new bit of intercepted functionality, supply a C snippet in
this directory named `FOO.c` (the name FOO should conform to C
function names -- letters, numbers, and underscores; if you're testing
interception of a single function, the simplest thing is to name
snippet file after the intercepted function name).
This file should contain a small bit of code that exercises the
functionality in question. It should be self-contained, and it should
produce some kind of description of what happened to stdout. The data
sent to stdout should include the const char* "where" value (which is
an indication of which test framework is using the snippet). Take a
look at getpid.c for a simple example.
If the snippet needs additional #include headers, please add them
in `include_headers.h`. These #includes will be used by every snippet,
so try to keep it minimal.
Snippet Testing Frameworks
--------------------------
We have the following frameworks that use the snippets:
### Variable Data
Most functionality intercepted by libfaketime will normally produce
variant output when invoked multiple times across the span of a few
seconds by different processes. But if `FAKETIME` (or an analogous
variable like `FAKERANDOM_SEED`) is set, the output data should remain
constant.
If this describes the functionality in a new snippet `FOO.c`, please
also drop a single-line file `FOO.variable` in this directory, where
the first word of the line is the variable that should hold the output
constant, and the rest of the line is the value of that variable.
See the `test_variable_data` target in `test/Makefile` for how this is
implemented.
### Library Constructors
Library constructor routines are run by ld.so before the main process
is launched. If the LD_PRELOADed libfaketime is masking a symbol from
libc, and another library has a constructor routine that invokes that
symbol, it might get called before libfaketime has had a chance to
initialize its followup pointers to the actual libc functionality.
This framework is applied automatically to all snippets.
See the `test_library_constructors` target in `test/Makefile` for how
this is implemented.
Adding a New Framework
----------------------
If you want to add a new framework that tests across all snippets,
implement it in a few lines of `test/Makefile` and document it in the
section above.

View File

@@ -0,0 +1,8 @@
struct timespec ts;
clockid_t ckid = CLOCK_REALTIME;
int ret = clock_gettime(ckid, &ts);
if (ret == 0) {
printf("[%s] clock_gettime(CLOCK_REALTIME[%d], &ts) -> {%lld, %ld}\n", where, ckid, (long long)ts.tv_sec, ts.tv_nsec);
} else {
printf("[%s] clock_gettime(CLOCK_REALTIME[%d], &ts) returned non-zero (%d), errno = %d (%s)\n", where, ckid, ret, errno, strerror(errno));
}

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

View File

@@ -0,0 +1,8 @@
struct timespec *ts = malloc(sizeof(struct timespec));
clockid_t ckid = CLOCK_REALTIME;
int ret = clock_gettime(ckid, ts);
if (ret == 0) {
printf("[%s] clock_gettime_heap(CLOCK_REALTIME[%d], ts) -> {%lld, %ld}\n", where, ckid, (long long)ts->tv_sec, ts->tv_nsec);
} else {
printf("[%s] clock_gettime_heap(CLOCK_REALTIME[%d], ts) returned non-zero (%d), errno = %d (%s)\n", where, ckid, ret, errno, strerror(errno));
}

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

View File

@@ -0,0 +1,6 @@
unsigned int targ;
if (getentropy(&targ, sizeof(targ)) == 0) {
printf("[%s] getentropy() yielded 0x%08x\n", where, targ);
} else {
printf("[%s] getentropy() failed with %d (%s)\n", where, errno, strerror(errno));
}

View File

@@ -0,0 +1 @@
FAKERANDOM_SEED 0x0123456789ABCDEF

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 @@
FAKETIME_FAKEPID 1

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 @@
FAKERANDOM_SEED 0xDEADBEEFDEADBEEF

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/random.h>
#include <sys/syscall.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>

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

@@ -0,0 +1,2 @@
long uid = syscall(__NR_getuid);
printf("[%s] syscall(__NR_getuid) -> %ld\n", where, uid);

View File

@@ -0,0 +1,8 @@
struct timespec ts;
clockid_t ckid = CLOCK_REALTIME;
long ret = syscall(__NR_clock_gettime, ckid, &ts);
if (ret == 0)
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], &ts) -> {%lld, %ld}\n", where, ckid, (long long)ts.tv_sec, ts.tv_nsec);
else
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], &ts) returned non-zero (%ld)\n", where, ckid, ret);

View File

@@ -0,0 +1 @@
FAKETIME 2020-01-01 00:00:00

View File

@@ -0,0 +1,8 @@
struct timespec *ts = malloc(sizeof(struct timespec));
clockid_t ckid = CLOCK_REALTIME;
long ret = syscall(__NR_clock_gettime, ckid, ts);
if (ret == 0)
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], ts) -> {%lld, %ld}\n", where, ckid, (long long)ts->tv_sec, ts->tv_nsec);
else
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], ts) returned non-zero (%ld)\n", where, ckid, ret);

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

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

@@ -0,0 +1,2 @@
time_t t = time(NULL);
printf("[%s] time() yielded %zd\n", where, t);

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

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"

54
test/test_variable_data.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
set -e
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
DELAY="${DELAY:-2}"
declare -A firstunset first second delayed delayedunset
err=0
for func in "$@"; do
if ! [ -x "./run_$func" ]; then
printf >&2 '%s does not exist, failing\n' "./run_$func"
exit 1
fi
read varname value < "snippets/$func.variable"
unset $varname
firstunset[$func]="$(env LD_PRELOAD="$FTPL" "./run_$func")"
first[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
second[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
if [ "${first[$func]}" != "${second[$func]}" ]; then
printf >&2 '[%s] Set %s="%s", but got two different outputs:\n - %s\n - %s\n' "$func" "$varname" "$value" "${first[$func]}" "${second[$func]}"
err=$(( $err + 1 ))
fi
if [ "${first[$func]}" == "${firstunset[$func]}" ]; then
printf >&2 '[%s] Same answer when %s="%s" and when unset:\n - set: %s\n - unset: %s\n' "$func" "$varname" "$value" "${first[$func]}" "${firstunset[$func]}"
err=$(( $err + 1 ))
fi
done
printf "Sleeping %d seconds..." "$DELAY"
sleep "$DELAY"
printf 'done\n'
for func in "$@"; do
read varname value < "snippets/$func.variable"
unset $varname
delayed[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
delayedunset[$func]="$(LD_PRELOAD="$FTPL" "./run_$func")"
if [ "${first[$func]}" != "${delayed[$func]}" ]; then
printf >&2 '[%s] Vary across delay of %d seconds (%s="%s"):\n - before: %s\n - after: %s\n' "$func" "$DELAY" "$varname" "$value" "${first[$func]}" "${delayed[$func]}"
err=$(( $err + 1 ))
fi
if [ "${firstunset[$func]}" == "${delayedunset[$func]}" ]; then
printf >&2 '[%s] Same answer when unset across delay of %d seconds:\n - before: %s\n - after: %s\n' "$func" "$DELAY" "${firstunset[$func]}" "${delayedunset[$func]}"
err=$(( $err + 1 ))
fi
done
if [ "$err" -gt 0 ]; then
printf >&2 'Got %d errors, failing\n' "$err"
exit 1
fi
exit 0

View File

@@ -83,6 +83,7 @@ void* pthread_test(void* args)
if (rt != ETIMEDOUT)
{
printf("pthread_cond_timedwait failed\n");
pthread_mutex_unlock(&fakeMutex);
exit(EXIT_FAILURE);
}
pthread_mutex_unlock(&fakeMutex);
@@ -105,6 +106,7 @@ void* pthread_test(void* args)
if (rt != ETIMEDOUT)
{
printf("pthread_cond_timedwait failed\n");
pthread_mutex_unlock(&fakeMutex);
exit(EXIT_FAILURE);
}
pthread_mutex_unlock(&fakeMutex);

46
test/variadic/inner.c Normal file
View File

@@ -0,0 +1,46 @@
#include <stdio.h>
#include <wchar.h>
#include <stdarg.h>
#include <stddef.h>
/* round 0: c, s, wc, i, wi */
long inner0(char *out, ...) {
char c = 0;
short s = 0;
wchar_t wc = 0;
int i = 0;
wint_t wi = 0;
va_list ap;
va_start(ap, out);
c = va_arg(ap, int);
s = va_arg(ap, int);
wc = va_arg(ap, typeof(wc));
i = va_arg(ap, typeof(i));
wi = va_arg(ap, typeof(wi));
va_end(ap);
int ret = sprintf(out, "c: 0x%x s: 0x%x wc: 0x%lx i: 0x%x wi: 0x%x\n", c, s, (long)wc, i, wi);
return ret;
}
/* round 1: l, ll, ptr, pd, sz */
long inner1(char *out, ...) {
long l = 0;
long long ll = 0;
void *ptr = NULL;
ptrdiff_t pd = 0;
size_t sz = 0;
va_list ap;
va_start(ap, out);
l = va_arg(ap, typeof(l));
ll = va_arg(ap, typeof(ll));
ptr = va_arg(ap, typeof(ptr));
pd = va_arg(ap, typeof(pd));
sz = va_arg(ap, typeof(sz));
va_end(ap);
int ret = sprintf(out, "l: 0x%lx ll: 0x%llx ptr: %p pd: 0x%tx sz: 0x%zx\n", l, ll, ptr, pd, sz);
return ret;
}

70
test/variadic/main.c Normal file
View File

@@ -0,0 +1,70 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <wchar.h>
extern long outer(long num, char *out, ...);
extern long inner0(char *out, ...);
extern long inner1(char *out, ...);
#define bufsize 2048
static int compare_buffers(int round,
long ret_outer, long ret_inner,
const char* outer, const char* inner) {
int ret = 0;
if (ret_outer != ret_inner) {
printf("Round %d: return values differ (outer: %ld inner: %ld)\n", round, ret_outer, ret_inner);
ret++;
}
if (memcmp(outer, inner, bufsize)) {
printf("Round %d strings differ:\n - outer: %s\n - inner: %s\n", round, outer, inner);
ret++;
}
if (ret == 0)
printf("Round %d success: %s\n", round, outer);
return ret;
}
int main() {
/* sizes of intrinsic types as reported by echo | cpp -dM | grep
SIZEOF, pruned to avoid floating point types. Should work with
both clang and gcc, not sure about other C preprocessors.
Note that we set bits in every high octet and every low octet to
see that they end up in the right spot.
*/
char c = 0x03L;
short s = (0x04L << ((__SIZEOF_SHORT__ - 1) * 8)) + 0xff;
wchar_t wc = (0x05L << ((__SIZEOF_WCHAR_T__ - 1) * 8)) + 0xfe;
int i = (0x06L << ((__SIZEOF_INT__ - 1) * 8)) + 0xfd;
wint_t wi = (0x07L << ((__SIZEOF_WINT_T__ - 1) * 8)) + 0xfc;
long l = (0x08L << ((__SIZEOF_LONG__ - 1) * 8) ) + 0xfb;
long long ll = (0x09LL << ((__SIZEOF_LONG_LONG__ - 1) * 8)) + 0xfa;
void *ptr = (void*)((0x0aL << ((__SIZEOF_POINTER__ - 1) * 8)) + 0xf9);
ptrdiff_t pd = (0x0bL << ((__SIZEOF_PTRDIFF_T__ -1) * 8)) + 0xf9;
size_t sz = (0x0cL << ((__SIZEOF_SIZE_T__ - 1) * 8)) + 0xf8;
char *buf[2];
for (int j = 0; j < 2; j++)
buf[j] = malloc(bufsize);
int ret[2];
int errors = 0;
#define reset_buffers(n) for (int j = 0; j < 2; j++) memset(buf[j], n, bufsize)
#define check_buffers(n) errors += compare_buffers(n, ret[0], ret[1], buf[0], buf[1])
reset_buffers(0);
ret[0] = outer(0, buf[0], c, s, wc, i, wi);
ret[1] = inner0(buf[1], c, s, wc, i, wi);
check_buffers(0);
reset_buffers(1);
ret[0] = outer(1, buf[0], l, ll, ptr, pd, sz);
ret[1] = inner1(buf[1], l, ll, ptr, pd, sz);
check_buffers(1);
return (int)errors;
}

21
test/variadic/outer.c Normal file
View File

@@ -0,0 +1,21 @@
#include <stdarg.h>
#include <time.h>
#include "../../src/faketime_common.h"
extern long inner0(char *out, ...);
extern long inner1(char *out, ...);
long outer(long num, char *out, ...) {
va_list ap;
va_start(ap, out);
variadic_promotion_t a[syscall_max_args];
for (int i = 0; i < syscall_max_args; i++)
a[i] = va_arg(ap, variadic_promotion_t);
va_end(ap);
if (num == 0)
return inner0(out, a[0], a[1], a[2], a[3], a[4], a[5]);
if (num == 1)
return inner1(out, a[0], a[1], a[2], a[3], a[4], a[5]);
else return -1;
}