Skip to content

Commit 72ce778

Browse files
committed
lib/vdso: Provide sanity check for cycles (again)
The original x86 VDSO implementation checked for the validity of the clock source read by testing whether the returned signed cycles value is less than zero. This check was also used by the vdso read function to signal that the current selected clocksource is not VDSO capable. During the rework of the VDSO code the check was removed and replaced with a check for the clocksource mode being != NONE. This turned out to be a mistake because the check is necessary for paravirt and hyperv clock sources. The reason is that these clock sources have their own internal sequence counter to validate the clocksource at the point of reading it. This is necessary because the hypervisor can invalidate the clocksource asynchronously so a check during the VDSO data update is not sufficient. Having a separate indicator for the validity is slower than just validating the cycles value. The check for it being negative turned out to be the fastest implementation and safe as it would require an uptime of ~73 years with a 4GHz counter frequency to result in a false positive. Add an optional function to validate the cycles with a default implementation which allows the compiler to optimize it out for architectures which do not require it. Fixes: 5d51bee ("clocksource: Add common vdso clock mode storage") Reported-by: Miklos Szeredi <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Miklos Szeredi <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent c7f3d43 commit 72ce778

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

lib/vdso/gettimeofday.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
3838
}
3939
#endif
4040

41+
#ifndef vdso_cycles_ok
42+
static inline bool vdso_cycles_ok(u64 cycles)
43+
{
44+
return true;
45+
}
46+
#endif
47+
4148
#ifdef CONFIG_TIME_NS
4249
static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
4350
struct __kernel_timespec *ts)
@@ -62,6 +69,8 @@ static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
6269
return -1;
6370

6471
cycles = __arch_get_hw_counter(vd->clock_mode);
72+
if (unlikely(!vdso_cycles_ok(cycles)))
73+
return -1;
6574
ns = vdso_ts->nsec;
6675
last = vd->cycle_last;
6776
ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
@@ -130,6 +139,8 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk,
130139
return -1;
131140

132141
cycles = __arch_get_hw_counter(vd->clock_mode);
142+
if (unlikely(!vdso_cycles_ok(cycles)))
143+
return -1;
133144
ns = vdso_ts->nsec;
134145
last = vd->cycle_last;
135146
ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);

0 commit comments

Comments
 (0)