libc: Fix possible overflow in binuptime().

This is an application of the kernel overflow fix from r357948 to
userspace, based on the algorithm developed by Bruce Evans. To keep
the ABI of the vds_timekeep stable, instead of adding the large_delta
member, MSB of both multipliers are added to quickly estimate the overflow.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2020-04-09 23:22:35 +00:00
parent c948a17a52
commit 09bae0a023

View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <sys/vdso.h>
#include <errno.h>
#include <strings.h>
#include <time.h>
#include <machine/atomic.h>
#include "libc_private.h"
@ -62,7 +63,8 @@ binuptime(struct bintime *bt, struct vdso_timekeep *tk, int abs)
{
struct vdso_timehands *th;
uint32_t curr, gen;
u_int delta;
uint64_t scale, x;
u_int delta, scale_bits;
int error;
do {
@ -78,7 +80,19 @@ binuptime(struct bintime *bt, struct vdso_timekeep *tk, int abs)
continue;
if (error != 0)
return (error);
bintime_addx(bt, th->th_scale * delta);
scale = th->th_scale;
#ifdef _LP64
scale_bits = ffsl(scale);
#else
scale_bits = ffsll(scale);
#endif
if (__predict_false(scale_bits + fls(delta) > 63)) {
x = (scale >> 32) * delta;
scale &= 0xffffffff;
bt->sec += x >> 32;
bintime_addx(bt, x << 32);
}
bintime_addx(bt, scale * delta);
if (abs)
bintime_add(bt, &th->th_boottime);