aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2023-02-23 05:43:17 +0000
committerCy Schubert <cy@FreeBSD.org>2023-02-24 14:50:53 +0000
commit70960bb86a3ba5b6f5c4652e613e6313a7ed1ac1 (patch)
treee9ca5dc6a2b9e39a02adcac39db34f5a289e8484
parentae4387d724e2661e5e4ee7743954ffaa9ac01275 (diff)
downloadsrc-70960bb86a3ba5b6f5c4652e613e6313a7ed1ac1.tar.gz
src-70960bb86a3ba5b6f5c4652e613e6313a7ed1ac1.zip
ping: Fix unsigned integer underflow resuling in a ping -R segfault
ping -R (F_RROUTE) will loop at ping.c:1381 until it segfaults or the unsigned int hlen happens to be less than the size of an IP header: slippy$ ping -R 192.168.0.101 PING 192.168.0.101 (192.168.0.101): 56 data bytes 64 bytes from 192.168.0.101: icmp_seq=0 ttl=63 time=1.081 ms RR: 192.168.0.1 192.168.0.101 192.168.0.101 10.1.1.254 10.1.1.91 unknown option bb unknown option 32 unknown option 6 ... unknown option 96 unknown option 2d Segmentation fault The reason for this is while looping through loose source routing (LSRR) and strict source routing (SSRR), hlen will become smaller than the IP header. It may even become negative. This should terminate the loop. However, when hlen is unsigned, an integer underflow occurs becoming a large number causing the loop to continue virtually forever until hlen is either by chance smaller than the lenghth of an IP header or it segfaults. Reviewed by: asomers Fixes: 46d7b45a267b MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D38744
-rw-r--r--sbin/ping/ping.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
index 6956b9a68ad2..2fc876e50776 100644
--- a/sbin/ping/ping.c
+++ b/sbin/ping/ping.c
@@ -1150,7 +1150,7 @@ pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv)
ssize_t icmp_data_raw_len;
double triptime;
int dupflag, i, j, recv_len;
- uint8_t hlen;
+ int8_t hlen;
uint16_t seq;
static int old_rrlen;
static char old_rr[MAX_IPOPTLEN];
@@ -1171,7 +1171,7 @@ pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv)
hlen = (l & 0x0f) << 2;
/* Reject IP packets with a short header */
- if (hlen < sizeof(struct ip)) {
+ if (hlen < (int8_t) sizeof(struct ip)) {
if (options & F_VERBOSE)
warn("IHL too short (%d bytes) from %s", hlen,
inet_ntoa(from->sin_addr));