`fstatat()` not intercepted (with glibc >= 2.33?)
It looks like libfaketime does not intercept fstatat().
This can be reproduced with the following example:
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
int main() {
struct stat st;
stat("1", &st);
printf("%ld\n", st.st_mtime);
fstatat(AT_FDCWD, "1", &st, 0);
printf("%ld\n", st.st_mtime);
return 0;
}
$ touch 1
$ FAKETIME='2024-01-01 00:00:00' LD_PRELOAD=/tmp/libfaketime/src/libfaketime.so.1 ./a.out
1704063600
1727378293
Apparently the code is referring to __fxstatat*() but it looks like glibc is using plain fstatat and fstatat64 since 2.33:
$ readelf -W -s /usr/lib64/libc.so.6 | grep f.*statat
607: 00000000001043f0 50 FUNC WEAK DEFAULT 13 fstatat@@GLIBC_2.33
725: 00000000001043f0 50 FUNC WEAK DEFAULT 13 fstatat64@@GLIBC_2.33
2588: 00000000001163a0 100 FUNC GLOBAL DEFAULT 13 __fxstatat@@GLIBC_2.4
3033: 00000000001163a0 100 FUNC GLOBAL DEFAULT 13 __fxstatat64@@GLIBC_2.4
Just a small datapoint:
We may be seeing something similar on ubuntu jammy (glibc 2.35) -- we run a backport of dovecot-2.3.21.1 there, and use faketime ... dovecot-lda to antedate delivery timestamps, and are seeing spurious warnings coming from https://github.com/dovecot/core/blob/d492236fa077cba1222695ca3267afb767235672/src/lib/file-dotlock.c#L585 .
However, that dovecot code calls fstat() instead of fstatat(), and when running a modified version of your reproducer to call fstat, those calls are getting intercepted by libfaketime, so I don't get what's going on here yet.
Sample output here:
$ touch 1 ; ./faketime -f -1d /tmp/henk
stat 1737468826
fstat 1737468826
fstatat 1737555226
time() 1737468826
$ cat /tmp/henk.c
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
int main() {
struct stat st;
stat("1", &st);
printf("stat %ld\n", st.st_ctime);
int fd = open("1", O_RDONLY);
fstat(fd, &st);
close(fd);
printf("fstat %ld\n", st.st_ctime);
fstatat(AT_FDCWD, "1", &st, 0);
printf("fstatat %ld\n", st.st_ctime);
time_t now = time(NULL);
printf("time() %ld\n", now);
return 0;
}
In our case this warning seems to be harmless so I'll just ignore it.