On Fri, Aug 08, 2025 at 03:12:36PM +0200, Henning Brauer wrote:
> heya,
>
> * [email protected] <[email protected]> [2025-08-07 01:02]:
> > We have found several privsep interface bugs in `ntpd`, where the
> > unprivileged
> > `ntp` compartment can trigger undefined behavior inside the privileged
> > compartment. We think that these bugs have *no security impact* but are
> > still
> > worth fixing, thus sending this report to bugs@.
>
> absolutely.
>
> > The privileged compartment accepts multiple messages from the unprivileged
> > `ntp` compartment, where the payload is a `double` arithmetic value. We
> > identified several cases where the privileged parent performs a lossy
> > conversion from `double` to `long` to extract the integer part of the
> > `double`.
> > This conversion is well-defined only when the `double` value is between
> > `LONG_MIN` and `LONG_MAX`. However, the privileged compartment does not
> > verify
> > whether the `double` is in this range before the conversion to a `long`,
> > allowing the unprivileged `ntp` compartment to send a value outside this
> > range,
> > thus triggering undefined behavior inside the privileged compartment.
>
> I guess the most sensible approach is to give d_to_tv a return value
> and make use of it.
> the log_warn in ntpd_settime could also be a fatal, after all, but the
> existing ones are also ust warnings.
>
> thanks for finding, analysis and report!
>
> cheers
>
> henning
>
> Index: ntpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntpd.c,v
> diff -u -p -r1.142 ntpd.c
> --- ntpd.c 21 Nov 2024 13:38:14 -0000 1.142
> +++ ntpd.c 8 Aug 2025 13:08:35 -0000
> @@ -410,6 +410,8 @@ dispatch_imsg(struct ntpd_conf *lconf, i
> fatalx("invalid IMSG_ADJTIME received");
> memcpy(&d, imsg.data, sizeof(d));
> n = ntpd_adjtime(d);
> + if (n == -1)
> + fatalx("IMSG_ADJTIME with invalid value");
> imsg_compose(ibuf, IMSG_ADJTIME, 0, 0, -1,
> &n, sizeof(n));
> break;
> @@ -474,7 +476,8 @@ ntpd_adjtime(double d)
> log_info("adjusting local clock by %fs", d);
> else
> log_debug("adjusting local clock by %fs", d);
> - d_to_tv(d, &tv);
> + if (d_to_tv(d, &tv) == -1)
> + return (-1);
> if (adjtime(&tv, &olddelta) == -1)
> log_warn("adjtime failed");
> else if (!firstadj && olddelta.tv_sec == 0 && olddelta.tv_usec == 0)
> @@ -532,7 +535,10 @@ ntpd_settime(double d)
> log_warn("gettimeofday");
> return;
> }
> - d_to_tv(d, &tv);
> + if (d_to_tv(d, &tv) == -1) {
> + log_warn("ntpd_settime: invalid value");
> + return;
> + }
> curtime.tv_usec += tv.tv_usec + 1000000;
> curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000);
> curtime.tv_usec %= 1000000;
> Index: ntpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntpd.h,v
> diff -u -p -r1.154 ntpd.h
> --- ntpd.h 21 May 2024 05:00:48 -0000 1.154
> +++ ntpd.h 8 Aug 2025 13:08:35 -0000
> @@ -399,7 +399,7 @@ double gettime_from_timeval(struct ti
> double getoffset(void);
> double gettime(void);
> time_t getmonotime(void);
> -void d_to_tv(double, struct timeval *);
> +int d_to_tv(double, struct timeval *);
> double lfp_to_d(struct l_fixedpt);
> struct l_fixedpt d_to_lfp(double);
> double sfp_to_d(struct s_fixedpt);
> Index: util.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/util.c,v
> diff -u -p -r1.28 util.c
> --- util.c 20 Dec 2023 15:36:36 -0000 1.28
> +++ util.c 8 Aug 2025 13:08:35 -0000
> @@ -73,15 +73,20 @@ getmonotime(void)
> }
>
>
> -void
> +int
> d_to_tv(double d, struct timeval *tv)
> {
> + if (d > (double)LONG_MAX || d < (double)LONG_MIN)
I would add for safety: !isfinite(d) || ...
-Otto
> + return (-1);
> +
> tv->tv_sec = d;
> tv->tv_usec = (d - tv->tv_sec) * 1000000;
> while (tv->tv_usec < 0) {
> tv->tv_usec += 1000000;
> tv->tv_sec -= 1;
> }
> +
> + return (0);
> }
>
> double
>
>
> --
> Henning Brauer, [email protected], [email protected]
> BS Web Services GmbH, http://bsws.de, Full-Service ISP
> Secure Hosting, Mail and DNS. Virtual & Dedicated Servers, Root to Fully
> Managed
> Henning Brauer Consulting, http://henningbrauer.com/
>