From nobody Tue Nov 29 22:55:20 2022 X-Original-To: dev-commits-src-main@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 4NMHjh4gspz4hmKN; Tue, 29 Nov 2022 22:55:20 +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 4NMHjh3yKgz3rdJ; Tue, 29 Nov 2022 22:55:20 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1669762520; 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=7Iq+y8rSo//aE1hrKdGInMV3seCbAqT2jrZIRU+7gT0=; b=iq+T8OK2ffHXh6PvwzRczSQx7ycSU3OlISk/0Sbw4gPd3gLIOfhDoQD4Gmw6jAKKv60oRx v9UC6IQrZQNZ+4FstoH+1b+NfucHw9WuBYj6SrH7Hid0mdy6Te4AR8KidXagAoMy/0WIu1 0mtNTF74dZjo4wptheBW4kO3fYb50F7BMKLVe5C8mWo9qP2jTrnuVSA/m7XRlsAiK9LPvq KWkiovUwF7w9bne8kdjIcpIoz+Ao5syZB2ZgCRIXnMYnHDU3UreZe7jET80Sv+F2T2XIH1 6Z8CpwU+Ql754ocR1+P4LcQY4pKfnrdDuhWIL9PRd4EXwLkQR2Dsmc2fVvr2tQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1669762520; 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=7Iq+y8rSo//aE1hrKdGInMV3seCbAqT2jrZIRU+7gT0=; b=oFc5uSndHh5d+SQUSjQV5FCAzfB7reCm5bqRrJIcUyoqzSAA29NWMG69E4TCuUitM51P7i pDok4712qw1noMS6lT3Xhs3Gv0gKuBD9SpPu34TOssFkR9S6s5b3LiuWJ4Sr7Bon1kFrSE lAYoQZgTu7CLyyF8spEwfH+gtXmT+d8iRc/9jP2g53fhsIBhsurkcolUVFaz7rZuR5UehL 4QjHivDmKCqFVW9zIQS41CMVfUNXEnlSl60YRNr/UC0WxWZZW7UiqOHicNM3TLd6TPZOC4 atWr/kEVB/b4mx12COJVtEnwja8ciy+vky0RFQxfn0ZSlG6Pq8fjU39L9HMGCw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1669762520; a=rsa-sha256; cv=none; b=nmRNWFb+n+bI+/6vDHct0vm27FRnkiJBbGXrHN3JkFFQdNTqq6h/mTf8j2Vv8MLUhlkKga ANgSTA8j993XxMvYrXh3064ufPb0upyVT+xRV6kHToadevwYNPQjBFzkXGqcry3X3y7Fbo 1E4KULunuMzFZKew/H0k0Ez7R1ifmZcBoOv21+qtIsuajqQ9t8EoskSOsbTFQwy53oqO9N TTQ0acyP+9nrGCrDU+rUrU8pClKnzLuzY0PMmWvtqr3WeUkKZJhVcSwRBFvNIUmCGCuEsT 4zxwHSv00qFcKdb9TOkKdlmyGpwau3ZQd14LgZPi4Zk1l4BcBfhfc1OjW2MHYQ== 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 4NMHjh2mnCzZMK; Tue, 29 Nov 2022 22:55:20 +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 2ATMtKSJ097686; Tue, 29 Nov 2022 22:55:20 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 2ATMtKi9097685; Tue, 29 Nov 2022 22:55:20 GMT (envelope-from git) Date: Tue, 29 Nov 2022 22:55:20 GMT Message-Id: <202211292255.2ATMtKi9097685@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Gordon Tetlow Subject: git: 46d7b45a267b - main - ping: Fix handling of IP packet sizes List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@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/main X-Git-Reftype: branch X-Git-Commit: 46d7b45a267b3d78c5054b210ff7b6c55bfca42b Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by gordon: URL: https://cgit.FreeBSD.org/src/commit/?id=46d7b45a267b3d78c5054b210ff7b6c55bfca42b commit 46d7b45a267b3d78c5054b210ff7b6c55bfca42b Author: Tom Jones AuthorDate: 2022-11-17 10:31:38 +0000 Commit: Gordon Tetlow CommitDate: 2022-11-29 22:51:50 +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 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 --- 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 4c4326f98f61..6956b9a68ad2 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -963,6 +963,9 @@ ping(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 && @@ -1144,8 +1147,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]; @@ -1155,15 +1160,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) @@ -1175,6 +1192,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 @@ -1304,12 +1322,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) &&