wolfcw / libfaketime

libfaketime modifies the system time for a single application
https://github.com/wolfcw/libfaketime
GNU General Public License v2.0
2.62k stars 319 forks source link

libfaketime hangs forever when 32-bit process is executed within 64-bit process #427

Open robbert-ef opened 1 year ago

robbert-ef commented 1 year ago

libfaketime seems to hang forever when a 32-bit process is started when libfaketime is available for 64 and 32-bit

Tested using 0.9.10

steps to reproduce:

1: build libfaketime for both 32 and 64-bit

make clean
CFLAGS="-m32" LDFLAGS="-m32" make
mv src/libfaketime.so.1 /lib/libfaketime.so
make clean
make
mv src/libfaketime.so.1 /lib64/libfaketime.so

2: build 32-bit example

test.c

#include <stdio.h>
int main() {
   printf("Hello, World!");
   return 0;
}

compile:

gcc -m32 test.c -o test

3: run

starting the 32-bit process:

LD_PRELOAD=libfaketime.so FAKETIME=+60d ./test
Hello, World!

when trying to start from within a 64-bit process, it hangs forever:

LD_PRELOAD=libfaketime.so FAKETIME=+60d bash -c ./test

output from gdb, attached to the 32-bit process:

(gdb) bt
#0  0xf7f03549 in __kernel_vsyscall ()
#1  0xf7d07b3c in do_futex_wait.constprop () from /lib/libpthread.so.0
#2  0xf7d07c27 in __new_sem_wait_slow.constprop.1 () from /lib/libpthread.so.0
#3  0xf7ee90e4 in ftpl_init () from /lib/libfaketime.so
#4  0xf7f14fce in _dl_init_internal () from /lib/ld-linux.so.2
#5  0xf7f0618f in _dl_start_user () from /lib/ld-linux.so.2

output from strace:

statfs("/dev/shm", {f_type=TMPFS_MAGIC, f_bsize=4096, f_blocks=16384, f_bfree=16360, f_bavail=16360, f_files=1018431, f_ffree=1018406, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_NOSUID|ST_NODEV|ST_NOEXEC|ST_RELATIME}) = 0
futex(0xf7d4e1a8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
open("/dev/shm/sem.faketime_sem_19240", O_RDWR|O_NOFOLLOW) = 3
fstat64(3, {st_mode=S_IFREG|0600, st_size=32, ...}) = 0
mmap2(NULL, 16, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xf7f36000
close(3)                                = 0
munmap(0xf7f36000, 16)                  = 0
open("/dev/shm/sem.faketime_sem_19240", O_RDWR|O_NOFOLLOW) = 3
fstat64(3, {st_mode=S_IFREG|0600, st_size=32, ...}) = 0
mmap2(NULL, 16, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xf7f36000
close(3)                                = 0
statfs("/dev/shm/", {f_type=TMPFS_MAGIC, f_bsize=4096, f_blocks=16384, f_bfree=16360, f_bavail=16360, f_files=1018431, f_ffree=1018406, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_NOSUID|ST_NODEV|ST_NOEXEC|ST_RELATIME}) = 0
futex(0xf7ceb1d0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
open("/dev/shm/faketime_shm_19240", O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600) = 3
mmap2(NULL, 48, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xf7f35000
futex(0xf7f36000, FUTEX_WAIT_PRIVATE, 1, NULL

it seems the process is using the shared shm/sem from the parent process (19240) this is broken since 0.9.8, in which FAKETIME_SHARED is used for passing the semaphore and shared memory.

wolfcw commented 1 year ago

Thanks for reporting. Might be related to how the struct timespec is defined on the system for 32 vs 64 bit processes, as it is used as a part of the shared memory libfaketime uses.

As a workaround, does it help to explicitly unset FAKETIME_SHARED before starting the child process? Also, I assume this only happens when already the parent process is started with libfaketime preloaded?

robbert-ef commented 1 year ago

correct! issue only occurs when libfaketime is loaded in the parent process using LD_PRELOAD. explicitly unsetting FAKETIME_SHARED resolves the issue for the example:

LD_PRELOAD=libfaketime.so FAKETIME=+60d bash -c 'unset FAKETIME_SHARED; ./test'
Hello, World!

This however is not a workaround for me as the child process in my use-case is a 32-bit python interpreter started from pyenv. I have no control on when the 32-bit process is started. This can also be the case for other applications in which a 32-bit process is used.

Maybe add an option to not share sem/shm? for example by setting FAKETIME_SHARED=0?

For now I will stick to 0.9.7 which is working without problem