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)