Commit 8e1b549d authored by Ryusuke Konishi's avatar Ryusuke Konishi Committed by Zeng Heng
Browse files

nilfs2: fix missing cleanup on rollforward recovery error

stable inclusion
from stable-v6.6.51
commit 9d8c3a585d564d776ee60d4aabec59b404be7403
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IARYB6
CVE: CVE-2024-46781

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=9d8c3a585d564d776ee60d4aabec59b404be7403

--------------------------------

commit 5787fcaab9eb5930f5378d6a1dd03d916d146622 upstream.

In an error injection test of a routine for mount-time recovery, KASAN
found a use-after-free bug.

It turned out that if data recovery was performed using partial logs
created by dsync writes, but an error occurred before starting the log
writer to create a recovered checkpoint, the inodes whose data had been
recovered were left in the ns_dirty_files list of the nilfs object and
were not freed.

Fix this issue by cleaning up inodes that have read the recovery data if
the recovery routine fails midway before the log writer starts.

Link: https://lkml.kernel.org/r/20240810065242.3701-1-konishi.ryusuke@gmail.com


Fixes: 0f3e1c7f ("nilfs2: recovery functions")
Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@gmail.com>
Tested-by: default avatarRyusuke Konishi <konishi.ryusuke@gmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarZeng Heng <zengheng4@huawei.com>
parent 81a41d2a
Loading
Loading
Loading
Loading
+33 −2
Original line number Diff line number Diff line
@@ -708,6 +708,33 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
	brelse(bh);
}

/**
 * nilfs_abort_roll_forward - cleaning up after a failed rollforward recovery
 * @nilfs: nilfs object
 */
static void nilfs_abort_roll_forward(struct the_nilfs *nilfs)
{
	struct nilfs_inode_info *ii, *n;
	LIST_HEAD(head);

	/* Abandon inodes that have read recovery data */
	spin_lock(&nilfs->ns_inode_lock);
	list_splice_init(&nilfs->ns_dirty_files, &head);
	spin_unlock(&nilfs->ns_inode_lock);
	if (list_empty(&head))
		return;

	set_nilfs_purging(nilfs);
	list_for_each_entry_safe(ii, n, &head, i_dirty) {
		spin_lock(&nilfs->ns_inode_lock);
		list_del_init(&ii->i_dirty);
		spin_unlock(&nilfs->ns_inode_lock);

		iput(&ii->vfs_inode);
	}
	clear_nilfs_purging(nilfs);
}

/**
 * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
 * @nilfs: nilfs object
@@ -766,15 +793,19 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
		if (unlikely(err)) {
			nilfs_err(sb, "error %d writing segment for recovery",
				  err);
			goto failed;
			goto put_root;
		}

		nilfs_finish_roll_forward(nilfs, ri);
	}

 failed:
put_root:
	nilfs_put_root(root);
	return err;

failed:
	nilfs_abort_roll_forward(nilfs);
	goto put_root;
}

/**