From nobody Tue Nov 29 23:18:14 2022 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4NMJD706jzz4hqM8; Tue, 29 Nov 2022 23:18:15 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4NMJD66fmqz400T; Tue, 29 Nov 2022 23:18:14 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1669763894; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=6LLBjVfKhOsIdEen04OxrfFku1W+/ajwIthdXg23HUs=; b=sNVRcTFAYLa80tLr8XBm2cQuFKONUBiSss1pfvxbHZthwP3vBRPw9A2FJXvEA3SoGS727a b2ZjOn64mqQ8qQI1GNjnP2FkQgM5ICQlzlw//zHZN6KDfhCPnfLJSFPhGmKhmQiGEe6ZwD YdTqX62C8qYF7lbjyknTYfC/9YsdKWjWJwHk47rlq65rsKTxAJ1enAwaJkN01q91rlR+KH caA0ahhfozm8OFMPY7PLKjQhYEn8VqGZgihrMhu4nJ8IF7duwL+x6ZLUb8y46vSgF8gaFq GqNgVs0LOS0Pe8N02IyCraCQ3vVoYTd9ir/DAvcW8LRof3Jr9DYZZ1wUBa4R+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1669763894; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=6LLBjVfKhOsIdEen04OxrfFku1W+/ajwIthdXg23HUs=; b=adkzDt6FACWfeuS0QpRgKIgy/YNeP6suXv3YoIjLf12FgBpDZFqBoTGoloDObz01DUCzsE uBJXqOrZ+FaQRvWUwwc7QMsRIxs3icKBXMmRr59zL1jl0xuUU/mUNTXsDzYCkRY3wVgEqD qAcOK1T0pNGkFYgcE/BzHufL1mVIsQfiAGYv8koKP7LUOyTk37OgE31Rj9FLHUu2S60MFj eso33mmZzBpSTzWQUiGQE77C9t+0fscmVYPLNeqZCo4MHGU8uJM2jFigFYOLCn8r/5Byu5 id4Y4xv6LEwIf9t684EKBB8S5DJaLWfx8MEOVBtN7s2LK9WxGb9B79udOyOurg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1669763894; a=rsa-sha256; cv=none; b=mn9jxXdAWqXJUtwpuVduxxwDRfLmWbNBZsA/AGeovV2qlias8fx4LR6w0Ob5jCyMEme3hU 4q3X2lhjfIN3zCE27EsDqgeG3oRwQUHCSTePlMU6y7gieJNqOkIDBFVqE3Pa5X99W9RcM7 nlnkooGQt1gy+BoVNtS2xybKGzcxkgOO85brkY+K3/SgSyshPVBI1UJuJHhUj4r8be4G7H 6LhIwSFh8Js2oCLVP5+/7LVdNgS5Qyo+1ChHHnroxe6rUe5b2AjNvaV2bFanh1ag/jpG48 30YPNv48fMCNGpP1RLZBD3wDnEeyMX6GhzB5ZEbaC+DuppAQ3mKG+s72zYt3Zw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4NMJD65hb8zbHc; Tue, 29 Nov 2022 23:18:14 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 2ATNIEh0028623; Tue, 29 Nov 2022 23:18:14 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 2ATNIEAJ028622; Tue, 29 Nov 2022 23:18:14 GMT (envelope-from git) Date: Tue, 29 Nov 2022 23:18:14 GMT Message-Id: <202211292318.2ATNIEAJ028622@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Gordon Tetlow Subject: git: 1d66ec7d51e9 - releng/12.4 - ping: Fix handling of IP packet sizes List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: gordon X-Git-Repository: src X-Git-Refname: refs/heads/releng/12.4 X-Git-Reftype: branch X-Git-Commit: 1d66ec7d51e9c0f1b97bf2e52c3155127cdcd624 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch releng/12.4 has been updated by gordon: URL: https://cgit.FreeBSD.org/src/commit/?id=1d66ec7d51e9c0f1b97bf2e52c3155127cdcd624 commit 1d66ec7d51e9c0f1b97bf2e52c3155127cdcd624 Author: Tom Jones AuthorDate: 2022-11-17 10:31:38 +0000 Commit: Gordon Tetlow CommitDate: 2022-11-29 23:17:20 +0000 ping: Fix handling of IP packet sizes Ping reads raw IP packets to parse ICMP responses. When reading the IP Header Len (IHL) ping was was taking the value from the provided packet without any validation. This could lead to remotely triggerable stack corruption. Validate the IHL against expected and recieved data sizes when reading from the received packet and when reading any quoted packets from within the ICMP response. Approved by: so, re (implicit) Reviewed by: markj, asomers Security: FreeBSD-SA-22:15.ping Security: CVE-2022-23093 Sponsored by: NetApp, Inc. Sponsored by: Klara, Inc. X-NetApp-PR: #77 Differential Revision: https://reviews.freebsd.org/D37195 (cherry picked from commit 46d7b45a267b3d78c5054b210ff7b6c55bfca42b) (cherry picked from commit 94395be05c14649cfc8e98551be9b2da8535637e) --- sbin/ping/ping.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index 79cdd5f78413..eda8bfbd35ea 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -947,6 +947,9 @@ main(int argc, char *const *argv) warn("recvmsg"); continue; } + /* If we have a 0 byte read from recvfrom continue */ + if (cc == 0) + continue; #ifdef SO_TIMESTAMP if (cmsg != NULL && cmsg->cmsg_level == SOL_SOCKET && @@ -1128,8 +1131,10 @@ pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) struct icmp icp; struct ip ip; const u_char *icmp_data_raw; + ssize_t icmp_data_raw_len; double triptime; - int dupflag, hlen, i, j, recv_len; + int dupflag, i, j, recv_len; + uint8_t hlen; uint16_t seq; static int old_rrlen; static char old_rr[MAX_IPOPTLEN]; @@ -1139,15 +1144,27 @@ pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) const u_char *oicmp_raw; /* - * Get size of IP header of the received packet. The - * information is contained in the lower four bits of the - * first byte. + * Get size of IP header of the received packet. + * The header length is contained in the lower four bits of the first + * byte and represents the number of 4 byte octets the header takes up. + * + * The IHL minimum value is 5 (20 bytes) and its maximum value is 15 + * (60 bytes). */ memcpy(&l, buf, sizeof(l)); hlen = (l & 0x0f) << 2; - memcpy(&ip, buf, hlen); - /* Check the IP header */ + /* Reject IP packets with a short header */ + if (hlen < sizeof(struct ip)) { + if (options & F_VERBOSE) + warn("IHL too short (%d bytes) from %s", hlen, + inet_ntoa(from->sin_addr)); + return; + } + + memcpy(&ip, buf, sizeof(struct ip)); + + /* Check packet has enough data to carry a valid ICMP header */ recv_len = cc; if (cc < hlen + ICMP_MINLEN) { if (options & F_VERBOSE) @@ -1159,6 +1176,7 @@ pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) #ifndef icmp_data icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_ip); #else + icmp_data_raw_len = cc - (hlen + offsetof(struct icmp, icmp_data)); icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_data); #endif @@ -1288,12 +1306,45 @@ pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) * as root to avoid leaking information not normally * available to those not running as root. */ + + /* + * If we don't have enough bytes for a quoted IP header and an + * ICMP header then stop. + */ + if (icmp_data_raw_len < + (ssize_t)(sizeof(struct ip) + sizeof(struct icmp))) { + if (options & F_VERBOSE) + warnx("quoted data too short (%zd bytes) from %s", + icmp_data_raw_len, inet_ntoa(from->sin_addr)); + return; + } + memcpy(&oip_header_len, icmp_data_raw, sizeof(oip_header_len)); oip_header_len = (oip_header_len & 0x0f) << 2; - memcpy(&oip, icmp_data_raw, oip_header_len); + + /* Reject IP packets with a short header */ + if (oip_header_len < sizeof(struct ip)) { + if (options & F_VERBOSE) + warnx("inner IHL too short (%d bytes) from %s", + oip_header_len, inet_ntoa(from->sin_addr)); + return; + } + + /* + * Check against the actual IHL length, to protect against + * quoated packets carrying IP options. + */ + if (icmp_data_raw_len < + (ssize_t)(oip_header_len + sizeof(struct icmp))) { + if (options & F_VERBOSE) + warnx("inner packet too short (%zd bytes) from %s", + icmp_data_raw_len, inet_ntoa(from->sin_addr)); + return; + } + + memcpy(&oip, icmp_data_raw, sizeof(struct ip)); oicmp_raw = icmp_data_raw + oip_header_len; - memcpy(&oicmp, oicmp_raw, offsetof(struct icmp, icmp_id) + - sizeof(oicmp.icmp_id)); + memcpy(&oicmp, oicmp_raw, sizeof(struct icmp)); if (((options & F_VERBOSE) && uid == 0) || (!(options & F_QUIET2) &&