Fix potential use-after-frees in FreeBSD getpages and setattr VOPs

The objset object is reallocated during certain dataset operations, such
as rollbacks, so the objset pointer must be loaded after acquiring the
teardown lock.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@ixsystems.com>
Signed-off-by: Mark Johnston <markj@FreeBSD.org>
Closes #12704
This commit is contained in:
Mark Johnston 2021-10-28 11:58:57 -04:00 committed by Tony Hutter
parent 6ed7d77b44
commit 07165ce540
1 changed files with 4 additions and 4 deletions

View File

@ -2222,7 +2222,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
{ {
vnode_t *vp = ZTOV(zp); vnode_t *vp = ZTOV(zp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs; zfsvfs_t *zfsvfs = zp->z_zfsvfs;
objset_t *os = zfsvfs->z_os; objset_t *os;
zilog_t *zilog; zilog_t *zilog;
dmu_tx_t *tx; dmu_tx_t *tx;
vattr_t oldva; vattr_t oldva;
@ -2257,6 +2257,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
ZFS_ENTER(zfsvfs); ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp); ZFS_VERIFY_ZP(zp);
os = zfsvfs->z_os;
zilog = zfsvfs->z_log; zilog = zfsvfs->z_log;
/* /*
@ -4060,7 +4061,6 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
{ {
znode_t *zp = VTOZ(vp); znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs; zfsvfs_t *zfsvfs = zp->z_zfsvfs;
objset_t *os = zp->z_zfsvfs->z_os;
zfs_locked_range_t *lr; zfs_locked_range_t *lr;
vm_object_t object; vm_object_t object;
off_t start, end, obj_size; off_t start, end, obj_size;
@ -4130,8 +4130,8 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
* ZFS will panic if we request DMU to read beyond the end of the last * ZFS will panic if we request DMU to read beyond the end of the last
* allocated block. * allocated block.
*/ */
error = dmu_read_pages(os, zp->z_id, ma, count, &pgsin_b, &pgsin_a, error = dmu_read_pages(zfsvfs->z_os, zp->z_id, ma, count, &pgsin_b,
MIN(end, obj_size) - (end - PAGE_SIZE)); &pgsin_a, MIN(end, obj_size) - (end - PAGE_SIZE));
if (lr != NULL) if (lr != NULL)
zfs_rangelock_exit(lr); zfs_rangelock_exit(lr);