Issues with time() when running a C musl application in docker container on arm
I am able to reproduce this exactly as described in the question. On my particular ARM hardware:
$ docker --versionDocker version 19.03.6, build 369ce74a3c [released approx. 2020-02-12]$ file demodemo: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),statically linked, with debug_info, not stripped
Using strace
we can observe this behavior inside a container launched as reported:
...clock_gettime64(CLOCK_REALTIME, 0xbe9c5e10) = -1 EPERM (Operation not permitted)...
However, if we add the --privileged
flag to the Docker command, it works:
# ./demohalloresult: 1608983884Current local time and date: Sat Dec 26 11:58:04 2020
This behavior is caused by a Docker issue: https://gitlab.alpinelinux.org/alpine/aports/-/issues/11774, which is fixed in this commit and rolled into Docker version 19.03.12
(?) and up.
ionFish has solved the puzzle. I will mark his post as answer. However, I would like to post a possible work around that I think should work in all cases. What do you guys think?
I created a wrapper for __clock_gettime and always fallback to gettime32.
DockerFix.c
#include <time.h>#include <errno.h>#include <stdint.h>#include <stdbool.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/syscall.h>static bool __wrap___clock_gettime_fallback = false;int __wrap___clock_gettime(clockid_t clk, struct timespec* ts){ int r; if (!__wrap___clock_gettime_fallback) { r = __real___clock_gettime(clk, ts); if (!r) return r; if (errno == EPERM || errno == EINVAL) { printf("WARN: clock_gettime() faulted with '%s'. Using SYS_clock_gettime32 as permanent fallback. Possible cause could be a faulty Docker version!\n", strerror(errno)); __wrap___clock_gettime_fallback = true; // skip in future } } long ts32[2]; r = syscall(SYS_clock_gettime32, clk, ts32); if (r == -ENOSYS && clk == CLOCK_REALTIME) { r = syscall(SYS_gettimeofday_time32, ts32, 0); ts32[1] *= 1000; } if (!r) { ts->tv_sec = ts32[0]; ts->tv_nsec = ts32[1]; } return r;}int __attribute__((weak, alias("__wrap___clock_gettime"))) clock_gettime(clockid_t clk, struct timespec* ts);
CMakeLists.txt
set(CMAKE_EXE_LINKER_FLAGS -Wl,--wrap=__clock_gettime")add_executable (TimeTest "TimeTest.c" "DockerFix.c")