Issues with time() when running a C musl application in docker container on arm Issues with time() when running a C musl application in docker container on arm docker docker

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")