Skip to content

Commit

Permalink
Fix use-after-free after unmount
Browse files Browse the repository at this point in the history
During unmount `zfsvfs` is destroyed and the pointer is zeroed in
the VCB. There is however still a copy of the pointer in the DCB.

Windows can still call into `zfs_AcquireForLazyWrite` through `CcMgr`
after unmount and this would use the already freed `zfsvfs` pointer.

To fix this we set the pointer to zero in the DCB and add a zero check
in `zfs_AcquireForLazyWrite`.

Signed-off-by: Axel Gembe <[email protected]>
  • Loading branch information
EchterAgo committed Oct 13, 2023
1 parent fee66c7 commit f848a9d
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 0 deletions.
10 changes: 10 additions & 0 deletions module/os/windows/zfs/zfs_vfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,7 @@ zfsvfs_teardown(zfsvfs_t *zfsvfs, boolean_t unmounting)
int
zfs_vfs_unmount(struct mount *mp, int mntflags, vfs_context_t context)
{
mount_t *mp_dcb = NULL;
zfsvfs_t *zfsvfs = vfs_fsprivate(mp);
objset_t *os;
char osname[MAXNAMELEN];
Expand Down Expand Up @@ -1670,6 +1671,15 @@ zfs_vfs_unmount(struct mount *mp, int mntflags, vfs_context_t context)
dmu_objset_disown(os, B_TRUE, zfsvfs);
}

mp_dcb = mp->parent_device;
if (likely(mp_dcb != NULL)) {
if (mp_dcb->type == MOUNT_TYPE_DCB) {
// dcb also has a reference to zfsvfs, we need to remove that

Check failure on line 1677 in module/os/windows/zfs/zfs_vfsops.c

View workflow job for this annotation

GitHub Actions / checkstyle

line > 80 characters
// before it is freed.
vfs_setfsprivate(mp_dcb, NULL);
}
}

zfs_freevfs(zfsvfs->z_vfs);

return (0);
Expand Down
5 changes: 5 additions & 0 deletions module/os/windows/zfs/zfs_vnops_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ zfs_AcquireForLazyWrite(void *Context, BOOLEAN Wait)
struct vnode *vp = fo->FsContext;
dprintf("%s:fo %p\n", __func__, fo);

if (unlikely(zfsvfs == NULL)) {
dprintf("%s: fo %p already freed zfsvfs\n", __func__, fo);
return (FALSE);
}

/* Confirm we are mounted, and stop unmounting */
if (vfs_busy(zfsvfs->z_vfs, 0) != 0)
return (FALSE);
Expand Down

0 comments on commit f848a9d

Please sign in to comment.