Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 May 2020 07:01:10 +0000 (UTC)
From:      Toomas Soome <tsoome@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r360891 - stable/11/stand/libsa/zfs
Message-ID:  <202005110701.04B71ATl096239@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tsoome
Date: Mon May 11 07:01:10 2020
New Revision: 360891
URL: https://svnweb.freebsd.org/changeset/base/360891

Log:
  MFC r360836:
  
  loader: vdev_read() can corrupt memory
  
  When reading less than sector size but from sector boundary,
  the vdev_read() will read full sector into the provided buffer
  and therefore corrupting memory past buffer end.

Modified:
  stable/11/stand/libsa/zfs/zfs.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/stand/libsa/zfs/zfs.c
==============================================================================
--- stable/11/stand/libsa/zfs/zfs.c	Mon May 11 06:59:01 2020	(r360890)
+++ stable/11/stand/libsa/zfs/zfs.c	Mon May 11 07:01:10 2020	(r360891)
@@ -417,7 +417,7 @@ vdev_read(vdev_t *vdev, void *priv, off_t offset, void
 		full_sec_size -= secsz;
 
 	/* Return of partial sector data requires a bounce buffer. */
-	if ((head > 0) || do_tail_read) {
+	if ((head > 0) || do_tail_read || bytes < secsz) {
 		bouncebuf = zfs_alloc(secsz);
 		if (bouncebuf == NULL) {
 			printf("vdev_read: out of memory\n");
@@ -441,14 +441,28 @@ vdev_read(vdev_t *vdev, void *priv, off_t offset, void
 		outbuf += min(secsz - head, bytes);
 	}
 
-	/* Full data return from read sectors */
+	/*
+	 * Full data return from read sectors.
+	 * Note, there is still corner case where we read
+	 * from sector boundary, but less than sector size, e.g. reading 512B
+	 * from 4k sector.
+	 */
 	if (full_sec_size > 0) {
-		res = read(fd, outbuf, full_sec_size);
-		if (res != full_sec_size) {
-			ret = EIO;
-			goto error;
+		if (bytes < full_sec_size) {
+			res = read(fd, bouncebuf, secsz);
+			if (res != secsz) {
+				ret = EIO;
+				goto error;
+			}
+			memcpy(outbuf, bouncebuf, bytes);
+		} else {
+			res = read(fd, outbuf, full_sec_size);
+			if (res != full_sec_size) {
+				ret = EIO;
+				goto error;
+			}
+			outbuf += full_sec_size;
 		}
-		outbuf += full_sec_size;
 	}
 
 	/* Partial data return from last sector */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202005110701.04B71ATl096239>