Added new feature to limit libfaketime activity

These changes add a new feature that can be used to limit
libfaketime's activity period, and prepares for the upcoming
0.9 release.
Four new environment variables can optionally be set:
FAKETIME_START_AFTER_SECONDS, FAKETIME_STOP_AFTER_SECONDS,
FAKETIME_START_AFTER_NUMCALLS, and FAKETIME_START_AFTER_NUMCALLS.
libfaketime will only return faked timestamps if the program's
runtime is between FAKETIME_START_AFTER_SECONDS and
FAKETIME_STOP_AFTER_SECONDS seconds. For example, a program
may be started with the real current time, and after 60
seconds, it will start to receive faked timestamps, e.g.,
one year in the future. The other pair of environment
variables limits libfaketime's activity based on the number
of time-related system calls of the started program,
instead of its run-time in seconds.
Using this new feature will break applications that cannot
handle larger sudden changes in timestamps, so use it with
care.
This commit is contained in:
Wolfgang Hommel
2012-01-08 22:41:54 +01:00
parent e72d8e0419
commit 837e2c7e62
5 changed files with 141 additions and 10 deletions

9
NEWS
View File

@@ -1,3 +1,12 @@
Since 0.8.2:
- Added support for "limited faking".
You can optionally specify when libfaketime starts to fake the
returned timestamps and when it shall stop doing so. For example,
a program can be started regularly, and after 5 minutes run-time
it will be sent two years into the future. Those limiting
start and stop times can be specified in seconds or as the
number of any time-related function calls within the program.
Since 0.8.1:
- Added a MacOS port.
Thanks to Derrick Brashear!

73
README
View File

@@ -1,6 +1,6 @@
==================================================
FakeTime Preload Library, version 0.8.1 (May 2011)
==================================================
=====================================================
FakeTime Preload Library, version 0.9 (Fabruary 2011)
=====================================================
Content of this file:
@@ -17,6 +17,7 @@ Content of this file:
e) Advanced features and caveats
f) Faking the date and time system-wide
g) Using the "faketime" wrapper script
h) "Limiting" libfaketime
5. License
6. Contact
@@ -318,6 +319,72 @@ faketime '2008-12-24 08:15:42' /bin/date
Thanks to Daniel Kahn Gillmor for providing these suggestions!
4h) "Limiting" libfaketime
--------------------------
Starting with version 0.9, libfaketime can be configured to not be continuously
active, but only during a certain time interval.
For example, you might want to start a program with the real current time, but
after 5 minutes of usage, you might want it to see a faked time, e.g., a year
in the future.
Dynamic changes to the faked time are alternatively possible by
- changing the FAKETIME environment variable at run-time; this is the preferred
way if you use libfaketime for debugging and testing as a programmer, as it
gives you the most direct control of libfaketime without any performance
penalities.
- not using the FAKETIME environment variable, but specifying the fake time in a
file (such as ~/.faketimerc). You can change the content of this file at
run-time. This works best with caching disabled (see Makefile), but comes at a
performance cost because this file has to be read and evaluated each time.
The feature described here works based on two pairs of environment variables,
FAKETIME_START_AFTER_SECONDS and FAKETIME_STOP_AFTER_SECONDS, and
FAKETIME_START_AFTER_NUMCALLS and FAKETIME_STOP_AFTER_NUMCALLS
The default value for each of these environment variables is -1, which means
"ignore this value".
If you want libfaketime to be only active during the run-time minutes 2 to 5
of your application, you would set
FAKETIME_START_AFTER_SECONDS=60
FAKETIME_STOP_AFTER_SECONDS=300
This means that your application will work with the real time from start (second
0) up to second 60. It will then see a faked time from run-time seconds 60 to
300 (minutes 2, 3, 4, and 5). After run-time second 600, it will again see the
real (not-faked) time.
This approach is not as flexible as changing the FAKETIME environment variable
during runtime, but may be easier to use, works on a per-program (and not a
per-user or system-wide) scope, and has only a minor performance overhead.
Using the other pair of environment variables, you can limit the activity time
of libfaketime not based on wall-clock seconds, but on the number of
time-related function calls the started program performs. This alternative is
probably only suitable for programmers who either know the code of the program
in order to determine useful start/stop values or want to perform fuzzing
tests.
Both pairs of environment variables can be combined to further restrict
libfaketime activity, although this is only useful in very few scenarios.
Limiting libfaketime activity in this way is not recommended in general. Many
programs will break when they are subject to sudden changes in time, especially
if they are started using the current (real) time and are then sent back into
the past after, e.g., 5 minutes. For example, they may appear to be frozen or
stuck because they are waiting until a certain point in time that, however, is
never reached due to the delayed libfaketime activity. Avoid using this
functionality unless you are sure you really need it and know what you are
doing.
5. License
----------

View File

@@ -30,6 +30,9 @@
# frequently. Disabling the cache may negatively influence the
# performance.
#
# LIMITEDFAKING
# - Support environment variables that limit time faking to certain
# time intervals or number of function calls.
#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
@@ -45,7 +48,7 @@ INSTALL = install
PREFIX = /usr/local
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -DFAKE_INTERNAL_CALLS -fPIC -DPOSIX_REALTIME
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -DFAKE_INTERNAL_CALLS -fPIC -DPOSIX_REALTIME -DLIMITEDFAKING
LDFLAGS += -shared -ldl -lm -lpthread
SRC = faketime.c

View File

@@ -30,6 +30,10 @@
# frequently. Disabling the cache may negatively influence the
# performance.
#
# LIMITEDFAKING
# - Support environment variables that limit time faking to certain
# time intervals or number of function calls.
#
#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
@@ -51,7 +55,7 @@ PREFIX = /usr/local
# 10.5
#CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch ppc
# 10.6
CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch x86_64
CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch x86_64 -DLIMITEDFAKING
SRC = faketime.c

View File

@@ -457,6 +457,7 @@ static time_t _ftpl_time(time_t *time_tptr) {
/* initialize our result with the real current time */
result = (*real_time)(time_tptr);
#endif
return result;
}
@@ -628,6 +629,17 @@ time_t fake_time(time_t *time_tptr) {
static time_t last_data_fetch = 0; /* not fetched previously at first call */
static int cache_expired = 1; /* considered expired at first call */
static int cache_duration = 10; /* cache fake time input for 10 seconds */
#ifdef LIMITEDFAKING
static long callcounter = 0;
static int limited_initialized = 0;
char envvarbuf[32];
static long FAKETIME_START_AFTER_SECONDS = -1;
static long FAKETIME_STOP_AFTER_SECONDS = -1;
static long FAKETIME_START_AFTER_NUMCALLS = -1;
static long FAKETIME_STOP_AFTER_NUMCALLS = -1;
#endif
/*
* This no longer appears to be necessary in Mac OS X 10.7 Lion
*/
@@ -644,13 +656,49 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
/* Sanity check by Karl Chan since v0.8 */
if (time_tptr == NULL) return -1;
#ifdef LIMITEDFAKING
/* Check whether we actually should be faking the returned timestamp. */
if (ftpl_starttime > 0) {
if (limited_initialized == 0) {
if (getenv("FAKETIME_START_AFTER_SECONDS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_START_AFTER_SECONDS"), 30);
FAKETIME_START_AFTER_SECONDS = atol(envvarbuf);
}
if (getenv("FAKETIME_STOP_AFTER_SECONDS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_STOP_AFTER_SECONDS"), 30);
FAKETIME_STOP_AFTER_SECONDS = atol(envvarbuf);
}
if (getenv("FAKETIME_START_AFTER_NUMCALLS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_START_AFTER_NUMCALLS"), 30);
FAKETIME_START_AFTER_NUMCALLS = atol(envvarbuf);
}
if (getenv("FAKETIME_STOP_AFTER_NUMCALLS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_STOP_AFTER_NUMCALLS"), 30);
FAKETIME_STOP_AFTER_NUMCALLS = atol(envvarbuf);
}
limited_initialized = 1;
}
if ((callcounter + 1) >= callcounter) callcounter++;
/* For debugging, output #seconds and #calls */
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
if ((FAKETIME_START_AFTER_SECONDS != -1) && ((*time_tptr - ftpl_starttime) < FAKETIME_START_AFTER_SECONDS)) return *time_tptr;
if ((FAKETIME_STOP_AFTER_SECONDS != -1) && ((*time_tptr - ftpl_starttime) >= FAKETIME_STOP_AFTER_SECONDS)) return *time_tptr;
if ((FAKETIME_START_AFTER_NUMCALLS != -1) && (callcounter < FAKETIME_START_AFTER_NUMCALLS)) return *time_tptr;
if ((FAKETIME_STOP_AFTER_NUMCALLS != -1) && (callcounter >= FAKETIME_STOP_AFTER_NUMCALLS)) return *time_tptr;
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
}
#endif
if (last_data_fetch > 0) {
if ((*time_tptr - last_data_fetch) > cache_duration) {
cache_expired = 1;
}
if ((*time_tptr - last_data_fetch) > cache_duration) {
cache_expired = 1;
}
else {
cache_expired = 0;
}
cache_expired = 0;
}
}
#ifdef NO_CACHING