On Mon, Aug 18, 2025 at 08:25:57AM +0200, Otto Moerbeek wrote:

> 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/
> > 
> 

And here is the diff with that:

Index: ntpd.c
===================================================================
RCS file: /home/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      18 Aug 2025 06:19:36 -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: /home/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      18 Aug 2025 06:19:36 -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: /home/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      18 Aug 2025 06:26:33 -0000
@@ -18,6 +18,7 @@
 
 #include <fcntl.h>
 #include <limits.h>
+#include <math.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -73,15 +74,20 @@ getmonotime(void)
 }
 
 
-void
+int
 d_to_tv(double d, struct timeval *tv)
 {
+       if (!isfinite(d) || d > (double)LONG_MAX || d < (double)LONG_MIN)
+               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

Reply via email to