Skip to content

Commit 456e378

Browse files
ahunter6KAGA-KOKO
authored andcommitted
vdso: Make delta calculation overflow safe
Kernel timekeeping is designed to keep the change in cycles (since the last timer interrupt) below max_cycles, which prevents multiplication overflow when converting cycles to nanoseconds. However, if timer interrupts stop, the calculation will eventually overflow. Add protection against that, enabled by config option CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT. Check against max_cycles, falling back to a slower higher precision calculation. Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Adrian Hunter <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent d2e58ab commit 456e378

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

lib/vdso/gettimeofday.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@
1313
# define VDSO_DELTA_MASK(vd) (vd->mask)
1414
#endif
1515

16+
#ifdef CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT
17+
static __always_inline bool vdso_delta_ok(const struct vdso_data *vd, u64 delta)
18+
{
19+
return delta < vd->max_cycles;
20+
}
21+
#else
22+
static __always_inline bool vdso_delta_ok(const struct vdso_data *vd, u64 delta)
23+
{
24+
return true;
25+
}
26+
#endif
27+
1628
#ifndef vdso_shift_ns
1729
static __always_inline u64 vdso_shift_ns(u64 ns, u32 shift)
1830
{
@@ -28,7 +40,10 @@ static __always_inline u64 vdso_calc_ns(const struct vdso_data *vd, u64 cycles,
2840
{
2941
u64 delta = (cycles - vd->cycle_last) & VDSO_DELTA_MASK(vd);
3042

31-
return vdso_shift_ns((delta * vd->mult) + base, vd->shift);
43+
if (likely(vdso_delta_ok(vd, delta)))
44+
return vdso_shift_ns((delta * vd->mult) + base, vd->shift);
45+
46+
return mul_u64_u32_add_u64_shr(delta, vd->mult, base, vd->shift);
3247
}
3348
#endif /* vdso_calc_ns */
3449

0 commit comments

Comments
 (0)