diff options
author | Chunwei Chen <[email protected]> | 2023-01-19 16:59:05 -0800 |
---|---|---|
committer | GitHub <[email protected]> | 2023-01-19 16:59:05 -0800 |
commit | c6dab6dd39214d587c7013e8c6dfeb085e3eb41c (patch) | |
tree | c0ec00fc4945800b7b8103d2abb3a42a26e9763e /module/os/linux/zfs/zfs_znode.c | |
parent | a379083d9f2bb9dd80f4636e593bcb2c1d94d11b (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_znode.c')
-rw-r--r-- | module/os/linux/zfs/zfs_znode.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index 395e2cf57..1faf25d93 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -271,7 +271,7 @@ zfs_znode_held(zfsvfs_t *zfsvfs, uint64_t obj) return (held); } -static znode_hold_t * +znode_hold_t * zfs_znode_hold_enter(zfsvfs_t *zfsvfs, uint64_t obj) { znode_hold_t *zh, *zh_new, search; @@ -304,7 +304,7 @@ zfs_znode_hold_enter(zfsvfs_t *zfsvfs, uint64_t obj) return (zh); } -static void +void zfs_znode_hold_exit(zfsvfs_t *zfsvfs, znode_hold_t *zh) { int i = ZFS_OBJ_HASH(zfsvfs, zh->zh_obj); @@ -357,7 +357,7 @@ zfs_znode_sa_init(zfsvfs_t *zfsvfs, znode_t *zp, void zfs_znode_dmu_fini(znode_t *zp) { - ASSERT(zfs_znode_held(ZTOZSB(zp), zp->z_id) || zp->z_unlinked || + ASSERT(zfs_znode_held(ZTOZSB(zp), zp->z_id) || RW_WRITE_HELD(&ZTOZSB(zp)->z_teardown_inactive_lock)); sa_handle_destroy(zp->z_sa_hdl); |