summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2022-09-12 08:38:03 -0400
committerRich Felker <dalias@aerifal.cx>2022-09-19 13:21:54 -0400
commitbf14ef193b4203aa9a8b173faeeea06d98397f65 (patch)
tree350a72f59d6afe649814bb65106c2e51c49ce0b5
parent6f3ead0ae16deb9f0004b275e29a276c9712ee3c (diff)
downloadmusl-bf14ef193b4203aa9a8b173faeeea06d98397f65.tar.gz
re-enable vdso clock_gettime on arm (32-bit) with workaround
commit 4486c579cbf0d989080705f515d08cb48636ba88 disabled vdso clock_gettime on arm due to a Linux kernel bug that was not understood at the time, whereby the vdso function silently produced catastrophically wrong results on some systems. since then, the bug was tracked down to the way the arm kernel disabled use of vdso clock_gettime on kernels where the necessary timer was not available or was disabled. it simply patched out the symbols, but it only did this for the legacy time32 functions, and left the time64 function in place but non-operational. kernel commit 4405bdf3c57ec28d606bdf5325f1167505bfdcd4 (first present in 5.8) provided the fix. if this were a bug that impacted all users of the broken kernel versions, we could probably ignore it and assume it had been patched or replaced. however, it's very possible that these kernels appear in the wild in devices running time32 userspace (glibc, musl 1.1.x, or some other environment) where they appear to work fine, but where our new binaries would fail catastrophically if we used the time64 vdso function. since the kernel has not (yet?) given us a way to probe for the working time64 vdso function semantically, we work around the problem by refusing to use the time64 one unless the time32 one is also present. this will revert to not using vdso at all if the time32 one is ever removed, but at least that's safe against wrong results and is just a missed optimization.
-rw-r--r--arch/arm/syscall_arch.h7
-rw-r--r--src/time/clock_gettime.c3
2 files changed, 10 insertions, 0 deletions
diff --git a/arch/arm/syscall_arch.h b/arch/arm/syscall_arch.h
index a877b2cf..624e992e 100644
--- a/arch/arm/syscall_arch.h
+++ b/arch/arm/syscall_arch.h
@@ -101,3 +101,10 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo
#define SYSCALL_FADVISE_6_ARG
#define SYSCALL_IPC_BROKEN_MODE
+
+#define VDSO_USEFUL
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
+#define VDSO_CGT_VER "LINUX_2.6"
+#define VDSO_CGT_WORKAROUND 1
diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c
index c7e66a51..4d2ec22f 100644
--- a/src/time/clock_gettime.c
+++ b/src/time/clock_gettime.c
@@ -42,6 +42,9 @@ static int cgt_init(clockid_t clk, struct timespec *ts)
p = cgt_time32_wrap;
}
}
+#ifdef VDSO_CGT_WORKAROUND
+ if (!__vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM)) p = 0;
+#endif
#endif
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))p;