From c6dab6dd39214d587c7013e8c6dfeb085e3eb41c Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Thu, 19 Jan 2023 16:59:05 -0800 Subject: Fix unprotected zfs_znode_dmu_fini In original code, zfs_znode_dmu_fini is called in zfs_rmnode without zfs_znode_hold_enter. It seems to assume it's ok to do so when the znode is unlinked. However this assumption is not correct, as zfs_zget can be called by NFS through zpl_fh_to_dentry as pointed out by Christian in https://github.com/openzfs/zfs/pull/12767, which could result in a use-after-free bug. Reviewed-by: Brian Behlendorf Co-authored-by: Ryan Moeller Signed-off-by: Chunwei Chen Signed-off-by: Ryan Moeller Closes #12767 Closes #14364 --- module/os/linux/zfs/zfs_dir.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'module/os/linux/zfs/zfs_dir.c') diff --git a/module/os/linux/zfs/zfs_dir.c b/module/os/linux/zfs/zfs_dir.c index 09eac37f9..1fec4ea09 100644 --- a/module/os/linux/zfs/zfs_dir.c +++ b/module/os/linux/zfs/zfs_dir.c @@ -649,6 +649,8 @@ zfs_rmnode(znode_t *zp) objset_t *os = zfsvfs->z_os; znode_t *xzp = NULL; dmu_tx_t *tx; + znode_hold_t *zh; + uint64_t z_id = zp->z_id; uint64_t acl_obj; uint64_t xattr_obj; uint64_t links; @@ -666,8 +668,9 @@ zfs_rmnode(znode_t *zp) * Not enough space to delete some xattrs. * Leave it in the unlinked set. */ + zh = zfs_znode_hold_enter(zfsvfs, z_id); zfs_znode_dmu_fini(zp); - + zfs_znode_hold_exit(zfsvfs, zh); return; } } @@ -686,7 +689,9 @@ zfs_rmnode(znode_t *zp) * Not enough space or we were interrupted by unmount. * Leave the file in the unlinked set. */ + zh = zfs_znode_hold_enter(zfsvfs, z_id); zfs_znode_dmu_fini(zp); + zfs_znode_hold_exit(zfsvfs, zh); return; } } @@ -726,7 +731,9 @@ zfs_rmnode(znode_t *zp) * which point we'll call zfs_unlinked_drain() to process it). */ dmu_tx_abort(tx); + zh = zfs_znode_hold_enter(zfsvfs, z_id); zfs_znode_dmu_fini(zp); + zfs_znode_hold_exit(zfsvfs, zh); goto out; } -- cgit v1.2.3