git: ed4f9a251868 - releng/13.2 - ping: Fix unsigned integer underflow resuling in a ping -R segfault

From: Cy Schubert <cy_at_FreeBSD.org>
Date: Mon, 27 Feb 2023 18:47:25 UTC
The branch releng/13.2 has been updated by cy:

URL: https://cgit.FreeBSD.org/src/commit/?id=ed4f9a251868149dd738640568b2fc48338b39e1

commit ed4f9a251868149dd738640568b2fc48338b39e1
Author:     Cy Schubert <cy@FreeBSD.org>
AuthorDate: 2023-02-23 05:43:17 +0000
Commit:     Cy Schubert <cy@FreeBSD.org>
CommitDate: 2023-02-27 18:46:42 +0000

    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.
    
    Approved by:    re (cperciva)
    Reviewed by:    asomers
    Fixes:          46d7b45a267b
    Differential Revision:  https://reviews.freebsd.org/D38744
    
    (cherry picked from commit 70960bb86a3ba5b6f5c4652e613e6313a7ed1ac1)
    (cherry picked from commit 18936d3526f3090e4164b8155762bf5bd54038a8)
---
 sbin/ping/ping.c | 4 ++--
 1 file 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));