mirror of
https://github.com/libfuse/libfuse.git
synced 2026-07-07 14:47:41 +08:00
memfs_ll: fix rename overwrite use-after-free and nlink double-decrement
When memfs_rename overwrites an existing target, it called remove_child(newname) -- which deletes the matched Dentry -- and then dereferenced existing_dentry again via existing_dentry->get_inode() to decrement the replaced inode's nlink, reading the freed Dentry: a use-after-free. Resolve the target inode before remove_child and use the saved pointer afterwards; the inode stays alive through the Inodes map reference. The same branch also decremented newparent's nlink twice when the target was a directory: once explicitly and again inside remove_child(), which already decrements a directory's parent. A directory-over-directory rename therefore left newparent's link count one too low (rmdir decrements the parent exactly once, via remove_child). Drop the redundant explicit decrement. Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
This commit is contained in:
+5
-5
@@ -958,15 +958,15 @@ static void memfs_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
|
||||
existing_dentry = newparentInode->find_child_locked(newname);
|
||||
if (existing_dentry) {
|
||||
if (existing_dentry->is_dir()) {
|
||||
if (!existing_dentry->get_inode()->is_empty()) {
|
||||
Inode *existing_inode = existing_dentry->get_inode();
|
||||
if (existing_inode->is_dir() && !existing_inode->is_empty()) {
|
||||
error = ENOTEMPTY;
|
||||
goto out_unlock;
|
||||
}
|
||||
newparentInode->dec_nlink();
|
||||
}
|
||||
// remove_child() frees the dentry and already decrements
|
||||
// newparent's nlink for a dir child; resolve the inode first.
|
||||
newparentInode->remove_child(newname);
|
||||
existing_dentry->get_inode()->dec_nlink();
|
||||
existing_inode->dec_nlink();
|
||||
}
|
||||
|
||||
child_dentry_copy = new Dentry(newname, child_dentry->inode);
|
||||
|
||||
Reference in New Issue
Block a user