Bug Summary

File:src/usr.sbin/rdate/ntp.c
Warning:line 146, column 2
Value stored to 's' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ntp.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/rdate/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/rdate/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/rdate/ntp.c
1/* $OpenBSD: ntp.c,v 1.36 2020/01/09 19:37:56 tb Exp $ */
2
3/*
4 * Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved.
5 * Copyright (c) 1996, 1997 by University of Cambridge. All rights reserved.
6 * Copyright (c) 2002 by Thorsten "mirabile" Glaser.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the author nor the university may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/socket.h>
33#include <sys/time.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <ctype.h>
38#include <err.h>
39#include <errno(*__errno()).h>
40#include <fcntl.h>
41#include <float.h>
42#include <limits.h>
43#include <math.h>
44#include <netdb.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <time.h>
49#include <poll.h>
50#include <unistd.h>
51
52#include "ntpleaps.h"
53
54/*
55 * NTP definitions. Note that these assume 8-bit bytes - sigh. There
56 * is little point in parameterising everything, as it is neither
57 * feasible nor useful. It would be very useful if more fields could
58 * be defined as unspecified. The NTP packet-handling routines
59 * contain a lot of extra assumptions.
60 */
61
62#define JAN_19702208988800.0 2208988800.0 /* 1970 - 1900 in seconds */
63#define NTP_SCALE4294967296.0 4294967296.0 /* 2^32, of course! */
64
65#define NTP_MODE_CLIENT3 3 /* NTP client mode */
66#define NTP_MODE_SERVER4 4 /* NTP server mode */
67#define NTP_VERSION4 4 /* The current version */
68#define NTP_VERSION_MIN1 1 /* The minimum valid version */
69#define NTP_VERSION_MAX4 4 /* The maximum valid version */
70#define NTP_STRATUM_MAX14 14 /* The maximum valid stratum */
71#define NTP_INSANITY3600.0 3600.0 /* Errors beyond this are hopeless */
72
73#define NTP_PACKET_MIN48 48 /* Without authentication */
74#define NTP_PACKET_MAX68 68 /* With authentication (ignored) */
75
76#define NTP_DISP_FIELD8 8 /* Offset of dispersion field */
77#define NTP_REFERENCE16 16 /* Offset of reference timestamp */
78#define NTP_ORIGINATE24 24 /* Offset of originate timestamp */
79#define NTP_RECEIVE32 32 /* Offset of receive timestamp */
80#define NTP_TRANSMIT40 40 /* Offset of transmit timestamp */
81
82#define STATUS_NOWARNING0 0 /* No Leap Indicator */
83#define STATUS_LEAPHIGH1 1 /* Last Minute Has 61 Seconds */
84#define STATUS_LEAPLOW2 2 /* Last Minute Has 59 Seconds */
85#define STATUS_ALARM3 3 /* Server Clock Not Synchronized */
86
87#define MAX_QUERIES25 25
88#define MAX_DELAY15 15
89
90#define MILLION_L1000000l 1000000l /* For conversion to/from timeval */
91#define MILLION_D1.0e6 1.0e6 /* Must be equal to MILLION_L */
92
93struct ntp_data {
94 u_char status;
95 u_char version;
96 u_char mode;
97 u_char stratum;
98 double receive;
99 double transmit;
100 double current;
101 u_int64_t recvck;
102
103 /* Local State */
104 double originate;
105 u_int64_t xmitck;
106};
107
108void ntp_client(const char *, int, struct timeval *, struct timeval *, int);
109int sync_ntp(int, const struct sockaddr *, double *, double *);
110int write_packet(int, struct ntp_data *);
111int read_packet(int, struct ntp_data *, double *, double *);
112void unpack_ntp(struct ntp_data *, u_char *);
113double current_time(double);
114void create_timeval(double, struct timeval *, struct timeval *);
115
116#ifdef DEBUG
117void print_packet(const struct ntp_data *);
118#endif
119
120int corrleaps;
121
122void
123ntp_client(const char *hostname, int family, struct timeval *new,
124 struct timeval *adjust, int leapflag)
125{
126 struct addrinfo hints, *res0, *res;
127 double offset, error;
128 int accept = 0, ret, s, ierror;
129
130 memset(&hints, 0, sizeof(hints));
131 hints.ai_family = family;
132 hints.ai_socktype = SOCK_DGRAM2;
133 ierror = getaddrinfo(hostname, "ntp", &hints, &res0);
134 if (ierror) {
135 errx(1, "%s: %s", hostname, gai_strerror(ierror));
136 /*NOTREACHED*/
137 }
138
139 if (pledge("stdio inet", NULL((void *)0)) == -1)
140 err(1, "pledge");
141
142 corrleaps = leapflag;
143 if (corrleaps)
144 ntpleaps_init();
145
146 s = -1;
Value stored to 's' is never read
147 for (res = res0; res; res = res->ai_next) {
148 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
149 if (s == -1)
150 continue;
151
152 ret = sync_ntp(s, res->ai_addr, &offset, &error);
153 if (ret < 0) {
154#ifdef DEBUG
155 fprintf(stderr(&__sF[2]), "try the next address\n");
156#endif
157 close(s);
158 s = -1;
159 continue;
160 }
161
162 accept++;
163 break;
164 }
165 freeaddrinfo(res0);
166
167#ifdef DEBUG
168 fprintf(stderr(&__sF[2]), "Correction: %.6f +/- %.6f\n", offset, error);
169#endif
170
171 if (accept < 1)
172 errx(1, "Unable to get a reasonable time estimate");
173
174 create_timeval(offset, new, adjust);
175}
176
177int
178sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
179{
180 int accepts = 0, rejects = 0;
181 int delay = MAX_DELAY15, ret;
182 double deadline;
183 double a, b, x, y;
184 double minerr = 0.1; /* Maximum ignorable variation */
185 struct ntp_data data;
186
187 deadline = current_time(JAN_19702208988800.0) + delay;
188 *offset = 0.0;
189 *error = NTP_INSANITY3600.0;
190
191 if (connect(fd, peer, SA_LEN(peer)((peer)->sa_len)) == -1) {
192 warn("Failed to connect to server");
193 return (-1);
194 }
195
196 while (accepts < MAX_QUERIES25) {
197 memset(&data, 0, sizeof(data));
198
199 if (current_time(JAN_19702208988800.0) > deadline) {
200 warnx("Not enough valid responses received in time");
201 return (-1);
202 }
203
204 if (write_packet(fd, &data) < 0)
205 return (-1);
206
207 ret = read_packet(fd, &data, &x, &y);
208
209 if (ret < 0)
210 return (-1);
211 else if (ret > 0) {
212#ifdef DEBUG
213 print_packet(&data);
214#endif
215
216 if (++rejects > MAX_QUERIES25) {
217 warnx("Too many bad or lost packets");
218 return (-1);
219 } else
220 continue;
221 } else
222 ++accepts;
223
224#ifdef DEBUG
225 fprintf(stderr(&__sF[2]), "Offset: %.6f +/- %.6f\n", x, y);
226#endif
227
228 if ((a = x - *offset) < 0.0)
229 a = -a;
230 if (accepts <= 1)
231 a = 0.0;
232 b = *error + y;
233 if (y < *error) {
234 *offset = x;
235 *error = y;
236 }
237
238#ifdef DEBUG
239 fprintf(stderr(&__sF[2]), "Best: %.6f +/- %.6f\n", *offset, *error);
240#endif
241
242 if (a > b) {
243 warnx("Inconsistent times received from NTP server");
244 return (-1);
245 }
246
247 if ((data.status & STATUS_ALARM3) == STATUS_ALARM3) {
248 warnx("Ignoring NTP server with alarm flag set");
249 return (-1);
250 }
251
252 if (*error <= minerr)
253 break;
254 }
255
256 return (accepts);
257}
258
259/* Send out NTP packet. */
260int
261write_packet(int fd, struct ntp_data *data)
262{
263 u_char packet[NTP_PACKET_MIN48];
264 ssize_t length;
265
266 memset(packet, 0, sizeof(packet));
267
268 packet[0] = (NTP_VERSION4 << 3) | (NTP_MODE_CLIENT3);
269
270 arc4random_buf(&data->xmitck, sizeof(data->xmitck));
271
272 /*
273 * Send out a random 64-bit number as our transmit time. The NTP
274 * server will copy said number into the originate field on the
275 * response that it sends us. This is totally legal per the SNTP spec.
276 *
277 * The impact of this is two fold: we no longer send out the current
278 * system time for the world to see (which may aid an attacker), and
279 * it gives us a (not very secure) way of knowing that we're not
280 * getting spoofed by an attacker that can't capture our traffic
281 * but can spoof packets from the NTP server we're communicating with.
282 *
283 * No endian concerns here. Since we're running as a strict
284 * unicast client, we don't have to worry about anyone else finding
285 * the transmit field intelligible.
286 */
287
288 bcopy(&data->xmitck, (packet + NTP_TRANSMIT40), sizeof(data->xmitck));
289
290 data->originate = current_time(JAN_19702208988800.0);
291
292 length = write(fd, packet, sizeof(packet));
293
294 if (length != sizeof(packet)) {
295 warn("Unable to send NTP packet to server");
296 return (-1);
297 }
298
299 return (0);
300}
301
302/*
303 * Check the packet and work out the offset and optionally the error.
304 * Note that this contains more checking than xntp does. Return 0 for
305 * success, 1 for failure. Note that it must not change its arguments
306 * if it fails.
307 */
308int
309read_packet(int fd, struct ntp_data *data, double *off, double *error)
310{
311 u_char receive[NTP_PACKET_MAX68];
312 struct pollfd pfd[1];
313 double x, y;
314 int length, r;
315
316 pfd[0].fd = fd;
317 pfd[0].events = POLLIN0x0001;
318
319retry:
320 r = poll(pfd, 1, 1000 * MAX_DELAY15 / MAX_QUERIES25);
321 if (r == -1) {
322 if (errno(*__errno()) == EINTR4)
323 goto retry;
324 warn("select");
325 return (r);
326 }
327
328 if (r != 1)
329 return (1);
330 if ((pfd[0].revents & POLLIN0x0001) == 0)
331 return (1);
332
333 length = read(fd, receive, NTP_PACKET_MAX68);
334 if (length == -1) {
335 warn("Unable to receive NTP packet from server");
336 return (-1);
337 }
338
339 if (length < NTP_PACKET_MIN48 || length > NTP_PACKET_MAX68) {
340 warnx("Invalid NTP packet size, packet rejected");
341 return (1);
342 }
343
344 unpack_ntp(data, receive);
345
346 if (data->recvck != data->xmitck) {
347 warnx("Invalid cookie received, packet rejected");
348 return (1);
349 }
350
351 if (data->version < NTP_VERSION_MIN1 ||
352 data->version > NTP_VERSION_MAX4) {
353 warnx("Received NTP version %u, need %u or lower",
354 data->version, NTP_VERSION4);
355 return (1);
356 }
357
358 if (data->mode != NTP_MODE_SERVER4) {
359 warnx("Invalid NTP server mode, packet rejected");
360 return (1);
361 }
362
363 if (data->stratum > NTP_STRATUM_MAX14) {
364 warnx("Invalid stratum received, packet rejected");
365 return (1);
366 }
367
368 if (data->transmit == 0.0) {
369 warnx("Server clock invalid, packet rejected");
370 return (1);
371 }
372
373 x = data->receive - data->originate;
374 y = data->transmit - data->current;
375
376 *off = (x + y) / 2;
377 *error = x - y;
378
379 x = (data->current - data->originate) / 2;
380
381 if (x > *error)
382 *error = x;
383
384 return (0);
385}
386
387/*
388 * Unpack the essential data from an NTP packet, bypassing struct
389 * layout and endian problems. Note that it ignores fields irrelevant
390 * to SNTP.
391 */
392void
393unpack_ntp(struct ntp_data *data, u_char *packet)
394{
395 int i;
396 double d;
397
398 data->current = current_time(JAN_19702208988800.0);
399
400 data->status = (packet[0] >> 6);
401 data->version = (packet[0] >> 3) & 0x07;
402 data->mode = packet[0] & 0x07;
403 data->stratum = packet[1];
404
405 for (i = 0, d = 0.0; i < 8; ++i)
406 d = 256.0*d+packet[NTP_RECEIVE32+i];
407
408 data->receive = d / NTP_SCALE4294967296.0;
409
410 for (i = 0, d = 0.0; i < 8; ++i)
411 d = 256.0*d+packet[NTP_TRANSMIT40+i];
412
413 data->transmit = d / NTP_SCALE4294967296.0;
414
415 /* See write_packet for why this isn't an endian problem. */
416 bcopy((packet + NTP_ORIGINATE24), &data->recvck, sizeof(data->recvck));
417}
418
419/*
420 * Get the current UTC time in seconds since the Epoch plus an offset
421 * (usually the time from the beginning of the century to the Epoch)
422 */
423double
424current_time(double offset)
425{
426 struct timeval current;
427 u_int64_t t;
428
429 if (gettimeofday(&current, NULL((void *)0)))
430 err(1, "Could not get local time of day");
431
432 /*
433 * At this point, current has the current TAI time.
434 * Now subtract leap seconds to set the posix tick.
435 */
436
437 t = SEC_TO_TAI64(current.tv_sec)((4611686018427387914ULL) + (u_int64_t)(current.tv_sec));
438 if (corrleaps)
439 ntpleaps_sub(&t);
440
441 return (offset + TAI64_TO_SEC(t)((t) - (4611686018427387914ULL)) + 1.0e-6 * current.tv_usec);
442}
443
444/*
445 * Change offset into current UTC time. This is portable, even if
446 * struct timeval uses an unsigned long for tv_sec.
447 */
448void
449create_timeval(double difference, struct timeval *new, struct timeval *adjust)
450{
451 struct timeval old;
452 long n;
453
454 /* Start by converting to timeval format. Note that we have to
455 * cater for negative, unsigned values. */
456 if ((n = (long) difference) > difference)
457 --n;
458 adjust->tv_sec = n;
459 adjust->tv_usec = (long) (MILLION_D1.0e6 * (difference-n));
460 errno(*__errno()) = 0;
461 if (gettimeofday(&old, NULL((void *)0)))
462 err(1, "Could not get local time of day");
463 new->tv_sec = old.tv_sec + adjust->tv_sec;
464 new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec);
465
466 if (n < 0) {
467 new->tv_usec += MILLION_L1000000l;
468 --new->tv_sec;
469 } else if (n >= MILLION_L1000000l) {
470 new->tv_usec -= MILLION_L1000000l;
471 ++new->tv_sec;
472 }
473}
474
475#ifdef DEBUG
476void
477print_packet(const struct ntp_data *data)
478{
479 printf("status: %u\n", data->status);
480 printf("version: %u\n", data->version);
481 printf("mode: %u\n", data->mode);
482 printf("stratum: %u\n", data->stratum);
483 printf("originate: %f\n", data->originate);
484 printf("receive: %f\n", data->receive);
485 printf("transmit: %f\n", data->transmit);
486 printf("current: %f\n", data->current);
487 printf("xmitck: 0x%0llX\n", data->xmitck);
488 printf("recvck: 0x%0llX\n", data->recvck);
489};
490#endif