From nobody Wed Nov 08 00:45:54 2023 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 4SQ5wy682kz4yvLm; Wed, 8 Nov 2023 00:45:54 +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 4SQ5wy5N3Hz3R83; Wed, 8 Nov 2023 00:45:54 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1699404354; 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=/TqTekpTpzNEss4luzw/5b7nZ+4P2bRA41BuN+CGsFo=; b=i1X+ZOjlpRGy5p6o2Spa3UHMuxX7unxEmNSPMGJr3qVti7cYyZ+oj19DwDg+7IN6bknPwX ohQ8v1rjlFZwbxf37N89DU2341gqo3DzbJzG4lNyEpUk6U1vyBq9jL7nfl0uC/FAriUg9u CzdrSaPQQ7RiX1gqk6tBag1MzCdJE8UjcIj1VO1UMkG/oZ4IH8NJTTpDwGcbSFu1mT06zE IL1Ywx8N/yWRK4KJQEAcuigX89BTU83/aZ87fJ4EJCTvGxU/Q6fQURn2GTcFNk8myrM3Fv I7Jwfc8nmY1sNyIUGlyNn0r1/xwMwKlUNn3Xo6OLcEh4hiWiGzgqd0x9hWvOgA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1699404354; 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=/TqTekpTpzNEss4luzw/5b7nZ+4P2bRA41BuN+CGsFo=; b=J4CJK0laGpIxGfWDGV5+tsM3aD1LwN0sHz+FdPdJ8xNflIOHndZrVfSlYklWcd+lyCWgo5 xQNMy6vSjWnROXXJ0NdWTj93DSGVZZkRY0J4cA273avDaIxVZ3TkEn0fDuMpJB3IpBmEWI 4MOtwHzqynU5vX2s7MeuLGZ4rs5uG7ECnlRjZL6al/E01DCv9iXmcJ4yov52cmg83q3cSu OiBxwdRXmrILAWl1CwL/In7dbog0LCDupmWx5d4GFJk7XCnDaIXcTm1xPV8yEUNjmkal0m jMp/klHL9kPjoinSzvyg/oQcPJpaG9JhA4qUwJS72WHs0hIrYS11DdMByCSWwg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1699404354; a=rsa-sha256; cv=none; b=MGp289IbbQ7eT4GqtebEyt59lUwzvfax7YSTlYIFK9I5A8NPHEIxGbykPa2yzEDMhbpP52 stTPpD7PNVPD9jhGtANpZHeyahuPc3AVCqCIuL3J1R2bVccEVf++egmht4ndRvYmqw21SG oYlw/kq1wZ9kEQRidaUaSMr5OPWTilE9GTHhIBowuBQy7DWQK7CGHIGEBsc5vLWvYc6Nic da8dwfmFbUIOoE6Ja9/kju7WUP1X2bp5UbYBCm5X9fS8ewKsBcG9yKWwpSaOiu9KSmA3Dx HTvGPb7GHrZpTsXpntlLtvyapGmFXTJpPvIgxQcocrBeLNminUpnLkcYZmcwew== 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 4SQ5wy4SB6z1BQf; Wed, 8 Nov 2023 00:45:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 3A80jsKD071168; Wed, 8 Nov 2023 00:45:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 3A80jsVZ071165; Wed, 8 Nov 2023 00:45:54 GMT (envelope-from git) Date: Wed, 8 Nov 2023 00:45:54 GMT Message-Id: <202311080045.3A80jsVZ071165@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Ed Maste Subject: git: 1f9c4610dde5 - releng/14.0 - fflush: correct buffer handling in __sflush 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: emaste X-Git-Repository: src X-Git-Refname: refs/heads/releng/14.0 X-Git-Reftype: branch X-Git-Commit: 1f9c4610dde5ecda4ad219b19f16ec712bc1d793 Auto-Submitted: auto-generated The branch releng/14.0 has been updated by emaste: URL: https://cgit.FreeBSD.org/src/commit/?id=1f9c4610dde5ecda4ad219b19f16ec712bc1d793 commit 1f9c4610dde5ecda4ad219b19f16ec712bc1d793 Author: Dag-Erling Smørgrav AuthorDate: 2023-08-03 15:08:03 +0000 Commit: Ed Maste CommitDate: 2023-11-08 00:45:25 +0000 fflush: correct buffer handling in __sflush This fixes CVE-2014-8611 correctly. The commit that purported to fix CVE-2014-8611 (805288c2f062) only hid it behind another bug. Two later commits, 86a16ada1ea6 and 44cf1e5eb470, attempted to address this new bug but mostly just confused the issue. This commit rolls back the three previous changes and fixes CVE-2014-8611 correctly. The key to understanding the bug (and the fix) is that `_w` has different meanings for different stream modes. If the stream is unbuffered, it is always zero. If the stream is fully buffered, it is the amount of space remaining in the buffer (equal to the buffer size when the buffer is empty and zero when the buffer is full). If the stream is line-buffered, it is a negative number reflecting the amount of data in the buffer (zero when the buffer is empty and negative buffer size when the buffer is full). At the heart of `fflush()`, we call the stream's write function in a loop, where `t` represents the return value from the last call and `n` the amount of data that remains to be written. When the write function fails, we need to move the unwritten data to the top of the buffer (unless nothing was written) and adjust `_p` (which points to the next free location in the buffer) and `_w` accordingly. These variables have already been set to the values they should have after a successful flush, so instead of adjusting them down to reflect what was written, we're adjusting them up to reflect what remains. The bug was that while `_p` was always adjusted, we only adjusted `_w` if the stream was fully buffered. The fix is to also adjust `_w` for line-buffered streams. Everything else is just noise. Fixes: 805288c2f062 Fixes: 86a16ada1ea6 Fixes: 44cf1e5eb470 Sponsored by: Klara, Inc. (cherry picked from commit 1f90b4edffe815aebb35e74b79e10593b31f6b75) (cherry picked from commit 1e99535be2ea9c0ef8bc57fc885e9c01fa95d2dd) (cherry picked from commit d09a3bf72c0b5f1779c52269671872368c99f02a) (cherry picked from commit 92709431b14df6c0687446247ac57cfc189ee827) (cherry picked from commit 418f026bd5a5084c1c4e2e91ad38051f6caa928c) (cherry picked from commit abe12d2f4ce31c3da0961b1b0a58df11f5a41e19) (cherry picked from commit 4e0e01bf6511c28212d7dff94fe131a502e13026) (cherry picked from commit d2c65a1c948648f11342274029a3f18b90aa58d2) Approved by: so Approved by: re (implicit) Security: FreeBSD-SA-23:15.stdio Sponsored by: The FreeBSD Foundation --- lib/libc/stdio/fflush.c | 27 ++++++++++----------------- lib/libc/stdio/fvwrite.c | 14 ++------------ lib/libc/stdio/wbuf.c | 12 ++---------- 3 files changed, 14 insertions(+), 39 deletions(-) diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c index a7f9348def50..61f23335106f 100644 --- a/lib/libc/stdio/fflush.c +++ b/lib/libc/stdio/fflush.c @@ -103,11 +103,11 @@ __weak_reference(__fflush, fflush_unlocked); int __sflush(FILE *fp) { - unsigned char *p, *old_p; - int n, t, old_w; + unsigned char *p; + int n, f, t; - t = fp->_flags; - if ((t & __SWR) == 0) + f = fp->_flags; + if ((f & __SWR) == 0) return (0); if ((p = fp->_bf._base) == NULL) @@ -119,26 +119,19 @@ __sflush(FILE *fp) * Set these immediately to avoid problems with longjmp and to allow * exchange buffering (via setvbuf) in user write function. */ - old_p = fp->_p; fp->_p = p; - old_w = fp->_w; - fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size; + fp->_w = f & (__SLBF|__SNBF) ? 0 : fp->_bf._size; for (; n > 0; n -= t, p += t) { t = _swrite(fp, (char *)p, n); if (t <= 0) { - /* Reset _p and _w. */ - if (p > fp->_p) { + if (p > fp->_p) /* Some was written. */ memmove(fp->_p, p, n); - fp->_p += n; - if ((fp->_flags & (__SLBF | __SNBF)) == 0) - fp->_w -= n; - /* conditional to handle setvbuf */ - } else if (p == fp->_p && errno == EINTR) { - fp->_p = old_p; - fp->_w = old_w; - } + /* Reset _p and _w. */ + fp->_p += n; + if ((fp->_flags & __SNBF) == 0) + fp->_w -= n; fp->_flags |= __SERR; return (EOF); } diff --git a/lib/libc/stdio/fvwrite.c b/lib/libc/stdio/fvwrite.c index 81e7ba89a644..acf8f72076cf 100644 --- a/lib/libc/stdio/fvwrite.c +++ b/lib/libc/stdio/fvwrite.c @@ -36,7 +36,6 @@ static char sccsid[] = "@(#)fvwrite.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include -#include #include #include #include @@ -53,7 +52,6 @@ int __sfvwrite(FILE *fp, struct __suio *uio) { size_t len; - unsigned char *old_p; char *p; struct __siov *iov; int w, s; @@ -137,12 +135,8 @@ __sfvwrite(FILE *fp, struct __suio *uio) COPY(w); /* fp->_w -= w; */ /* unneeded */ fp->_p += w; - old_p = fp->_p; - if (__fflush(fp) == EOF) { - if (old_p == fp->_p && errno == EINTR) - fp->_p -= w; + if (__fflush(fp)) goto err; - } } else if (len >= (w = fp->_bf._size)) { /* write directly */ w = _swrite(fp, p, w); @@ -181,12 +175,8 @@ __sfvwrite(FILE *fp, struct __suio *uio) COPY(w); /* fp->_w -= w; */ fp->_p += w; - old_p = fp->_p; - if (__fflush(fp) == EOF) { - if (old_p == fp->_p && errno == EINTR) - fp->_p -= w; + if (__fflush(fp)) goto err; - } } else if (s >= (w = fp->_bf._size)) { w = _swrite(fp, p, w); if (w <= 0) diff --git a/lib/libc/stdio/wbuf.c b/lib/libc/stdio/wbuf.c index acbe379ad90e..558322b4001e 100644 --- a/lib/libc/stdio/wbuf.c +++ b/lib/libc/stdio/wbuf.c @@ -50,7 +50,6 @@ static char sccsid[] = "@(#)wbuf.c 8.1 (Berkeley) 6/4/93"; int __swbuf(int c, FILE *fp) { - unsigned char *old_p; int n; /* @@ -86,15 +85,8 @@ __swbuf(int c, FILE *fp) } fp->_w--; *fp->_p++ = c; - old_p = fp->_p; - if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) { - if (__fflush(fp) != 0) { - if (fp->_p == old_p && errno == EINTR) { - fp->_p--; - fp->_w++; - } + if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) + if (__fflush(fp) != 0) return (EOF); - } - } return (c); }