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