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>