Module Name:    src
Committed By:   dholland
Date:           Sun Dec 18 01:19:34 UTC 2016

Modified Files:
        src/sbin/ping: ping.c

Log Message:
PR bin/36997 Zafer Aydogan: ping doesn't validate numeric inputs enough.

Reject packet intervals < 1 ns as they lead to infinite loops adding
zero timespecs.

Fix the behind-schedule behavior so it doesn't spend all its time in
that loop adding very small timespecs. Try ping -c 500 -i 0.000000001
to see this in action with the old ping.


To generate a diff of this commit:
cvs rdiff -u -r1.113 -r1.114 src/sbin/ping/ping.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/ping/ping.c
diff -u src/sbin/ping/ping.c:1.113 src/sbin/ping/ping.c:1.114
--- src/sbin/ping/ping.c:1.113	Sun Dec 18 00:21:33 2016
+++ src/sbin/ping/ping.c	Sun Dec 18 01:19:34 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ping.c,v 1.113 2016/12/18 00:21:33 dholland Exp $	*/
+/*	$NetBSD: ping.c,v 1.114 2016/12/18 01:19:34 dholland Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -58,7 +58,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: ping.c,v 1.113 2016/12/18 00:21:33 dholland Exp $");
+__RCSID("$NetBSD: ping.c,v 1.114 2016/12/18 01:19:34 dholland Exp $");
 #endif
 
 #include <stdio.h>
@@ -461,6 +461,9 @@ main(int argc, char *argv[])
 		errx(EXIT_FAILURE, "Must be superuser to use -l");
 #endif
 	sec_to_timespec(interval, &interval_tv);
+	if (interval_tv.tv_sec == 0 && interval_tv.tv_nsec == 0) {
+		errx(EXIT_FAILURE, "Packet interval must be at least 1 ns");
+	}
 
 	if ((pingflags & (F_AUDIBLE|F_FLOOD)) == (F_AUDIBLE|F_FLOOD))
 		warnx("Sorry, no audible output for flood pings");
@@ -893,6 +896,8 @@ pinger(void)
 {
 	struct tv32 tv32;
 	int i, cc, sw;
+	double waittime;
+	long numskip;
 
 	opack_icmp.icmp_code = 0;
 	opack_icmp.icmp_seq = htons((u_int16_t)(ntransmitted));
@@ -976,10 +981,32 @@ pinger(void)
 	 * If we are at most 100 ms behind, send extras to get caught up.
 	 * Otherwise, skip packets we were too slow to send.
 	 */
-	if (diffsec(&next_tx, &now) <= interval) {
-		do {
-			timespecadd(&next_tx, &interval_tv, &next_tx);
-		} while (diffsec(&next_tx, &now) < -0.1);
+	waittime = diffsec(&next_tx, &now);
+	if (waittime < -1.0) {
+		/* very behind - forget about being precise */
+		next_tx.tv_sec += (int)(-waittime);
+	} else if (waittime < -0.1) {
+		/* behind - skip a few */
+		if (interval_tv.tv_sec == 0) {
+			numskip = (long)(-waittime / interval_tv.tv_nsec);
+			next_tx.tv_nsec += numskip * interval_tv.tv_nsec;
+			/*
+			 * We can add at most one second's worth, but allow
+			 * for tv_nsec reaching 2 billion just in case FP
+			 * issues strike.
+			 */
+			while (next_tx.tv_nsec >= 1000000000) {
+				next_tx.tv_sec++;
+				next_tx.tv_nsec -= 1000000000;
+			}
+		} else {
+			do {
+				timespecadd(&next_tx, &interval_tv, &next_tx);
+			} while (diffsec(&next_tx, &now) < -0.1);
+		}
+
+	} else if (waittime <= interval) {
+		timespecadd(&next_tx, &interval_tv, &next_tx);
 	}
 
 	if (pingflags & F_FLOOD)

Reply via email to