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 */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to