]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/ntp/libntp/adjtime.c
Fix multiple vulnerabilities in ntp. [SA-18:02.ntp]
[FreeBSD/releng/10.3.git] / contrib / ntp / libntp / adjtime.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #ifdef MPE 
6 /*
7  * MPE lacks adjtime(), so we define our own.  But note that time slewing has
8  * a sub-second accuracy bug documented in SR 5003462838 which prevents ntpd
9  * from being able to maintain clock synch.  Because of the bug, this adjtime()
10  * implementation as used by ntpd has a side-effect of screwing up the hardware
11  * PDC clock, which will need to be reset with a reboot.
12  *
13  * This problem affects all versions of MPE at the time of this writing (when
14  * MPE/iX 7.0 is the most current).  It only causes bad things to happen when
15  * doing continuous clock synchronization with ntpd; note that you CAN run ntpd
16  * with "disable ntp" in ntp.conf if you wish to provide a time server.
17  *
18  * The one-time clock adjustment functionality of ntpdate and ntp_timeset can
19  * be used without screwing up the PDC clock.
20  * 
21  */
22 #include <time.h>
23
24 int adjtime(struct timeval *delta, struct timeval *olddelta);
25
26 int adjtime(struct timeval *delta, struct timeval *olddelta)
27
28 {
29 /* Documented, supported MPE system intrinsics. */
30
31 extern void GETPRIVMODE(void);
32 extern void GETUSERMODE(void);
33
34 /* Undocumented, unsupported MPE internal functions. */
35
36 extern long long current_correction_usecs(void);
37 extern long long get_time(void);
38 extern void get_time_change_info(long long *, char *, char *);
39 extern long long pdc_time(int *);
40 extern void set_time_correction(long long, int, int);
41 extern long long ticks_to_micro(long long);
42
43 long long big_sec, big_usec, new_correction = 0LL;
44 long long prev_correction;
45
46 if (delta != NULL) {
47   /* Adjustment required.  Convert delta to 64-bit microseconds. */
48   big_sec = (long)delta->tv_sec;
49   big_usec = delta->tv_usec;
50   new_correction = (big_sec * 1000000LL) + big_usec;
51 }
52
53 GETPRIVMODE();
54
55 /* Determine how much of a previous correction (if any) we're interrupting. */
56 prev_correction = current_correction_usecs();
57
58 if (delta != NULL) {
59   /* Adjustment required. */
60
61 #if 0
62   /* Speculative code disabled until bug SR 5003462838 is fixed.  This bug
63      prevents accurate time slewing, and indeed renders ntpd inoperable. */
64
65   if (prev_correction != 0LL) {
66     /* A previous adjustment did not complete.  Since the PDC UTC clock was
67     immediately jumped at the start of the previous adjustment, we must
68     explicitly reset it to the value of the MPE local time clock minus the
69     time zone offset. */
70
71     char pwf_since_boot, recover_pwf_time;
72     long long offset_ticks, offset_usecs, pdc_usecs_current, pdc_usecs_wanted;
73     int hpe_status;
74
75     get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
76     offset_usecs = ticks_to_micro(offset_ticks);
77     pdc_usecs_wanted = get_time() - offset_usecs;
78     pdc_usecs_current = pdc_time(&hpe_status);
79     if (hpe_status == 0) 
80       /* Force new PDC time by starting an extra correction. */
81       set_time_correction(pdc_usecs_wanted - pdc_usecs_current,0,1);
82   }
83 #endif /* 0 */
84     
85   /* Immediately jump the PDC time to the new value, and then initiate a 
86      gradual MPE time correction slew. */
87   set_time_correction(new_correction,0,1);
88 }
89
90 GETUSERMODE();
91
92 if (olddelta != NULL) {
93   /* Caller wants to know remaining amount of previous correction. */
94   (long)olddelta->tv_sec = prev_correction / 1000000LL;
95   olddelta->tv_usec = prev_correction % 1000000LL;
96 }
97
98 return 0;
99 }
100 #endif /* MPE */
101
102 #ifdef NEED_HPUX_ADJTIME
103 /*************************************************************************/
104 /* (c) Copyright Tai Jin, 1988.  All Rights Reserved.                    */
105 /*     Hewlett-Packard Laboratories.                                     */
106 /*                                                                       */
107 /* Permission is hereby granted for unlimited modification, use, and     */
108 /* distribution.  This software is made available with no warranty of    */
109 /* any kind, express or implied.  This copyright notice must remain      */
110 /* intact in all versions of this software.                              */
111 /*                                                                       */
112 /* The author would appreciate it if any bug fixes and enhancements were */
113 /* to be sent back to him for incorporation into future versions of this */
114 /* software.  Please send changes to tai@iag.hp.com or ken@sdd.hp.com.   */
115 /*************************************************************************/
116
117 /*
118  * Revision history
119  *
120  * 9 Jul 94     David L. Mills, Unibergity of Delabunch
121  *              Implemented variable threshold to limit age of
122  *              corrections; reformatted code for readability.
123  */
124
125 #ifndef lint
126 static char RCSid[] = "adjtime.c,v 3.1 1993/07/06 01:04:42 jbj Exp";
127 #endif
128
129 #include <sys/types.h>
130 #include <sys/ipc.h>
131 #include <sys/msg.h>
132 #include <time.h>
133 #include <signal.h>
134 #include "adjtime.h"
135
136 #define abs(x)  ((x) < 0 ? -(x) : (x))
137
138 /*
139  * The following paramters are appropriate for an NTP adjustment
140  * interval of one second.
141  */
142 #define ADJ_THRESH 200          /* initial threshold */
143 #define ADJ_DELTA 4             /* threshold decrement */
144
145 static long adjthresh;          /* adjustment threshold */
146 static long saveup;             /* corrections accumulator */
147
148 /*
149  * clear_adjtime - reset accumulator and threshold variables
150  */
151 void
152 _clear_adjtime(void)
153 {
154         saveup = 0;
155         adjthresh = ADJ_THRESH;
156 }
157
158 /*
159  * adjtime - hp-ux copout of the standard Unix adjtime() system call
160  */
161 int
162 adjtime(
163         register struct timeval *delta,
164         register struct timeval *olddelta
165         )
166 {
167         struct timeval newdelta;
168
169         /*
170          * Corrections greater than one second are done immediately.
171          */
172         if (delta->tv_sec) {
173                 adjthresh = ADJ_THRESH;
174                 saveup = 0;
175                 return(_adjtime(delta, olddelta));
176         }
177
178         /*
179          * Corrections less than one second are accumulated until
180          * tripping a threshold, which is initially set at ADJ_THESH and
181          * reduced in ADJ_DELTA steps to zero. The idea here is to
182          * introduce large corrections quickly, while making sure that
183          * small corrections are introduced without excessive delay. The
184          * idea comes from the ARPAnet routing update algorithm.
185          */
186         saveup += delta->tv_usec;
187         if (abs(saveup) >= adjthresh) {
188                 adjthresh = ADJ_THRESH;
189                 newdelta.tv_sec = 0;
190                 newdelta.tv_usec = saveup;
191                 saveup = 0;
192                 return(_adjtime(&newdelta, olddelta));
193         } else {
194                 adjthresh -= ADJ_DELTA;
195         }
196
197         /*
198          * While nobody uses it, return the residual before correction,
199          * as per Unix convention.
200          */
201         if (olddelta)
202             olddelta->tv_sec = olddelta->tv_usec = 0;
203         return(0);
204 }
205
206 /*
207  * _adjtime - does the actual work
208  */
209 int
210 _adjtime(
211         register struct timeval *delta,
212         register struct timeval *olddelta
213         )
214 {
215         register int mqid;
216         MsgBuf msg;
217         register MsgBuf *msgp = &msg;
218
219         /*
220          * Get the key to the adjtime message queue (note that we must
221          * get it every time because the queue might have been removed
222          * and recreated)
223          */
224         if ((mqid = msgget(KEY, 0)) == -1)
225             return (-1);
226         msgp->msgb.mtype = CLIENT;
227         msgp->msgb.tv = *delta;
228         if (olddelta)
229             msgp->msgb.code = DELTA2;
230         else
231             msgp->msgb.code = DELTA1;
232
233         /*
234          * Tickle adjtimed and snatch residual, if indicated. Lots of
235          * fanatic error checking here.
236          */
237         if (msgsnd(mqid, &msgp->msgp, MSGSIZE, 0) == -1)
238             return (-1);
239         if (olddelta) {
240                 if (msgrcv(mqid, &msgp->msgp, MSGSIZE, SERVER, 0) == -1)
241                     return (-1);
242                 *olddelta = msgp->msgb.tv;
243         }
244         return (0);
245 }
246
247 #else
248 # if NEED_QNX_ADJTIME
249 /*
250  * Emulate adjtime() using QNX ClockAdjust().
251  * Chris Burghart <burghart@atd.ucar.edu>, 11/2001
252  * Miroslaw Pabich <miroslaw_pabich@o2.pl>, 09/2005
253  *
254  * This is an implementation of adjtime() for QNX.  
255  * ClockAdjust() is used to tweak the system clock for about
256  * 1 second period until the desired delta is achieved.
257  * Time correction slew is limited to reasonable value.
258  * Internal rounding and relative errors are reduced.
259  */
260 # include <sys/neutrino.h>
261 # include <sys/time.h>
262
263 # include <ntp_stdlib.h>
264
265 /*
266  * Time correction slew limit. QNX is a hard real-time system,
267  * so don't adjust system clock too fast.
268  */
269 #define CORR_SLEW_LIMIT     0.02  /* [s/s] */
270
271 /*
272  * Period of system clock adjustment. It should be equal to adjtime
273  * execution period (1s). If slightly less than 1s (0.95-0.99), then olddelta
274  * residual error (introduced by execution period jitter) will be reduced.
275  */
276 #define ADJUST_PERIOD       0.97  /* [s] */
277
278 int 
279 adjtime (struct timeval *delta, struct timeval *olddelta)
280 {
281     double delta_nsec;
282     double delta_nsec_old;
283     struct _clockadjust adj;
284     struct _clockadjust oldadj;
285
286     /*
287      * How many nanoseconds are we adjusting?
288      */
289     if (delta != NULL)
290         delta_nsec = 1e9 * (long)delta->tv_sec + 1e3 * delta->tv_usec;
291     else
292         delta_nsec = 0;
293
294     /*
295      * Build the adjust structure and call ClockAdjust()
296      */
297     if (delta_nsec != 0)
298     {
299         struct _clockperiod period;
300         long count;
301         long increment;
302         long increment_limit;
303         int isneg = 0;
304
305         /*
306          * Convert to absolute value for future processing
307          */
308         if (delta_nsec < 0)
309         {
310             isneg = 1;
311             delta_nsec = -delta_nsec;
312         }
313
314         /*
315          * Get the current clock period (nanoseconds)
316          */
317         if (ClockPeriod (CLOCK_REALTIME, 0, &period, 0) == -1)
318             return -1;
319
320         /*
321          * Compute count and nanoseconds increment
322          */
323         count = 1e9 * ADJUST_PERIOD / period.nsec;
324         increment = delta_nsec / count + .5;
325         /* Reduce relative error */
326         if (count > increment + 1)
327         {
328             increment = 1 + (long)((delta_nsec - 1) / count);
329             count = delta_nsec / increment + .5;
330         }
331
332         /*
333          * Limit the adjust increment to appropriate value
334          */
335         increment_limit = CORR_SLEW_LIMIT * period.nsec;
336         if (increment > increment_limit)
337         {
338             increment = increment_limit;
339             count = delta_nsec / increment + .5;
340             /* Reduce relative error */
341             if (increment > count + 1)
342             {
343                 count =  1 + (long)((delta_nsec - 1) / increment);
344                 increment = delta_nsec / count + .5;
345             }
346         }
347
348         adj.tick_nsec_inc = isneg ? -increment : increment;
349         adj.tick_count = count;
350     }
351     else
352     {
353         adj.tick_nsec_inc = 0;
354         adj.tick_count = 0;
355     }
356
357     if (ClockAdjust (CLOCK_REALTIME, &adj, &oldadj) == -1)
358         return -1;
359
360     /*
361      * Build olddelta
362      */
363     delta_nsec_old = (double)oldadj.tick_count * oldadj.tick_nsec_inc;
364     if (olddelta != NULL)
365     {
366         if (delta_nsec_old != 0)
367         {
368             /* Reduce rounding error */
369             delta_nsec_old += (delta_nsec_old < 0) ? -500 : 500;
370             olddelta->tv_sec = delta_nsec_old / 1e9;
371             olddelta->tv_usec = (long)(delta_nsec_old - 1e9
372                                  * (long)olddelta->tv_sec) / 1000;
373         }
374         else
375         {
376             olddelta->tv_sec = 0;
377             olddelta->tv_usec = 0;
378         }
379     }
380
381     return 0;
382 }
383 # else /* no special adjtime() needed */
384 int adjtime_bs;
385 # endif
386 #endif