Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 9 May 2020 06:25:21 +0000 (UTC)
From:      Toomas Soome <tsoome@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r360836 - head/stand/libsa/zfs
Message-ID:  <202005090625.0496PLvc091232@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tsoome
Date: Sat May  9 06:25:20 2020
New Revision: 360836
URL: https://svnweb.freebsd.org/changeset/base/360836

Log:
  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.
  
  MFC after:	2 days

Modified:
  head/stand/libsa/zfs/zfs.c

Modified: head/stand/libsa/zfs/zfs.c
==============================================================================
--- head/stand/libsa/zfs/zfs.c	Sat May  9 05:04:02 2020	(r360835)
+++ head/stand/libsa/zfs/zfs.c	Sat May  9 06:25:20 2020	(r360836)
@@ -418,7 +418,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 = malloc(secsz);
 		if (bouncebuf == NULL) {
 			printf("vdev_read: out of memory\n");
@@ -442,14 +442,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?202005090625.0496PLvc091232>