lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <174786677584.1383760.1107858755678329558.stgit@frogsfrogsfrogs>
Date: Wed, 21 May 2025 15:35:26 -0700
From: "Darrick J. Wong" <djwong@...nel.org>
To: tytso@....edu
Cc: linux-ext4@...r.kernel.org, linux-ext4@...r.kernel.org
Subject: [PATCH 02/29] libext2fs: fix livelock in the unix io manager

From: Darrick J. Wong <djwong@...nel.org>

generic/441 found a livelock in the unix IO manager.  Let's say that
write_primary_superblock decides to call io_channel_set_blksize in the
process of writing the primary super.

unix_set_blksize then takes the cache and bounce mutexes, and calls
flush_cached_blocks.  If there are dirty blocks in the cache, they will
be written with raw_write_blk.  Unfortunately, that function tries to
take the bounce mutex, which we already hold.  At that point, we
livelock fuse2fs.

Cc: <linux-ext4@...r.kernel.org> # v1.46.0
Fixes: f20627cc639ab6 ("libext2fs: add threading support to the I/O manager abstraction")
Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
---
 lib/ext2fs/unix_io.c |   25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)


diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index b98c44a84bb0af..be70fee38890c8 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -344,7 +344,8 @@ static errcode_t raw_read_blk(io_channel channel,
 	return retval;
 }
 
-#define RAW_WRITE_NO_HANDLER	1
+#define RAW_WRITE_NO_HANDLER	(1U << 0)
+#define RAW_WRITE_NOLOCK	(1U << 1)
 
 static errcode_t raw_write_blk(io_channel channel,
 			       struct unix_private_data *data,
@@ -404,13 +405,15 @@ static errcode_t raw_write_blk(io_channel channel,
 	    (IS_ALIGNED(buf, channel->align) &&
 	     IS_ALIGNED(location, channel->align) &&
 	     IS_ALIGNED(size, channel->align))) {
-		mutex_lock(data, BOUNCE_MTX);
+		if (!(flags & RAW_WRITE_NOLOCK))
+			mutex_lock(data, BOUNCE_MTX);
 		if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) {
 			retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
 			goto error_unlock;
 		}
 		actual = write(data->dev, buf, size);
-		mutex_unlock(data, BOUNCE_MTX);
+		if (!(flags & RAW_WRITE_NOLOCK))
+			mutex_unlock(data, BOUNCE_MTX);
 		if (actual < 0) {
 			retval = errno;
 			goto error_out;
@@ -445,7 +448,8 @@ static errcode_t raw_write_blk(io_channel channel,
 	while (size > 0) {
 		int actual_w;
 
-		mutex_lock(data, BOUNCE_MTX);
+		if (!(flags & RAW_WRITE_NOLOCK))
+			mutex_lock(data, BOUNCE_MTX);
 		if (size < align_size || offset) {
 			if (ext2fs_llseek(data->dev, aligned_blk * align_size,
 					  SEEK_SET) < 0) {
@@ -474,7 +478,8 @@ static errcode_t raw_write_blk(io_channel channel,
 			goto error_unlock;
 		}
 		actual_w = write(data->dev, data->bounce, align_size);
-		mutex_unlock(data, BOUNCE_MTX);
+		if (!(flags & RAW_WRITE_NOLOCK))
+			mutex_unlock(data, BOUNCE_MTX);
 		if (actual_w < 0) {
 			retval = errno;
 			goto error_out;
@@ -490,7 +495,8 @@ static errcode_t raw_write_blk(io_channel channel,
 	return 0;
 
 error_unlock:
-	mutex_unlock(data, BOUNCE_MTX);
+	if (!(flags & RAW_WRITE_NOLOCK))
+		mutex_unlock(data, BOUNCE_MTX);
 error_out:
 	if (((flags & RAW_WRITE_NO_HANDLER) == 0) && channel->write_error)
 		retval = (channel->write_error)(channel, block, count, buf,
@@ -673,9 +679,14 @@ static errcode_t flush_cached_blocks(io_channel channel,
 		if (!cache->in_use)
 			continue;
 		if (cache->dirty) {
+			int raw_flags = RAW_WRITE_NO_HANDLER;
+
+			if (flags & FLUSH_NOLOCK)
+				raw_flags |= RAW_WRITE_NOLOCK;
+
 			retval = raw_write_blk(channel, data,
 					       cache->block, 1, cache->buf,
-					       RAW_WRITE_NO_HANDLER);
+					       raw_flags);
 			if (retval) {
 				cache->write_err = 1;
 				errors_found = 1;


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ