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

Check for values between INT_MAX and LONG_MAX (if they're different)
when using strtol to get an int. This applies to the -c and -l options;
the other uses were already checked.

Also limit the inter-packet interval given with -i to values that
don't cause integer overflow calling poll() with milliseconds.

Really large intervals (the number is read as floating point) can
produce positive poll() values but negative integers when converted to
struct timespec; this produces behavior akin to using -l at first and
could be construed as a local DoS vulnerability.
This commit is contained in:
dholland 2016-12-18 00:21:33 +00:00
parent 9383f03afa
commit e0d8c787c6
1 changed files with 27 additions and 6 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ping.c,v 1.112 2016/10/07 22:31:05 joerg Exp $ */
/* $NetBSD: ping.c,v 1.113 2016/12/18 00:21:33 dholland Exp $ */
/*
* Copyright (c) 1989, 1993
@ -58,7 +58,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ping.c,v 1.112 2016/10/07 22:31:05 joerg Exp $");
__RCSID("$NetBSD: ping.c,v 1.113 2016/12/18 00:21:33 dholland Exp $");
#endif
#include <stdio.h>
@ -295,11 +295,17 @@ main(int argc, char *argv[])
compat = 1;
break;
case 'c':
npackets = strtol(optarg, &p, 0);
if (*p != '\0' || npackets <= 0)
l = strtol(optarg, &p, 0);
if (*p != '\0' || l <= 0)
errx(EXIT_FAILURE,
"Bad/invalid number of packets: %s",
optarg);
#if INT_MAX < LONG_MAX
if (l > INT_MAX)
errx(EXIT_FAILURE,
"Too many packets to count: %ld", l);
#endif
npackets = l;
break;
case 'D':
pingflags |= F_DF;
@ -318,12 +324,27 @@ main(int argc, char *argv[])
if (*p != '\0' || interval <= 0)
errx(EXIT_FAILURE, "Bad/invalid interval: %s",
optarg);
/*
* In order to avoid overflowing the microseconds
* argument of poll() the interval must be less than
* INT_MAX/1000. Limit it to one second less than
* that to be safe.
*/
if (interval >= INT_MAX/1000.0 - 1.0)
errx(EXIT_FAILURE,
"Timing interval %g too large", interval);
break;
case 'l':
preload = strtol(optarg, &p, 0);
if (*p != '\0' || preload < 0)
l = strtol(optarg, &p, 0);
if (*p != '\0' || l < 0)
errx(EXIT_FAILURE, "Bad/invalid preload value: "
"%s", optarg);
#if INT_MAX < LONG_MAX
if (l > INT_MAX)
errx(EXIT_FAILURE,
"Too many preload packets: %ld", l);
#endif
preload = l;
break;
case 'n':
pingflags |= F_NUMERIC;