aboutsummaryrefslogtreecommitdiffstats
path: root/module/os/linux/zfs/zfs_dir.c
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2023-01-19 16:59:05 -0800
committerGitHub <[email protected]>2023-01-19 16:59:05 -0800
commitc6dab6dd39214d587c7013e8c6dfeb085e3eb41c (patch)
treec0ec00fc4945800b7b8103d2abb3a42a26e9763e /module/os/linux/zfs/zfs_dir.c
parenta379083d9f2bb9dd80f4636e593bcb2c1d94d11b (diff)
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 <[email protected]> Co-authored-by: Ryan Moeller <[email protected]> Signed-off-by: Chunwei Chen <[email protected]> Signed-off-by: Ryan Moeller <[email protected]> Closes #12767 Closes #14364
Diffstat (limited to 'module/os/linux/zfs/zfs_dir.c')
-rw-r--r--module/os/linux/zfs/zfs_dir.c9
1 files changed, 8 insertions, 1 deletions
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;
}