linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v6.6 00/10] Address CVE-2024-46701
@ 2025-01-24 19:19 cel
  2025-01-24 19:19 ` [RFC PATCH v6.6 01/10] libfs: Re-arrange locking in offset_iterate_dir() cel
                   ` (10 more replies)
  0 siblings, 11 replies; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

This series backports several upstream fixes to origin/linux-6.6.y
in order to address CVE-2024-46701:

  https://nvd.nist.gov/vuln/detail/CVE-2024-46701

As applied to origin/linux-6.6.y, this series passes fstests and the
git regression suite.

Before officially requesting that stable@ merge this series, I'd
like to provide an opportunity for community review of the backport
patches.

You can also find them them in the "nfsd-6.6.y" branch in

  https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git

Chuck Lever (10):
  libfs: Re-arrange locking in offset_iterate_dir()
  libfs: Define a minimum directory offset
  libfs: Add simple_offset_empty()
  libfs: Fix simple_offset_rename_exchange()
  libfs: Add simple_offset_rename() API
  shmem: Fix shmem_rename2()
  libfs: Return ENOSPC when the directory offset range is exhausted
  Revert "libfs: Add simple_offset_empty()"
  libfs: Replace simple_offset end-of-directory detection
  libfs: Use d_children list to iterate simple_offset directories

 fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |   2 +
 mm/shmem.c         |   3 +-
 3 files changed, 134 insertions(+), 48 deletions(-)

-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 01/10] libfs: Re-arrange locking in offset_iterate_dir()
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
@ 2025-01-24 19:19 ` cel
  2025-01-24 19:19 ` [RFC PATCH v6.6 02/10] libfs: Define a minimum directory offset cel
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever,
	Liam R. Howlett, Jan Kara

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 3f6d810665dfde0d33785420618ceb03fba0619d ]

Liam and Matthew say that once the RCU read lock is released,
xa_state is not safe to re-use for the next xas_find() call. But the
RCU read lock must be released on each loop iteration so that
dput(), which might_sleep(), can be called safely.

Thus we are forced to walk the offset tree with fresh state for each
directory entry. xa_find() can do this for us, though it might be a
little less efficient than maintaining xa_state locally.

We believe that in the current code base, inode->i_rwsem provides
protection for the xa_state maintained in
offset_iterate_dir(). However, there is no guarantee that will
continue to be the case in the future.

Since offset_iterate_dir() doesn't build xa_state locally any more,
there's no longer a strong need for offset_find_next(). Clean up by
rolling these two helpers together.

Suggested-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
Message-ID: <170785993027.11135.8830043889278631735.stgit@91.116.238.104.host.secureserver.net>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/170820142021.6328.15047865406275957018.stgit@91.116.238.104.host.secureserver.net
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index dc0f7519045f..430f7c95336c 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -401,12 +401,13 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
 	return vfs_setpos(file, offset, U32_MAX);
 }
 
-static struct dentry *offset_find_next(struct xa_state *xas)
+static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset)
 {
 	struct dentry *child, *found = NULL;
+	XA_STATE(xas, &octx->xa, offset);
 
 	rcu_read_lock();
-	child = xas_next_entry(xas, U32_MAX);
+	child = xas_next_entry(&xas, U32_MAX);
 	if (!child)
 		goto out;
 	spin_lock(&child->d_lock);
@@ -429,12 +430,11 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
 
 static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 {
-	struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode);
-	XA_STATE(xas, &so_ctx->xa, ctx->pos);
+	struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
 	struct dentry *dentry;
 
 	while (true) {
-		dentry = offset_find_next(&xas);
+		dentry = offset_find_next(octx, ctx->pos);
 		if (!dentry)
 			return ERR_PTR(-ENOENT);
 
@@ -443,8 +443,8 @@ static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 			break;
 		}
 
+		ctx->pos = dentry2offset(dentry) + 1;
 		dput(dentry);
-		ctx->pos = xas.xa_index + 1;
 	}
 	return NULL;
 }
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 02/10] libfs: Define a minimum directory offset
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
  2025-01-24 19:19 ` [RFC PATCH v6.6 01/10] libfs: Re-arrange locking in offset_iterate_dir() cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "libfs: Define a minimum directory offset" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 03/10] libfs: Add simple_offset_empty() cel
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever,
	Jan Kara

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 7beea725a8ca412c6190090ce7c3a13b169592a1 ]

This value is used in several places, so make it a symbolic
constant.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/170820142741.6328.12428356024575347885.stgit@91.116.238.104.host.secureserver.net
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: ecba88a3b32d ("libfs: Add simple_offset_empty()")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index 430f7c95336c..c3dc58e776f9 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -239,6 +239,11 @@ const struct inode_operations simple_dir_inode_operations = {
 };
 EXPORT_SYMBOL(simple_dir_inode_operations);
 
+/* 0 is '.', 1 is '..', so always start with offset 2 or more */
+enum {
+	DIR_OFFSET_MIN	= 2,
+};
+
 static void offset_set(struct dentry *dentry, u32 offset)
 {
 	dentry->d_fsdata = (void *)((uintptr_t)(offset));
@@ -260,9 +265,7 @@ void simple_offset_init(struct offset_ctx *octx)
 {
 	xa_init_flags(&octx->xa, XA_FLAGS_ALLOC1);
 	lockdep_set_class(&octx->xa.xa_lock, &simple_offset_xa_lock);
-
-	/* 0 is '.', 1 is '..', so always start with offset 2 */
-	octx->next_offset = 2;
+	octx->next_offset = DIR_OFFSET_MIN;
 }
 
 /**
@@ -275,7 +278,7 @@ void simple_offset_init(struct offset_ctx *octx)
  */
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
 {
-	static const struct xa_limit limit = XA_LIMIT(2, U32_MAX);
+	static const struct xa_limit limit = XA_LIMIT(DIR_OFFSET_MIN, U32_MAX);
 	u32 offset;
 	int ret;
 
@@ -480,7 +483,7 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
 		return 0;
 
 	/* In this case, ->private_data is protected by f_pos_lock */
-	if (ctx->pos == 2)
+	if (ctx->pos == DIR_OFFSET_MIN)
 		file->private_data = NULL;
 	else if (file->private_data == ERR_PTR(-ENOENT))
 		return 0;
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 03/10] libfs: Add simple_offset_empty()
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
  2025-01-24 19:19 ` [RFC PATCH v6.6 01/10] libfs: Re-arrange locking in offset_iterate_dir() cel
  2025-01-24 19:19 ` [RFC PATCH v6.6 02/10] libfs: Define a minimum directory offset cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "libfs: Add simple_offset_empty()" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 04/10] libfs: Fix simple_offset_rename_exchange() cel
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever,
	Jan Kara

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit ecba88a3b32d733d41e27973e25b2bc580f64281 ]

For simple filesystems that use directory offset mapping, rely
strictly on the directory offset map to tell when a directory has
no children.

After this patch is applied, the emptiness test holds only the RCU
read lock when the directory being tested has no children.

In addition, this adds another layer of confirmation that
simple_offset_add/remove() are working as expected.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/170820143463.6328.7872919188371286951.stgit@91.116.238.104.host.secureserver.net
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: 5a1a25be995e ("libfs: Add simple_offset_rename() API")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c         | 32 ++++++++++++++++++++++++++++++++
 include/linux/fs.h |  1 +
 mm/shmem.c         |  4 ++--
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index c3dc58e776f9..d7b901cb9af4 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -312,6 +312,38 @@ void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry)
 	offset_set(dentry, 0);
 }
 
+/**
+ * simple_offset_empty - Check if a dentry can be unlinked
+ * @dentry: dentry to be tested
+ *
+ * Returns 0 if @dentry is a non-empty directory; otherwise returns 1.
+ */
+int simple_offset_empty(struct dentry *dentry)
+{
+	struct inode *inode = d_inode(dentry);
+	struct offset_ctx *octx;
+	struct dentry *child;
+	unsigned long index;
+	int ret = 1;
+
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return ret;
+
+	index = DIR_OFFSET_MIN;
+	octx = inode->i_op->get_offset_ctx(inode);
+	xa_for_each(&octx->xa, index, child) {
+		spin_lock(&child->d_lock);
+		if (simple_positive(child)) {
+			spin_unlock(&child->d_lock);
+			ret = 0;
+			break;
+		}
+		spin_unlock(&child->d_lock);
+	}
+
+	return ret;
+}
+
 /**
  * simple_offset_rename_exchange - exchange rename with directory offsets
  * @old_dir: parent of dentry being moved
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 6c3d86532e3f..5104405ce3e6 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3197,6 +3197,7 @@ struct offset_ctx {
 void simple_offset_init(struct offset_ctx *octx);
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
+int simple_offset_empty(struct dentry *dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
 				  struct dentry *old_dentry,
 				  struct inode *new_dir,
diff --git a/mm/shmem.c b/mm/shmem.c
index db7dd45c9181..aaf679976f3b 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3368,7 +3368,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
 
 static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	if (!simple_empty(dentry))
+	if (!simple_offset_empty(dentry))
 		return -ENOTEMPTY;
 
 	drop_nlink(d_inode(dentry));
@@ -3425,7 +3425,7 @@ static int shmem_rename2(struct mnt_idmap *idmap,
 		return simple_offset_rename_exchange(old_dir, old_dentry,
 						     new_dir, new_dentry);
 
-	if (!simple_empty(new_dentry))
+	if (!simple_offset_empty(new_dentry))
 		return -ENOTEMPTY;
 
 	if (flags & RENAME_WHITEOUT) {
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 04/10] libfs: Fix simple_offset_rename_exchange()
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (2 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 03/10] libfs: Add simple_offset_empty() cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "libfs: Fix simple_offset_rename_exchange()" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 05/10] libfs: Add simple_offset_rename() API cel
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 23cdd0eed3f1fff3af323092b0b88945a7950d8e ]

User space expects the replacement (old) directory entry to have
the same directory offset after the rename.

Suggested-by: Christian Brauner <brauner@kernel.org>
Fixes: a2e459555c5f ("shmem: stable directory offsets")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20240415152057.4605-2-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index d7b901cb9af4..2029cb6a0e15 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -294,6 +294,18 @@ int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
 	return 0;
 }
 
+static int simple_offset_replace(struct offset_ctx *octx, struct dentry *dentry,
+				 long offset)
+{
+	void *ret;
+
+	ret = xa_store(&octx->xa, offset, dentry, GFP_KERNEL);
+	if (xa_is_err(ret))
+		return xa_err(ret);
+	offset_set(dentry, offset);
+	return 0;
+}
+
 /**
  * simple_offset_remove - Remove an entry to a directory's offset map
  * @octx: directory offset ctx to be updated
@@ -351,6 +363,9 @@ int simple_offset_empty(struct dentry *dentry)
  * @new_dir: destination parent
  * @new_dentry: destination dentry
  *
+ * This API preserves the directory offset values. Caller provides
+ * appropriate serialization.
+ *
  * Returns zero on success. Otherwise a negative errno is returned and the
  * rename is rolled back.
  */
@@ -368,11 +383,11 @@ int simple_offset_rename_exchange(struct inode *old_dir,
 	simple_offset_remove(old_ctx, old_dentry);
 	simple_offset_remove(new_ctx, new_dentry);
 
-	ret = simple_offset_add(new_ctx, old_dentry);
+	ret = simple_offset_replace(new_ctx, old_dentry, new_index);
 	if (ret)
 		goto out_restore;
 
-	ret = simple_offset_add(old_ctx, new_dentry);
+	ret = simple_offset_replace(old_ctx, new_dentry, old_index);
 	if (ret) {
 		simple_offset_remove(new_ctx, old_dentry);
 		goto out_restore;
@@ -387,10 +402,8 @@ int simple_offset_rename_exchange(struct inode *old_dir,
 	return 0;
 
 out_restore:
-	offset_set(old_dentry, old_index);
-	xa_store(&old_ctx->xa, old_index, old_dentry, GFP_KERNEL);
-	offset_set(new_dentry, new_index);
-	xa_store(&new_ctx->xa, new_index, new_dentry, GFP_KERNEL);
+	(void)simple_offset_replace(old_ctx, old_dentry, old_index);
+	(void)simple_offset_replace(new_ctx, new_dentry, new_index);
 	return ret;
 }
 
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 05/10] libfs: Add simple_offset_rename() API
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (3 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 04/10] libfs: Fix simple_offset_rename_exchange() cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "libfs: Add simple_offset_rename() API" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 06/10] shmem: Fix shmem_rename2() cel
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 5a1a25be995e1014abd01600479915683e356f5c ]

I'm about to fix a tmpfs rename bug that requires the use of
internal simple_offset helpers that are not available in mm/shmem.c

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20240415152057.4605-3-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c         | 21 +++++++++++++++++++++
 include/linux/fs.h |  2 ++
 mm/shmem.c         |  3 +--
 3 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index 2029cb6a0e15..15d8c3300dae 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -356,6 +356,27 @@ int simple_offset_empty(struct dentry *dentry)
 	return ret;
 }
 
+/**
+ * simple_offset_rename - handle directory offsets for rename
+ * @old_dir: parent directory of source entry
+ * @old_dentry: dentry of source entry
+ * @new_dir: parent_directory of destination entry
+ * @new_dentry: dentry of destination
+ *
+ * Caller provides appropriate serialization.
+ *
+ * Returns zero on success, a negative errno value on failure.
+ */
+int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
+			 struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir);
+	struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir);
+
+	simple_offset_remove(old_ctx, old_dentry);
+	return simple_offset_add(new_ctx, old_dentry);
+}
+
 /**
  * simple_offset_rename_exchange - exchange rename with directory offsets
  * @old_dir: parent of dentry being moved
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 5104405ce3e6..e4d139fcaad0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3198,6 +3198,8 @@ void simple_offset_init(struct offset_ctx *octx);
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
 int simple_offset_empty(struct dentry *dentry);
+int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
+			 struct inode *new_dir, struct dentry *new_dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
 				  struct dentry *old_dentry,
 				  struct inode *new_dir,
diff --git a/mm/shmem.c b/mm/shmem.c
index aaf679976f3b..ab2b0e87b051 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3434,8 +3434,7 @@ static int shmem_rename2(struct mnt_idmap *idmap,
 			return error;
 	}
 
-	simple_offset_remove(shmem_get_offset_ctx(old_dir), old_dentry);
-	error = simple_offset_add(shmem_get_offset_ctx(new_dir), old_dentry);
+	error = simple_offset_rename(old_dir, old_dentry, new_dir, new_dentry);
 	if (error)
 		return error;
 
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 06/10] shmem: Fix shmem_rename2()
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (4 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 05/10] libfs: Add simple_offset_rename() API cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "shmem: Fix shmem_rename2()" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 07/10] libfs: Return ENOSPC when the directory offset range is exhausted cel
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit ad191eb6d6942bb835a0b20b647f7c53c1d99ca4 ]

When renaming onto an existing directory entry, user space expects
the replacement entry to have the same directory offset as the
original one.

Link: https://gitlab.alpinelinux.org/alpine/aports/-/issues/15966
Fixes: a2e459555c5f ("shmem: stable directory offsets")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20240415152057.4605-4-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/libfs.c b/fs/libfs.c
index 15d8c3300dae..ab9fc182fd22 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -365,6 +365,9 @@ int simple_offset_empty(struct dentry *dentry)
  *
  * Caller provides appropriate serialization.
  *
+ * User space expects the directory offset value of the replaced
+ * (new) directory entry to be unchanged after a rename.
+ *
  * Returns zero on success, a negative errno value on failure.
  */
 int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -372,8 +375,14 @@ int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
 {
 	struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir);
 	struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir);
+	long new_offset = dentry2offset(new_dentry);
 
 	simple_offset_remove(old_ctx, old_dentry);
+
+	if (new_offset) {
+		offset_set(new_dentry, 0);
+		return simple_offset_replace(new_ctx, old_dentry, new_offset);
+	}
 	return simple_offset_add(new_ctx, old_dentry);
 }
 
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 07/10] libfs: Return ENOSPC when the directory offset range is exhausted
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (5 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 06/10] shmem: Fix shmem_rename2() cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "libfs: Return ENOSPC when the directory offset range is exhausted" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 08/10] Revert "libfs: Add simple_offset_empty()" cel
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever,
	Jeff Layton

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 903dc9c43a155e0893280c7472d4a9a3a83d75a6 ]

Testing shows that the EBUSY error return from mtree_alloc_cyclic()
leaks into user space. The ERRORS section of "man creat(2)" says:

>	EBUSY	O_EXCL was specified in flags and pathname refers
>		to a block device that is in use by the system
>		(e.g., it is mounted).

ENOSPC is closer to what applications expect in this situation.

Note that the normal range of simple directory offset values is
2..2^63, so hitting this error is going to be rare to impossible.

Fixes: 6faddda69f62 ("libfs: Add directory operations for stable offsets")
Cc: stable@vger.kernel.org # v6.9+
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Yang Erkun <yangerkun@huawei.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-2-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index ab9fc182fd22..200bcfc2ac34 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -287,8 +287,8 @@ int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
 
 	ret = xa_alloc_cyclic(&octx->xa, &offset, dentry, limit,
 			      &octx->next_offset, GFP_KERNEL);
-	if (ret < 0)
-		return ret;
+	if (unlikely(ret < 0))
+		return ret == -EBUSY ? -ENOSPC : ret;
 
 	offset_set(dentry, offset);
 	return 0;
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 08/10] Revert "libfs: Add simple_offset_empty()"
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (6 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 07/10] libfs: Return ENOSPC when the directory offset range is exhausted cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "Revert "libfs: Add simple_offset_empty()"" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 09/10] libfs: Replace simple_offset end-of-directory detection cel
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit d7bde4f27ceef3dc6d72010a20d4da23db835a32 ]

simple_empty() and simple_offset_empty() perform the same task.
The latter's use as a canary to find bugs has not found any new
issues. A subsequent patch will remove the use of the mtree for
iterating directory contents, so revert back to using a similar
mechanism for determining whether a directory is indeed empty.

Only one such mechanism is ever needed.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-3-cel@kernel.org
Reviewed-by: Yang Erkun <yangerkun@huawei.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c         | 32 --------------------------------
 include/linux/fs.h |  1 -
 mm/shmem.c         |  4 ++--
 3 files changed, 2 insertions(+), 35 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index 200bcfc2ac34..082bacf0b9e6 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -324,38 +324,6 @@ void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry)
 	offset_set(dentry, 0);
 }
 
-/**
- * simple_offset_empty - Check if a dentry can be unlinked
- * @dentry: dentry to be tested
- *
- * Returns 0 if @dentry is a non-empty directory; otherwise returns 1.
- */
-int simple_offset_empty(struct dentry *dentry)
-{
-	struct inode *inode = d_inode(dentry);
-	struct offset_ctx *octx;
-	struct dentry *child;
-	unsigned long index;
-	int ret = 1;
-
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return ret;
-
-	index = DIR_OFFSET_MIN;
-	octx = inode->i_op->get_offset_ctx(inode);
-	xa_for_each(&octx->xa, index, child) {
-		spin_lock(&child->d_lock);
-		if (simple_positive(child)) {
-			spin_unlock(&child->d_lock);
-			ret = 0;
-			break;
-		}
-		spin_unlock(&child->d_lock);
-	}
-
-	return ret;
-}
-
 /**
  * simple_offset_rename - handle directory offsets for rename
  * @old_dir: parent directory of source entry
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e4d139fcaad0..e47596d354ff 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3197,7 +3197,6 @@ struct offset_ctx {
 void simple_offset_init(struct offset_ctx *octx);
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
-int simple_offset_empty(struct dentry *dentry);
 int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
 			 struct inode *new_dir, struct dentry *new_dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
diff --git a/mm/shmem.c b/mm/shmem.c
index ab2b0e87b051..283fb62084d4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3368,7 +3368,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
 
 static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	if (!simple_offset_empty(dentry))
+	if (!simple_empty(dentry))
 		return -ENOTEMPTY;
 
 	drop_nlink(d_inode(dentry));
@@ -3425,7 +3425,7 @@ static int shmem_rename2(struct mnt_idmap *idmap,
 		return simple_offset_rename_exchange(old_dir, old_dentry,
 						     new_dir, new_dentry);
 
-	if (!simple_offset_empty(new_dentry))
+	if (!simple_empty(new_dentry))
 		return -ENOTEMPTY;
 
 	if (flags & RENAME_WHITEOUT) {
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 09/10] libfs: Replace simple_offset end-of-directory detection
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (7 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 08/10] Revert "libfs: Add simple_offset_empty()" cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "libfs: Replace simple_offset end-of-directory detection" has been added to the 6.6-stable tree gregkh
  2025-01-24 19:19 ` [RFC PATCH v6.6 10/10] libfs: Use d_children list to iterate simple_offset directories cel
  2025-01-29 13:55 ` [RFC PATCH v6.6 00/10] Address CVE-2024-46701 Chuck Lever
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 68a3a65003145644efcbb651e91db249ccd96281 ]

According to getdents(3), the d_off field in each returned directory
entry points to the next entry in the directory. The d_off field in
the last returned entry in the readdir buffer must contain a valid
offset value, but if it points to an actual directory entry, then
readdir/getdents can loop.

This patch introduces a specific fixed offset value that is placed
in the d_off field of the last entry in a directory. Some user space
applications assume that the EOD offset value is larger than the
offsets of real directory entries, so the largest valid offset value
is reserved for this purpose. This new value is never allocated by
simple_offset_add().

When ->iterate_dir() returns, getdents{64} inserts the ctx->pos
value into the d_off field of the last valid entry in the readdir
buffer. When it hits EOD, offset_readdir() sets ctx->pos to the EOD
offset value so the last entry is updated to point to the EOD marker.

When trying to read the entry at the EOD offset, offset_readdir()
terminates immediately.

It is worth noting that using a Maple tree for directory offset
value allocation does not guarantee a 63-bit range of values --
on platforms where "long" is a 32-bit type, the directory offset
value range is still 0..(2^31 - 1). For broad compatibility with
32-bit user space, the largest tmpfs directory cookie value is now
S32_MAX.

Fixes: 796432efab1e ("libfs: getdents() should return 0 after reaching EOD")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-5-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c | 37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index 082bacf0b9e6..d546f3f0c036 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -239,9 +239,15 @@ const struct inode_operations simple_dir_inode_operations = {
 };
 EXPORT_SYMBOL(simple_dir_inode_operations);
 
-/* 0 is '.', 1 is '..', so always start with offset 2 or more */
+/* simple_offset_add() never assigns these to a dentry */
 enum {
-	DIR_OFFSET_MIN	= 2,
+	DIR_OFFSET_EOD		= S32_MAX,
+};
+
+/* simple_offset_add() allocation range */
+enum {
+	DIR_OFFSET_MIN		= 2,
+	DIR_OFFSET_MAX		= DIR_OFFSET_EOD - 1,
 };
 
 static void offset_set(struct dentry *dentry, u32 offset)
@@ -278,7 +284,8 @@ void simple_offset_init(struct offset_ctx *octx)
  */
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
 {
-	static const struct xa_limit limit = XA_LIMIT(DIR_OFFSET_MIN, U32_MAX);
+	static const struct xa_limit limit = XA_LIMIT(DIR_OFFSET_MIN,
+						      DIR_OFFSET_MAX);
 	u32 offset;
 	int ret;
 
@@ -442,8 +449,6 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
 		return -EINVAL;
 	}
 
-	/* In this case, ->private_data is protected by f_pos_lock */
-	file->private_data = NULL;
 	return vfs_setpos(file, offset, U32_MAX);
 }
 
@@ -453,7 +458,7 @@ static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset)
 	XA_STATE(xas, &octx->xa, offset);
 
 	rcu_read_lock();
-	child = xas_next_entry(&xas, U32_MAX);
+	child = xas_next_entry(&xas, DIR_OFFSET_MAX);
 	if (!child)
 		goto out;
 	spin_lock(&child->d_lock);
@@ -474,7 +479,7 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
 			  inode->i_ino, fs_umode_to_dtype(inode->i_mode));
 }
 
-static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
+static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 {
 	struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
 	struct dentry *dentry;
@@ -482,7 +487,7 @@ static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 	while (true) {
 		dentry = offset_find_next(octx, ctx->pos);
 		if (!dentry)
-			return ERR_PTR(-ENOENT);
+			goto out_eod;
 
 		if (!offset_dir_emit(ctx, dentry)) {
 			dput(dentry);
@@ -492,7 +497,10 @@ static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 		ctx->pos = dentry2offset(dentry) + 1;
 		dput(dentry);
 	}
-	return NULL;
+	return;
+
+out_eod:
+	ctx->pos = DIR_OFFSET_EOD;
 }
 
 /**
@@ -512,6 +520,8 @@ static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
  *
  * On return, @ctx->pos contains an offset that will read the next entry
  * in this directory when offset_readdir() is called again with @ctx.
+ * Caller places this value in the d_off field of the last entry in the
+ * user's buffer.
  *
  * Return values:
  *   %0 - Complete
@@ -524,13 +534,8 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
 
 	if (!dir_emit_dots(file, ctx))
 		return 0;
-
-	/* In this case, ->private_data is protected by f_pos_lock */
-	if (ctx->pos == DIR_OFFSET_MIN)
-		file->private_data = NULL;
-	else if (file->private_data == ERR_PTR(-ENOENT))
-		return 0;
-	file->private_data = offset_iterate_dir(d_inode(dir), ctx);
+	if (ctx->pos != DIR_OFFSET_EOD)
+		offset_iterate_dir(d_inode(dir), ctx);
 	return 0;
 }
 
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RFC PATCH v6.6 10/10] libfs: Use d_children list to iterate simple_offset directories
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (8 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 09/10] libfs: Replace simple_offset end-of-directory detection cel
@ 2025-01-24 19:19 ` cel
  2025-01-30  8:59   ` Patch "libfs: Use d_children list to iterate simple_offset directories" has been added to the 6.6-stable tree gregkh
  2025-01-29 13:55 ` [RFC PATCH v6.6 00/10] Address CVE-2024-46701 Chuck Lever
  10 siblings, 1 reply; 28+ messages in thread
From: cel @ 2025-01-24 19:19 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit b9b588f22a0c049a14885399e27625635ae6ef91 ]

The mtree mechanism has been effective at creating directory offsets
that are stable over multiple opendir instances. However, it has not
been able to handle the subtleties of renames that are concurrent
with readdir.

Instead of using the mtree to emit entries in the order of their
offset values, use it only to map incoming ctx->pos to a starting
entry. Then use the directory's d_children list, which is already
maintained properly by the dcache, to find the next child to emit.

One of the sneaky things about this is that when the mtree-allocated
offset value wraps (which is very rare), looking up ctx->pos++ is
not going to find the next entry; it will return NULL. Instead, by
following the d_children list, the offset values can appear in any
order but all of the entries in the directory will be visited
eventually.

Note also that the readdir() is guaranteed to reach the tail of this
list. Entries are added only at the head of d_children, and readdir
walks from its current position in that list towards its tail.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-6-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/libfs.c | 84 ++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 59 insertions(+), 25 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index d546f3f0c036..f5566964aa7d 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -241,12 +241,13 @@ EXPORT_SYMBOL(simple_dir_inode_operations);
 
 /* simple_offset_add() never assigns these to a dentry */
 enum {
+	DIR_OFFSET_FIRST	= 2,		/* Find first real entry */
 	DIR_OFFSET_EOD		= S32_MAX,
 };
 
 /* simple_offset_add() allocation range */
 enum {
-	DIR_OFFSET_MIN		= 2,
+	DIR_OFFSET_MIN		= DIR_OFFSET_FIRST + 1,
 	DIR_OFFSET_MAX		= DIR_OFFSET_EOD - 1,
 };
 
@@ -452,51 +453,84 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
 	return vfs_setpos(file, offset, U32_MAX);
 }
 
-static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset)
+static struct dentry *find_positive_dentry(struct dentry *parent,
+					   struct dentry *dentry,
+					   bool next)
 {
+	struct dentry *found = NULL;
+
+	spin_lock(&parent->d_lock);
+	if (next)
+		dentry = list_next_entry(dentry, d_child);
+	else if (!dentry)
+		dentry = list_first_entry_or_null(&parent->d_subdirs,
+						  struct dentry, d_child);
+	for (; dentry && !list_entry_is_head(dentry, &parent->d_subdirs, d_child);
+	     dentry = list_next_entry(dentry, d_child)) {
+		if (!simple_positive(dentry))
+			continue;
+		spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+		if (simple_positive(dentry))
+			found = dget_dlock(dentry);
+		spin_unlock(&dentry->d_lock);
+		if (likely(found))
+			break;
+	}
+	spin_unlock(&parent->d_lock);
+	return found;
+}
+
+static noinline_for_stack struct dentry *
+offset_dir_lookup(struct dentry *parent, loff_t offset)
+{
+	struct inode *inode = d_inode(parent);
+	struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
 	struct dentry *child, *found = NULL;
+
 	XA_STATE(xas, &octx->xa, offset);
 
-	rcu_read_lock();
-	child = xas_next_entry(&xas, DIR_OFFSET_MAX);
-	if (!child)
-		goto out;
-	spin_lock(&child->d_lock);
-	if (simple_positive(child))
-		found = dget_dlock(child);
-	spin_unlock(&child->d_lock);
-out:
-	rcu_read_unlock();
+	if (offset == DIR_OFFSET_FIRST)
+		found = find_positive_dentry(parent, NULL, false);
+	else {
+		rcu_read_lock();
+		child = xas_next_entry(&xas, DIR_OFFSET_MAX);
+		found = find_positive_dentry(parent, child, false);
+		rcu_read_unlock();
+	}
 	return found;
 }
 
 static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
 {
-	u32 offset = dentry2offset(dentry);
 	struct inode *inode = d_inode(dentry);
 
-	return ctx->actor(ctx, dentry->d_name.name, dentry->d_name.len, offset,
-			  inode->i_ino, fs_umode_to_dtype(inode->i_mode));
+	return dir_emit(ctx, dentry->d_name.name, dentry->d_name.len,
+			inode->i_ino, fs_umode_to_dtype(inode->i_mode));
 }
 
-static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
+static void offset_iterate_dir(struct file *file, struct dir_context *ctx)
 {
-	struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
+	struct dentry *dir = file->f_path.dentry;
 	struct dentry *dentry;
 
+	dentry = offset_dir_lookup(dir, ctx->pos);
+	if (!dentry)
+		goto out_eod;
 	while (true) {
-		dentry = offset_find_next(octx, ctx->pos);
-		if (!dentry)
-			goto out_eod;
+		struct dentry *next;
 
-		if (!offset_dir_emit(ctx, dentry)) {
-			dput(dentry);
+		ctx->pos = dentry2offset(dentry);
+		if (!offset_dir_emit(ctx, dentry))
 			break;
-		}
 
-		ctx->pos = dentry2offset(dentry) + 1;
+		next = find_positive_dentry(dir, dentry, true);
 		dput(dentry);
+
+		if (!next)
+			goto out_eod;
+		dentry = next;
 	}
+	dput(dentry);
 	return;
 
 out_eod:
@@ -535,7 +569,7 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
 	if (!dir_emit_dots(file, ctx))
 		return 0;
 	if (ctx->pos != DIR_OFFSET_EOD)
-		offset_iterate_dir(d_inode(dir), ctx);
+		offset_iterate_dir(file, ctx);
 	return 0;
 }
 
-- 
2.47.0



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
                   ` (9 preceding siblings ...)
  2025-01-24 19:19 ` [RFC PATCH v6.6 10/10] libfs: Use d_children list to iterate simple_offset directories cel
@ 2025-01-29 13:55 ` Chuck Lever
  2025-01-29 14:50   ` Greg Kroah-Hartman
  10 siblings, 1 reply; 28+ messages in thread
From: Chuck Lever @ 2025-01-29 13:55 UTC (permalink / raw)
  To: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Greg Kroah-Hartman, Sasha Levin
  Cc: linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On 1/24/25 2:19 PM, cel@kernel.org wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
> 
> This series backports several upstream fixes to origin/linux-6.6.y
> in order to address CVE-2024-46701:
> 
>    https://nvd.nist.gov/vuln/detail/CVE-2024-46701
> 
> As applied to origin/linux-6.6.y, this series passes fstests and the
> git regression suite.
> 
> Before officially requesting that stable@ merge this series, I'd
> like to provide an opportunity for community review of the backport
> patches.
> 
> You can also find them them in the "nfsd-6.6.y" branch in
> 
>    https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
> 
> Chuck Lever (10):
>    libfs: Re-arrange locking in offset_iterate_dir()
>    libfs: Define a minimum directory offset
>    libfs: Add simple_offset_empty()
>    libfs: Fix simple_offset_rename_exchange()
>    libfs: Add simple_offset_rename() API
>    shmem: Fix shmem_rename2()
>    libfs: Return ENOSPC when the directory offset range is exhausted
>    Revert "libfs: Add simple_offset_empty()"
>    libfs: Replace simple_offset end-of-directory detection
>    libfs: Use d_children list to iterate simple_offset directories
> 
>   fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
>   include/linux/fs.h |   2 +
>   mm/shmem.c         |   3 +-
>   3 files changed, 134 insertions(+), 48 deletions(-)
> 

I've heard no objections or other comments. Greg, Sasha, shall we
proceed with merging this patch series into v6.6 ?


-- 
Chuck Lever


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-29 13:55 ` [RFC PATCH v6.6 00/10] Address CVE-2024-46701 Chuck Lever
@ 2025-01-29 14:50   ` Greg Kroah-Hartman
  2025-01-29 15:06     ` Chuck Lever
  0 siblings, 1 reply; 28+ messages in thread
From: Greg Kroah-Hartman @ 2025-01-29 14:50 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Sasha Levin, linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On Wed, Jan 29, 2025 at 08:55:15AM -0500, Chuck Lever wrote:
> On 1/24/25 2:19 PM, cel@kernel.org wrote:
> > From: Chuck Lever <chuck.lever@oracle.com>
> > 
> > This series backports several upstream fixes to origin/linux-6.6.y
> > in order to address CVE-2024-46701:
> > 
> >    https://nvd.nist.gov/vuln/detail/CVE-2024-46701
> > 
> > As applied to origin/linux-6.6.y, this series passes fstests and the
> > git regression suite.
> > 
> > Before officially requesting that stable@ merge this series, I'd
> > like to provide an opportunity for community review of the backport
> > patches.
> > 
> > You can also find them them in the "nfsd-6.6.y" branch in
> > 
> >    https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
> > 
> > Chuck Lever (10):
> >    libfs: Re-arrange locking in offset_iterate_dir()
> >    libfs: Define a minimum directory offset
> >    libfs: Add simple_offset_empty()
> >    libfs: Fix simple_offset_rename_exchange()
> >    libfs: Add simple_offset_rename() API
> >    shmem: Fix shmem_rename2()
> >    libfs: Return ENOSPC when the directory offset range is exhausted
> >    Revert "libfs: Add simple_offset_empty()"
> >    libfs: Replace simple_offset end-of-directory detection
> >    libfs: Use d_children list to iterate simple_offset directories
> > 
> >   fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
> >   include/linux/fs.h |   2 +
> >   mm/shmem.c         |   3 +-
> >   3 files changed, 134 insertions(+), 48 deletions(-)
> > 
> 
> I've heard no objections or other comments. Greg, Sasha, shall we
> proceed with merging this patch series into v6.6 ?

Um, but not all of these are in a released kernel yet, so we can't take
them all yet.  Also what about 6.12.y and 6.13.y for those commits that
will be showing up in 6.14-rc1?  We can't have regressions for people
moving to those releases from 6.6.y, right?

thanks,

greg k-h


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-29 14:50   ` Greg Kroah-Hartman
@ 2025-01-29 15:06     ` Chuck Lever
  2025-01-29 15:21       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 28+ messages in thread
From: Chuck Lever @ 2025-01-29 15:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Sasha Levin, linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On 1/29/25 9:50 AM, Greg Kroah-Hartman wrote:
> On Wed, Jan 29, 2025 at 08:55:15AM -0500, Chuck Lever wrote:
>> On 1/24/25 2:19 PM, cel@kernel.org wrote:
>>> From: Chuck Lever <chuck.lever@oracle.com>
>>>
>>> This series backports several upstream fixes to origin/linux-6.6.y
>>> in order to address CVE-2024-46701:
>>>
>>>     https://nvd.nist.gov/vuln/detail/CVE-2024-46701
>>>
>>> As applied to origin/linux-6.6.y, this series passes fstests and the
>>> git regression suite.
>>>
>>> Before officially requesting that stable@ merge this series, I'd
>>> like to provide an opportunity for community review of the backport
>>> patches.
>>>
>>> You can also find them them in the "nfsd-6.6.y" branch in
>>>
>>>     https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
>>>
>>> Chuck Lever (10):
>>>     libfs: Re-arrange locking in offset_iterate_dir()
>>>     libfs: Define a minimum directory offset
>>>     libfs: Add simple_offset_empty()
>>>     libfs: Fix simple_offset_rename_exchange()
>>>     libfs: Add simple_offset_rename() API
>>>     shmem: Fix shmem_rename2()
>>>     libfs: Return ENOSPC when the directory offset range is exhausted
>>>     Revert "libfs: Add simple_offset_empty()"
>>>     libfs: Replace simple_offset end-of-directory detection
>>>     libfs: Use d_children list to iterate simple_offset directories
>>>
>>>    fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
>>>    include/linux/fs.h |   2 +
>>>    mm/shmem.c         |   3 +-
>>>    3 files changed, 134 insertions(+), 48 deletions(-)
>>>
>>
>> I've heard no objections or other comments. Greg, Sasha, shall we
>> proceed with merging this patch series into v6.6 ?
> 
> Um, but not all of these are in a released kernel yet, so we can't take
> them all yet.

Hi Greg -

The new patches are in v6.14 now. I'm asking stable to take these
whenever you are ready. Would that be v6.14-rc1? I can send a reminder
if you like.


> Also what about 6.12.y and 6.13.y for those commits that
> will be showing up in 6.14-rc1?  We can't have regressions for people
> moving to those releases from 6.6.y, right?

The upstream commits have Fixes tags. I assumed that your automation
will find those and apply them to those kernels -- the upstream versions
of these patches I expect will apply cleanly to recent LTS.


-- 
Chuck Lever


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-29 15:06     ` Chuck Lever
@ 2025-01-29 15:21       ` Greg Kroah-Hartman
  2025-01-29 16:37         ` Chuck Lever
  0 siblings, 1 reply; 28+ messages in thread
From: Greg Kroah-Hartman @ 2025-01-29 15:21 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Sasha Levin, linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On Wed, Jan 29, 2025 at 10:06:49AM -0500, Chuck Lever wrote:
> On 1/29/25 9:50 AM, Greg Kroah-Hartman wrote:
> > On Wed, Jan 29, 2025 at 08:55:15AM -0500, Chuck Lever wrote:
> > > On 1/24/25 2:19 PM, cel@kernel.org wrote:
> > > > From: Chuck Lever <chuck.lever@oracle.com>
> > > > 
> > > > This series backports several upstream fixes to origin/linux-6.6.y
> > > > in order to address CVE-2024-46701:
> > > > 
> > > >     https://nvd.nist.gov/vuln/detail/CVE-2024-46701
> > > > 
> > > > As applied to origin/linux-6.6.y, this series passes fstests and the
> > > > git regression suite.
> > > > 
> > > > Before officially requesting that stable@ merge this series, I'd
> > > > like to provide an opportunity for community review of the backport
> > > > patches.
> > > > 
> > > > You can also find them them in the "nfsd-6.6.y" branch in
> > > > 
> > > >     https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
> > > > 
> > > > Chuck Lever (10):
> > > >     libfs: Re-arrange locking in offset_iterate_dir()
> > > >     libfs: Define a minimum directory offset
> > > >     libfs: Add simple_offset_empty()
> > > >     libfs: Fix simple_offset_rename_exchange()
> > > >     libfs: Add simple_offset_rename() API
> > > >     shmem: Fix shmem_rename2()
> > > >     libfs: Return ENOSPC when the directory offset range is exhausted
> > > >     Revert "libfs: Add simple_offset_empty()"
> > > >     libfs: Replace simple_offset end-of-directory detection
> > > >     libfs: Use d_children list to iterate simple_offset directories
> > > > 
> > > >    fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
> > > >    include/linux/fs.h |   2 +
> > > >    mm/shmem.c         |   3 +-
> > > >    3 files changed, 134 insertions(+), 48 deletions(-)
> > > > 
> > > 
> > > I've heard no objections or other comments. Greg, Sasha, shall we
> > > proceed with merging this patch series into v6.6 ?
> > 
> > Um, but not all of these are in a released kernel yet, so we can't take
> > them all yet.
> 
> Hi Greg -
> 
> The new patches are in v6.14 now. I'm asking stable to take these
> whenever you are ready. Would that be v6.14-rc1? I can send a reminder
> if you like.

Yes, we have to wait until changes are in a -rc release unless there are
"real reasons to take it now" :)

> > Also what about 6.12.y and 6.13.y for those commits that
> > will be showing up in 6.14-rc1?  We can't have regressions for people
> > moving to those releases from 6.6.y, right?
> 
> The upstream commits have Fixes tags. I assumed that your automation
> will find those and apply them to those kernels -- the upstream versions
> of these patches I expect will apply cleanly to recent LTS.

"Fixes:" are never guaranteed to show up in stable kernels, they are
only a "maybe when we get some spare cycles and get around to it we
might do a simple pass to see what works or doesn't."

If you KNOW a change is a bugfix for stable kernels, please mark it as
such!  "Fixes:" is NOT how to do that, and never has been.  It's only
additional meta-data that helps us out.

So please send us a list of the commits that need to go to 6.12.y and
6.13.y, we have to have that before we could take the 6.6.y changes.

thanks,

greg k-h


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-29 15:21       ` Greg Kroah-Hartman
@ 2025-01-29 16:37         ` Chuck Lever
  2025-01-30  8:45           ` Greg Kroah-Hartman
  0 siblings, 1 reply; 28+ messages in thread
From: Chuck Lever @ 2025-01-29 16:37 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Sasha Levin, linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On 1/29/25 10:21 AM, Greg Kroah-Hartman wrote:
> On Wed, Jan 29, 2025 at 10:06:49AM -0500, Chuck Lever wrote:
>> On 1/29/25 9:50 AM, Greg Kroah-Hartman wrote:
>>> On Wed, Jan 29, 2025 at 08:55:15AM -0500, Chuck Lever wrote:
>>>> On 1/24/25 2:19 PM, cel@kernel.org wrote:
>>>>> From: Chuck Lever <chuck.lever@oracle.com>
>>>>>
>>>>> This series backports several upstream fixes to origin/linux-6.6.y
>>>>> in order to address CVE-2024-46701:
>>>>>
>>>>>      https://nvd.nist.gov/vuln/detail/CVE-2024-46701
>>>>>
>>>>> As applied to origin/linux-6.6.y, this series passes fstests and the
>>>>> git regression suite.
>>>>>
>>>>> Before officially requesting that stable@ merge this series, I'd
>>>>> like to provide an opportunity for community review of the backport
>>>>> patches.
>>>>>
>>>>> You can also find them them in the "nfsd-6.6.y" branch in
>>>>>
>>>>>      https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
>>>>>
>>>>> Chuck Lever (10):
>>>>>      libfs: Re-arrange locking in offset_iterate_dir()
>>>>>      libfs: Define a minimum directory offset
>>>>>      libfs: Add simple_offset_empty()
>>>>>      libfs: Fix simple_offset_rename_exchange()
>>>>>      libfs: Add simple_offset_rename() API
>>>>>      shmem: Fix shmem_rename2()
>>>>>      libfs: Return ENOSPC when the directory offset range is exhausted
>>>>>      Revert "libfs: Add simple_offset_empty()"
>>>>>      libfs: Replace simple_offset end-of-directory detection
>>>>>      libfs: Use d_children list to iterate simple_offset directories
>>>>>
>>>>>     fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
>>>>>     include/linux/fs.h |   2 +
>>>>>     mm/shmem.c         |   3 +-
>>>>>     3 files changed, 134 insertions(+), 48 deletions(-)
>>>>>
>>>>
>>>> I've heard no objections or other comments. Greg, Sasha, shall we
>>>> proceed with merging this patch series into v6.6 ?
>>>
>>> Um, but not all of these are in a released kernel yet, so we can't take
>>> them all yet.
>>
>> Hi Greg -
>>
>> The new patches are in v6.14 now. I'm asking stable to take these
>> whenever you are ready. Would that be v6.14-rc1? I can send a reminder
>> if you like.
> 
> Yes, we have to wait until changes are in a -rc release unless there are
> "real reasons to take it now" :)
> 
>>> Also what about 6.12.y and 6.13.y for those commits that
>>> will be showing up in 6.14-rc1?  We can't have regressions for people
>>> moving to those releases from 6.6.y, right?
>>
>> The upstream commits have Fixes tags. I assumed that your automation
>> will find those and apply them to those kernels -- the upstream versions
>> of these patches I expect will apply cleanly to recent LTS.
> 
> "Fixes:" are never guaranteed to show up in stable kernels, they are
> only a "maybe when we get some spare cycles and get around to it we
> might do a simple pass to see what works or doesn't."
> 
> If you KNOW a change is a bugfix for stable kernels, please mark it as
> such!  "Fixes:" is NOT how to do that, and never has been.  It's only
> additional meta-data that helps us out.
> 
> So please send us a list of the commits that need to go to 6.12.y and
> 6.13.y, we have to have that before we could take the 6.6.y changes.

903dc9c43a15 ("libfs: Return ENOSPC when the directory offset range is 
exhausted")
d7bde4f27cee ("Revert "libfs: Add simple_offset_empty()"")
b662d858131d ("Revert "libfs: fix infinite directory reads for offset dir"")
68a3a6500314 ("libfs: Replace simple_offset end-of-directory detection")
b9b588f22a0c ("libfs: Use d_children list to iterate simple_offset 
directories")

-- 
Chuck Lever


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-29 16:37         ` Chuck Lever
@ 2025-01-30  8:45           ` Greg Kroah-Hartman
  2025-01-30 14:02             ` Chuck Lever
  0 siblings, 1 reply; 28+ messages in thread
From: Greg Kroah-Hartman @ 2025-01-30  8:45 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Sasha Levin, linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On Wed, Jan 29, 2025 at 11:37:51AM -0500, Chuck Lever wrote:
> On 1/29/25 10:21 AM, Greg Kroah-Hartman wrote:
> > On Wed, Jan 29, 2025 at 10:06:49AM -0500, Chuck Lever wrote:
> > > On 1/29/25 9:50 AM, Greg Kroah-Hartman wrote:
> > > > On Wed, Jan 29, 2025 at 08:55:15AM -0500, Chuck Lever wrote:
> > > > > On 1/24/25 2:19 PM, cel@kernel.org wrote:
> > > > > > From: Chuck Lever <chuck.lever@oracle.com>
> > > > > > 
> > > > > > This series backports several upstream fixes to origin/linux-6.6.y
> > > > > > in order to address CVE-2024-46701:
> > > > > > 
> > > > > >      https://nvd.nist.gov/vuln/detail/CVE-2024-46701
> > > > > > 
> > > > > > As applied to origin/linux-6.6.y, this series passes fstests and the
> > > > > > git regression suite.
> > > > > > 
> > > > > > Before officially requesting that stable@ merge this series, I'd
> > > > > > like to provide an opportunity for community review of the backport
> > > > > > patches.
> > > > > > 
> > > > > > You can also find them them in the "nfsd-6.6.y" branch in
> > > > > > 
> > > > > >      https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
> > > > > > 
> > > > > > Chuck Lever (10):
> > > > > >      libfs: Re-arrange locking in offset_iterate_dir()
> > > > > >      libfs: Define a minimum directory offset
> > > > > >      libfs: Add simple_offset_empty()
> > > > > >      libfs: Fix simple_offset_rename_exchange()
> > > > > >      libfs: Add simple_offset_rename() API
> > > > > >      shmem: Fix shmem_rename2()
> > > > > >      libfs: Return ENOSPC when the directory offset range is exhausted
> > > > > >      Revert "libfs: Add simple_offset_empty()"
> > > > > >      libfs: Replace simple_offset end-of-directory detection
> > > > > >      libfs: Use d_children list to iterate simple_offset directories
> > > > > > 
> > > > > >     fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
> > > > > >     include/linux/fs.h |   2 +
> > > > > >     mm/shmem.c         |   3 +-
> > > > > >     3 files changed, 134 insertions(+), 48 deletions(-)
> > > > > > 
> > > > > 
> > > > > I've heard no objections or other comments. Greg, Sasha, shall we
> > > > > proceed with merging this patch series into v6.6 ?
> > > > 
> > > > Um, but not all of these are in a released kernel yet, so we can't take
> > > > them all yet.
> > > 
> > > Hi Greg -
> > > 
> > > The new patches are in v6.14 now. I'm asking stable to take these
> > > whenever you are ready. Would that be v6.14-rc1? I can send a reminder
> > > if you like.
> > 
> > Yes, we have to wait until changes are in a -rc release unless there are
> > "real reasons to take it now" :)
> > 
> > > > Also what about 6.12.y and 6.13.y for those commits that
> > > > will be showing up in 6.14-rc1?  We can't have regressions for people
> > > > moving to those releases from 6.6.y, right?
> > > 
> > > The upstream commits have Fixes tags. I assumed that your automation
> > > will find those and apply them to those kernels -- the upstream versions
> > > of these patches I expect will apply cleanly to recent LTS.
> > 
> > "Fixes:" are never guaranteed to show up in stable kernels, they are
> > only a "maybe when we get some spare cycles and get around to it we
> > might do a simple pass to see what works or doesn't."
> > 
> > If you KNOW a change is a bugfix for stable kernels, please mark it as
> > such!  "Fixes:" is NOT how to do that, and never has been.  It's only
> > additional meta-data that helps us out.
> > 
> > So please send us a list of the commits that need to go to 6.12.y and
> > 6.13.y, we have to have that before we could take the 6.6.y changes.
> 
> 903dc9c43a15 ("libfs: Return ENOSPC when the directory offset range is
> exhausted")
> d7bde4f27cee ("Revert "libfs: Add simple_offset_empty()"")
> b662d858131d ("Revert "libfs: fix infinite directory reads for offset dir"")
> 68a3a6500314 ("libfs: Replace simple_offset end-of-directory detection")
> b9b588f22a0c ("libfs: Use d_children list to iterate simple_offset
> directories")

Cool, thanks for the list (and not all were marked with fixes, i.e.
those reverts, I guess we need to start checking for reverts better.  I
have tooling set up for that but not integrated yet...)

I'll just queue them all up now.

greg k-h


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "libfs: Add simple_offset_rename() API" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 05/10] libfs: Add simple_offset_rename() API cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, linux-mm, sashal,
	viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    libfs: Add simple_offset_rename() API

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libfs-add-simple_offset_rename-api.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110405-greg=kroah.com@vger.kernel.org Fri Jan 24 20:21:49 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:40 -0500
Subject: libfs: Add simple_offset_rename() API
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>
Message-ID: <20250124191946.22308-6-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 5a1a25be995e1014abd01600479915683e356f5c ]

I'm about to fix a tmpfs rename bug that requires the use of
internal simple_offset helpers that are not available in mm/shmem.c

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20240415152057.4605-3-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c         |   21 +++++++++++++++++++++
 include/linux/fs.h |    2 ++
 mm/shmem.c         |    3 +--
 3 files changed, 24 insertions(+), 2 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -357,6 +357,27 @@ int simple_offset_empty(struct dentry *d
 }
 
 /**
+ * simple_offset_rename - handle directory offsets for rename
+ * @old_dir: parent directory of source entry
+ * @old_dentry: dentry of source entry
+ * @new_dir: parent_directory of destination entry
+ * @new_dentry: dentry of destination
+ *
+ * Caller provides appropriate serialization.
+ *
+ * Returns zero on success, a negative errno value on failure.
+ */
+int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
+			 struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir);
+	struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir);
+
+	simple_offset_remove(old_ctx, old_dentry);
+	return simple_offset_add(new_ctx, old_dentry);
+}
+
+/**
  * simple_offset_rename_exchange - exchange rename with directory offsets
  * @old_dir: parent of dentry being moved
  * @old_dentry: dentry being moved
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3198,6 +3198,8 @@ void simple_offset_init(struct offset_ct
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
 int simple_offset_empty(struct dentry *dentry);
+int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
+			 struct inode *new_dir, struct dentry *new_dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
 				  struct dentry *old_dentry,
 				  struct inode *new_dir,
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3434,8 +3434,7 @@ static int shmem_rename2(struct mnt_idma
 			return error;
 	}
 
-	simple_offset_remove(shmem_get_offset_ctx(old_dir), old_dentry);
-	error = simple_offset_add(shmem_get_offset_ctx(new_dir), old_dentry);
+	error = simple_offset_rename(old_dir, old_dentry, new_dir, new_dentry);
 	if (error)
 		return error;
 


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "libfs: Add simple_offset_empty()" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 03/10] libfs: Add simple_offset_empty() cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, jack, linux-mm,
	sashal, viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    libfs: Add simple_offset_empty()

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libfs-add-simple_offset_empty.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110403-greg=kroah.com@vger.kernel.org Fri Jan 24 20:20:42 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:38 -0500
Subject: libfs: Add simple_offset_empty()
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>, Jan Kara <jack@suse.cz>
Message-ID: <20250124191946.22308-4-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit ecba88a3b32d733d41e27973e25b2bc580f64281 ]

For simple filesystems that use directory offset mapping, rely
strictly on the directory offset map to tell when a directory has
no children.

After this patch is applied, the emptiness test holds only the RCU
read lock when the directory being tested has no children.

In addition, this adds another layer of confirmation that
simple_offset_add/remove() are working as expected.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/170820143463.6328.7872919188371286951.stgit@91.116.238.104.host.secureserver.net
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: 5a1a25be995e ("libfs: Add simple_offset_rename() API")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c         |   32 ++++++++++++++++++++++++++++++++
 include/linux/fs.h |    1 +
 mm/shmem.c         |    4 ++--
 3 files changed, 35 insertions(+), 2 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -313,6 +313,38 @@ void simple_offset_remove(struct offset_
 }
 
 /**
+ * simple_offset_empty - Check if a dentry can be unlinked
+ * @dentry: dentry to be tested
+ *
+ * Returns 0 if @dentry is a non-empty directory; otherwise returns 1.
+ */
+int simple_offset_empty(struct dentry *dentry)
+{
+	struct inode *inode = d_inode(dentry);
+	struct offset_ctx *octx;
+	struct dentry *child;
+	unsigned long index;
+	int ret = 1;
+
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return ret;
+
+	index = DIR_OFFSET_MIN;
+	octx = inode->i_op->get_offset_ctx(inode);
+	xa_for_each(&octx->xa, index, child) {
+		spin_lock(&child->d_lock);
+		if (simple_positive(child)) {
+			spin_unlock(&child->d_lock);
+			ret = 0;
+			break;
+		}
+		spin_unlock(&child->d_lock);
+	}
+
+	return ret;
+}
+
+/**
  * simple_offset_rename_exchange - exchange rename with directory offsets
  * @old_dir: parent of dentry being moved
  * @old_dentry: dentry being moved
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3197,6 +3197,7 @@ struct offset_ctx {
 void simple_offset_init(struct offset_ctx *octx);
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
+int simple_offset_empty(struct dentry *dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
 				  struct dentry *old_dentry,
 				  struct inode *new_dir,
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3368,7 +3368,7 @@ static int shmem_unlink(struct inode *di
 
 static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	if (!simple_empty(dentry))
+	if (!simple_offset_empty(dentry))
 		return -ENOTEMPTY;
 
 	drop_nlink(d_inode(dentry));
@@ -3425,7 +3425,7 @@ static int shmem_rename2(struct mnt_idma
 		return simple_offset_rename_exchange(old_dir, old_dentry,
 						     new_dir, new_dentry);
 
-	if (!simple_empty(new_dentry))
+	if (!simple_offset_empty(new_dentry))
 		return -ENOTEMPTY;
 
 	if (flags & RENAME_WHITEOUT) {


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "libfs: Fix simple_offset_rename_exchange()" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 04/10] libfs: Fix simple_offset_rename_exchange() cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, linux-mm, sashal,
	viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    libfs: Fix simple_offset_rename_exchange()

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libfs-fix-simple_offset_rename_exchange.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110404-greg=kroah.com@vger.kernel.org Fri Jan 24 20:21:48 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:39 -0500
Subject: libfs: Fix simple_offset_rename_exchange()
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>
Message-ID: <20250124191946.22308-5-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 23cdd0eed3f1fff3af323092b0b88945a7950d8e ]

User space expects the replacement (old) directory entry to have
the same directory offset after the rename.

Suggested-by: Christian Brauner <brauner@kernel.org>
Fixes: a2e459555c5f ("shmem: stable directory offsets")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20240415152057.4605-2-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c |   25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -294,6 +294,18 @@ int simple_offset_add(struct offset_ctx
 	return 0;
 }
 
+static int simple_offset_replace(struct offset_ctx *octx, struct dentry *dentry,
+				 long offset)
+{
+	void *ret;
+
+	ret = xa_store(&octx->xa, offset, dentry, GFP_KERNEL);
+	if (xa_is_err(ret))
+		return xa_err(ret);
+	offset_set(dentry, offset);
+	return 0;
+}
+
 /**
  * simple_offset_remove - Remove an entry to a directory's offset map
  * @octx: directory offset ctx to be updated
@@ -351,6 +363,9 @@ int simple_offset_empty(struct dentry *d
  * @new_dir: destination parent
  * @new_dentry: destination dentry
  *
+ * This API preserves the directory offset values. Caller provides
+ * appropriate serialization.
+ *
  * Returns zero on success. Otherwise a negative errno is returned and the
  * rename is rolled back.
  */
@@ -368,11 +383,11 @@ int simple_offset_rename_exchange(struct
 	simple_offset_remove(old_ctx, old_dentry);
 	simple_offset_remove(new_ctx, new_dentry);
 
-	ret = simple_offset_add(new_ctx, old_dentry);
+	ret = simple_offset_replace(new_ctx, old_dentry, new_index);
 	if (ret)
 		goto out_restore;
 
-	ret = simple_offset_add(old_ctx, new_dentry);
+	ret = simple_offset_replace(old_ctx, new_dentry, old_index);
 	if (ret) {
 		simple_offset_remove(new_ctx, old_dentry);
 		goto out_restore;
@@ -387,10 +402,8 @@ int simple_offset_rename_exchange(struct
 	return 0;
 
 out_restore:
-	offset_set(old_dentry, old_index);
-	xa_store(&old_ctx->xa, old_index, old_dentry, GFP_KERNEL);
-	offset_set(new_dentry, new_index);
-	xa_store(&new_ctx->xa, new_index, new_dentry, GFP_KERNEL);
+	(void)simple_offset_replace(old_ctx, old_dentry, old_index);
+	(void)simple_offset_replace(new_ctx, new_dentry, new_index);
 	return ret;
 }
 


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "libfs: Define a minimum directory offset" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 02/10] libfs: Define a minimum directory offset cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, jack, linux-mm,
	sashal, viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    libfs: Define a minimum directory offset

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libfs-define-a-minimum-directory-offset.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110402-greg=kroah.com@vger.kernel.org Fri Jan 24 20:21:35 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:37 -0500
Subject: libfs: Define a minimum directory offset
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>, Jan Kara <jack@suse.cz>
Message-ID: <20250124191946.22308-3-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 7beea725a8ca412c6190090ce7c3a13b169592a1 ]

This value is used in several places, so make it a symbolic
constant.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/170820142741.6328.12428356024575347885.stgit@91.116.238.104.host.secureserver.net
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: ecba88a3b32d ("libfs: Add simple_offset_empty()")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c |   13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -239,6 +239,11 @@ const struct inode_operations simple_dir
 };
 EXPORT_SYMBOL(simple_dir_inode_operations);
 
+/* 0 is '.', 1 is '..', so always start with offset 2 or more */
+enum {
+	DIR_OFFSET_MIN	= 2,
+};
+
 static void offset_set(struct dentry *dentry, u32 offset)
 {
 	dentry->d_fsdata = (void *)((uintptr_t)(offset));
@@ -260,9 +265,7 @@ void simple_offset_init(struct offset_ct
 {
 	xa_init_flags(&octx->xa, XA_FLAGS_ALLOC1);
 	lockdep_set_class(&octx->xa.xa_lock, &simple_offset_xa_lock);
-
-	/* 0 is '.', 1 is '..', so always start with offset 2 */
-	octx->next_offset = 2;
+	octx->next_offset = DIR_OFFSET_MIN;
 }
 
 /**
@@ -275,7 +278,7 @@ void simple_offset_init(struct offset_ct
  */
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
 {
-	static const struct xa_limit limit = XA_LIMIT(2, U32_MAX);
+	static const struct xa_limit limit = XA_LIMIT(DIR_OFFSET_MIN, U32_MAX);
 	u32 offset;
 	int ret;
 
@@ -480,7 +483,7 @@ static int offset_readdir(struct file *f
 		return 0;
 
 	/* In this case, ->private_data is protected by f_pos_lock */
-	if (ctx->pos == 2)
+	if (ctx->pos == DIR_OFFSET_MIN)
 		file->private_data = NULL;
 	else if (file->private_data == ERR_PTR(-ENOENT))
 		return 0;


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "libfs: Return ENOSPC when the directory offset range is exhausted" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 07/10] libfs: Return ENOSPC when the directory offset range is exhausted cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, jlayton,
	linux-mm, sashal, viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    libfs: Return ENOSPC when the directory offset range is exhausted

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110407-greg=kroah.com@vger.kernel.org Fri Jan 24 20:20:27 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:42 -0500
Subject: libfs: Return ENOSPC when the directory offset range is exhausted
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>, Jeff Layton <jlayton@kernel.org>
Message-ID: <20250124191946.22308-8-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 903dc9c43a155e0893280c7472d4a9a3a83d75a6 ]

Testing shows that the EBUSY error return from mtree_alloc_cyclic()
leaks into user space. The ERRORS section of "man creat(2)" says:

>	EBUSY	O_EXCL was specified in flags and pathname refers
>		to a block device that is in use by the system
>		(e.g., it is mounted).

ENOSPC is closer to what applications expect in this situation.

Note that the normal range of simple directory offset values is
2..2^63, so hitting this error is going to be rare to impossible.

Fixes: 6faddda69f62 ("libfs: Add directory operations for stable offsets")
Cc: stable@vger.kernel.org # v6.9+
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Yang Erkun <yangerkun@huawei.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-2-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -287,8 +287,8 @@ int simple_offset_add(struct offset_ctx
 
 	ret = xa_alloc_cyclic(&octx->xa, &offset, dentry, limit,
 			      &octx->next_offset, GFP_KERNEL);
-	if (ret < 0)
-		return ret;
+	if (unlikely(ret < 0))
+		return ret == -EBUSY ? -ENOSPC : ret;
 
 	offset_set(dentry, offset);
 	return 0;


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "libfs: Use d_children list to iterate simple_offset directories" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 10/10] libfs: Use d_children list to iterate simple_offset directories cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, linux-mm, sashal,
	viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    libfs: Use d_children list to iterate simple_offset directories

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110410-greg=kroah.com@vger.kernel.org Fri Jan 24 20:22:00 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:45 -0500
Subject: libfs: Use d_children list to iterate simple_offset directories
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>
Message-ID: <20250124191946.22308-11-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit b9b588f22a0c049a14885399e27625635ae6ef91 ]

The mtree mechanism has been effective at creating directory offsets
that are stable over multiple opendir instances. However, it has not
been able to handle the subtleties of renames that are concurrent
with readdir.

Instead of using the mtree to emit entries in the order of their
offset values, use it only to map incoming ctx->pos to a starting
entry. Then use the directory's d_children list, which is already
maintained properly by the dcache, to find the next child to emit.

One of the sneaky things about this is that when the mtree-allocated
offset value wraps (which is very rare), looking up ctx->pos++ is
not going to find the next entry; it will return NULL. Instead, by
following the d_children list, the offset values can appear in any
order but all of the entries in the directory will be visited
eventually.

Note also that the readdir() is guaranteed to reach the tail of this
list. Entries are added only at the head of d_children, and readdir
walks from its current position in that list towards its tail.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-6-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c |   84 ++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 59 insertions(+), 25 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -241,12 +241,13 @@ EXPORT_SYMBOL(simple_dir_inode_operation
 
 /* simple_offset_add() never assigns these to a dentry */
 enum {
+	DIR_OFFSET_FIRST	= 2,		/* Find first real entry */
 	DIR_OFFSET_EOD		= S32_MAX,
 };
 
 /* simple_offset_add() allocation range */
 enum {
-	DIR_OFFSET_MIN		= 2,
+	DIR_OFFSET_MIN		= DIR_OFFSET_FIRST + 1,
 	DIR_OFFSET_MAX		= DIR_OFFSET_EOD - 1,
 };
 
@@ -452,51 +453,84 @@ static loff_t offset_dir_llseek(struct f
 	return vfs_setpos(file, offset, U32_MAX);
 }
 
-static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset)
+static struct dentry *find_positive_dentry(struct dentry *parent,
+					   struct dentry *dentry,
+					   bool next)
+{
+	struct dentry *found = NULL;
+
+	spin_lock(&parent->d_lock);
+	if (next)
+		dentry = list_next_entry(dentry, d_child);
+	else if (!dentry)
+		dentry = list_first_entry_or_null(&parent->d_subdirs,
+						  struct dentry, d_child);
+	for (; dentry && !list_entry_is_head(dentry, &parent->d_subdirs, d_child);
+	     dentry = list_next_entry(dentry, d_child)) {
+		if (!simple_positive(dentry))
+			continue;
+		spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+		if (simple_positive(dentry))
+			found = dget_dlock(dentry);
+		spin_unlock(&dentry->d_lock);
+		if (likely(found))
+			break;
+	}
+	spin_unlock(&parent->d_lock);
+	return found;
+}
+
+static noinline_for_stack struct dentry *
+offset_dir_lookup(struct dentry *parent, loff_t offset)
 {
+	struct inode *inode = d_inode(parent);
+	struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
 	struct dentry *child, *found = NULL;
+
 	XA_STATE(xas, &octx->xa, offset);
 
-	rcu_read_lock();
-	child = xas_next_entry(&xas, DIR_OFFSET_MAX);
-	if (!child)
-		goto out;
-	spin_lock(&child->d_lock);
-	if (simple_positive(child))
-		found = dget_dlock(child);
-	spin_unlock(&child->d_lock);
-out:
-	rcu_read_unlock();
+	if (offset == DIR_OFFSET_FIRST)
+		found = find_positive_dentry(parent, NULL, false);
+	else {
+		rcu_read_lock();
+		child = xas_next_entry(&xas, DIR_OFFSET_MAX);
+		found = find_positive_dentry(parent, child, false);
+		rcu_read_unlock();
+	}
 	return found;
 }
 
 static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
 {
-	u32 offset = dentry2offset(dentry);
 	struct inode *inode = d_inode(dentry);
 
-	return ctx->actor(ctx, dentry->d_name.name, dentry->d_name.len, offset,
-			  inode->i_ino, fs_umode_to_dtype(inode->i_mode));
+	return dir_emit(ctx, dentry->d_name.name, dentry->d_name.len,
+			inode->i_ino, fs_umode_to_dtype(inode->i_mode));
 }
 
-static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
+static void offset_iterate_dir(struct file *file, struct dir_context *ctx)
 {
-	struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
+	struct dentry *dir = file->f_path.dentry;
 	struct dentry *dentry;
 
+	dentry = offset_dir_lookup(dir, ctx->pos);
+	if (!dentry)
+		goto out_eod;
 	while (true) {
-		dentry = offset_find_next(octx, ctx->pos);
-		if (!dentry)
-			goto out_eod;
+		struct dentry *next;
 
-		if (!offset_dir_emit(ctx, dentry)) {
-			dput(dentry);
+		ctx->pos = dentry2offset(dentry);
+		if (!offset_dir_emit(ctx, dentry))
 			break;
-		}
 
-		ctx->pos = dentry2offset(dentry) + 1;
+		next = find_positive_dentry(dir, dentry, true);
 		dput(dentry);
+
+		if (!next)
+			goto out_eod;
+		dentry = next;
 	}
+	dput(dentry);
 	return;
 
 out_eod:
@@ -535,7 +569,7 @@ static int offset_readdir(struct file *f
 	if (!dir_emit_dots(file, ctx))
 		return 0;
 	if (ctx->pos != DIR_OFFSET_EOD)
-		offset_iterate_dir(d_inode(dir), ctx);
+		offset_iterate_dir(file, ctx);
 	return 0;
 }
 


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "Revert "libfs: Add simple_offset_empty()"" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 08/10] Revert "libfs: Add simple_offset_empty()" cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, linux-mm, sashal,
	viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    Revert "libfs: Add simple_offset_empty()"

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     revert-libfs-add-simple_offset_empty.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110408-greg=kroah.com@vger.kernel.org Fri Jan 24 20:21:08 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:43 -0500
Subject: Revert "libfs: Add simple_offset_empty()"
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>
Message-ID: <20250124191946.22308-9-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit d7bde4f27ceef3dc6d72010a20d4da23db835a32 ]

simple_empty() and simple_offset_empty() perform the same task.
The latter's use as a canary to find bugs has not found any new
issues. A subsequent patch will remove the use of the mtree for
iterating directory contents, so revert back to using a similar
mechanism for determining whether a directory is indeed empty.

Only one such mechanism is ever needed.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-3-cel@kernel.org
Reviewed-by: Yang Erkun <yangerkun@huawei.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c         |   32 --------------------------------
 include/linux/fs.h |    1 -
 mm/shmem.c         |    4 ++--
 3 files changed, 2 insertions(+), 35 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -325,38 +325,6 @@ void simple_offset_remove(struct offset_
 }
 
 /**
- * simple_offset_empty - Check if a dentry can be unlinked
- * @dentry: dentry to be tested
- *
- * Returns 0 if @dentry is a non-empty directory; otherwise returns 1.
- */
-int simple_offset_empty(struct dentry *dentry)
-{
-	struct inode *inode = d_inode(dentry);
-	struct offset_ctx *octx;
-	struct dentry *child;
-	unsigned long index;
-	int ret = 1;
-
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return ret;
-
-	index = DIR_OFFSET_MIN;
-	octx = inode->i_op->get_offset_ctx(inode);
-	xa_for_each(&octx->xa, index, child) {
-		spin_lock(&child->d_lock);
-		if (simple_positive(child)) {
-			spin_unlock(&child->d_lock);
-			ret = 0;
-			break;
-		}
-		spin_unlock(&child->d_lock);
-	}
-
-	return ret;
-}
-
-/**
  * simple_offset_rename - handle directory offsets for rename
  * @old_dir: parent directory of source entry
  * @old_dentry: dentry of source entry
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3197,7 +3197,6 @@ struct offset_ctx {
 void simple_offset_init(struct offset_ctx *octx);
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
-int simple_offset_empty(struct dentry *dentry);
 int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
 			 struct inode *new_dir, struct dentry *new_dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3368,7 +3368,7 @@ static int shmem_unlink(struct inode *di
 
 static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	if (!simple_offset_empty(dentry))
+	if (!simple_empty(dentry))
 		return -ENOTEMPTY;
 
 	drop_nlink(d_inode(dentry));
@@ -3425,7 +3425,7 @@ static int shmem_rename2(struct mnt_idma
 		return simple_offset_rename_exchange(old_dir, old_dentry,
 						     new_dir, new_dentry);
 
-	if (!simple_offset_empty(new_dentry))
+	if (!simple_empty(new_dentry))
 		return -ENOTEMPTY;
 
 	if (flags & RENAME_WHITEOUT) {


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "shmem: Fix shmem_rename2()" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 06/10] shmem: Fix shmem_rename2() cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, linux-mm, sashal,
	viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    shmem: Fix shmem_rename2()

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     shmem-fix-shmem_rename2.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110406-greg=kroah.com@vger.kernel.org Fri Jan 24 20:22:02 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:41 -0500
Subject: shmem: Fix shmem_rename2()
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>
Message-ID: <20250124191946.22308-7-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit ad191eb6d6942bb835a0b20b647f7c53c1d99ca4 ]

When renaming onto an existing directory entry, user space expects
the replacement entry to have the same directory offset as the
original one.

Link: https://gitlab.alpinelinux.org/alpine/aports/-/issues/15966
Fixes: a2e459555c5f ("shmem: stable directory offsets")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20240415152057.4605-4-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c |    9 +++++++++
 1 file changed, 9 insertions(+)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -365,6 +365,9 @@ int simple_offset_empty(struct dentry *d
  *
  * Caller provides appropriate serialization.
  *
+ * User space expects the directory offset value of the replaced
+ * (new) directory entry to be unchanged after a rename.
+ *
  * Returns zero on success, a negative errno value on failure.
  */
 int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -372,8 +375,14 @@ int simple_offset_rename(struct inode *o
 {
 	struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir);
 	struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir);
+	long new_offset = dentry2offset(new_dentry);
 
 	simple_offset_remove(old_ctx, old_dentry);
+
+	if (new_offset) {
+		offset_set(new_dentry, 0);
+		return simple_offset_replace(new_ctx, old_dentry, new_offset);
+	}
 	return simple_offset_add(new_ctx, old_dentry);
 }
 


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Patch "libfs: Replace simple_offset end-of-directory detection" has been added to the 6.6-stable tree
  2025-01-24 19:19 ` [RFC PATCH v6.6 09/10] libfs: Replace simple_offset end-of-directory detection cel
@ 2025-01-30  8:59   ` gregkh
  0 siblings, 0 replies; 28+ messages in thread
From: gregkh @ 2025-01-30  8:59 UTC (permalink / raw)
  To: akpm, brauner, cel, chuck.lever, gregkh, hughd, linux-mm, sashal,
	viro, yangerkun, yukuai3
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    libfs: Replace simple_offset end-of-directory detection

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libfs-replace-simple_offset-end-of-directory-detection.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From stable+bounces-110409-greg=kroah.com@vger.kernel.org Fri Jan 24 20:22:03 2025
From: cel@kernel.org
Date: Fri, 24 Jan 2025 14:19:44 -0500
Subject: libfs: Replace simple_offset end-of-directory detection
To: Hugh Dickins <hughd@google.com>, Andrew Morten <akpm@linux-foundation.org>, Christian Brauner <brauner@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>, <stable@vger.kernel.org>, <linux-mm@kvack.org>, yukuai3@huawei.com, yangerkun@huawei.com, Chuck Lever <chuck.lever@oracle.com>
Message-ID: <20250124191946.22308-10-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit 68a3a65003145644efcbb651e91db249ccd96281 ]

According to getdents(3), the d_off field in each returned directory
entry points to the next entry in the directory. The d_off field in
the last returned entry in the readdir buffer must contain a valid
offset value, but if it points to an actual directory entry, then
readdir/getdents can loop.

This patch introduces a specific fixed offset value that is placed
in the d_off field of the last entry in a directory. Some user space
applications assume that the EOD offset value is larger than the
offsets of real directory entries, so the largest valid offset value
is reserved for this purpose. This new value is never allocated by
simple_offset_add().

When ->iterate_dir() returns, getdents{64} inserts the ctx->pos
value into the d_off field of the last valid entry in the readdir
buffer. When it hits EOD, offset_readdir() sets ctx->pos to the EOD
offset value so the last entry is updated to point to the EOD marker.

When trying to read the entry at the EOD offset, offset_readdir()
terminates immediately.

It is worth noting that using a Maple tree for directory offset
value allocation does not guarantee a 63-bit range of values --
on platforms where "long" is a 32-bit type, the directory offset
value range is still 0..(2^31 - 1). For broad compatibility with
32-bit user space, the largest tmpfs directory cookie value is now
S32_MAX.

Fixes: 796432efab1e ("libfs: getdents() should return 0 after reaching EOD")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://lore.kernel.org/r/20241228175522.1854234-5-cel@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/libfs.c |   37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -239,9 +239,15 @@ const struct inode_operations simple_dir
 };
 EXPORT_SYMBOL(simple_dir_inode_operations);
 
-/* 0 is '.', 1 is '..', so always start with offset 2 or more */
+/* simple_offset_add() never assigns these to a dentry */
 enum {
-	DIR_OFFSET_MIN	= 2,
+	DIR_OFFSET_EOD		= S32_MAX,
+};
+
+/* simple_offset_add() allocation range */
+enum {
+	DIR_OFFSET_MIN		= 2,
+	DIR_OFFSET_MAX		= DIR_OFFSET_EOD - 1,
 };
 
 static void offset_set(struct dentry *dentry, u32 offset)
@@ -278,7 +284,8 @@ void simple_offset_init(struct offset_ct
  */
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
 {
-	static const struct xa_limit limit = XA_LIMIT(DIR_OFFSET_MIN, U32_MAX);
+	static const struct xa_limit limit = XA_LIMIT(DIR_OFFSET_MIN,
+						      DIR_OFFSET_MAX);
 	u32 offset;
 	int ret;
 
@@ -442,8 +449,6 @@ static loff_t offset_dir_llseek(struct f
 		return -EINVAL;
 	}
 
-	/* In this case, ->private_data is protected by f_pos_lock */
-	file->private_data = NULL;
 	return vfs_setpos(file, offset, U32_MAX);
 }
 
@@ -453,7 +458,7 @@ static struct dentry *offset_find_next(s
 	XA_STATE(xas, &octx->xa, offset);
 
 	rcu_read_lock();
-	child = xas_next_entry(&xas, U32_MAX);
+	child = xas_next_entry(&xas, DIR_OFFSET_MAX);
 	if (!child)
 		goto out;
 	spin_lock(&child->d_lock);
@@ -474,7 +479,7 @@ static bool offset_dir_emit(struct dir_c
 			  inode->i_ino, fs_umode_to_dtype(inode->i_mode));
 }
 
-static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
+static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 {
 	struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
 	struct dentry *dentry;
@@ -482,7 +487,7 @@ static void *offset_iterate_dir(struct i
 	while (true) {
 		dentry = offset_find_next(octx, ctx->pos);
 		if (!dentry)
-			return ERR_PTR(-ENOENT);
+			goto out_eod;
 
 		if (!offset_dir_emit(ctx, dentry)) {
 			dput(dentry);
@@ -492,7 +497,10 @@ static void *offset_iterate_dir(struct i
 		ctx->pos = dentry2offset(dentry) + 1;
 		dput(dentry);
 	}
-	return NULL;
+	return;
+
+out_eod:
+	ctx->pos = DIR_OFFSET_EOD;
 }
 
 /**
@@ -512,6 +520,8 @@ static void *offset_iterate_dir(struct i
  *
  * On return, @ctx->pos contains an offset that will read the next entry
  * in this directory when offset_readdir() is called again with @ctx.
+ * Caller places this value in the d_off field of the last entry in the
+ * user's buffer.
  *
  * Return values:
  *   %0 - Complete
@@ -524,13 +534,8 @@ static int offset_readdir(struct file *f
 
 	if (!dir_emit_dots(file, ctx))
 		return 0;
-
-	/* In this case, ->private_data is protected by f_pos_lock */
-	if (ctx->pos == DIR_OFFSET_MIN)
-		file->private_data = NULL;
-	else if (file->private_data == ERR_PTR(-ENOENT))
-		return 0;
-	file->private_data = offset_iterate_dir(d_inode(dir), ctx);
+	if (ctx->pos != DIR_OFFSET_EOD)
+		offset_iterate_dir(d_inode(dir), ctx);
 	return 0;
 }
 


Patches currently in stable-queue which might be from cel@kernel.org are

queue-6.6/libfs-replace-simple_offset-end-of-directory-detection.patch
queue-6.6/libfs-re-arrange-locking-in-offset_iterate_dir.patch
queue-6.6/libfs-add-simple_offset_empty.patch
queue-6.6/shmem-fix-shmem_rename2.patch
queue-6.6/revert-libfs-add-simple_offset_empty.patch
queue-6.6/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch
queue-6.6/libfs-define-a-minimum-directory-offset.patch
queue-6.6/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch
queue-6.6/libfs-fix-simple_offset_rename_exchange.patch
queue-6.6/libfs-add-simple_offset_rename-api.patch


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-30  8:45           ` Greg Kroah-Hartman
@ 2025-01-30 14:02             ` Chuck Lever
  2025-01-30 14:24               ` Greg Kroah-Hartman
  0 siblings, 1 reply; 28+ messages in thread
From: Chuck Lever @ 2025-01-30 14:02 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Sasha Levin, linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On 1/30/25 3:45 AM, Greg Kroah-Hartman wrote:
> On Wed, Jan 29, 2025 at 11:37:51AM -0500, Chuck Lever wrote:
>> On 1/29/25 10:21 AM, Greg Kroah-Hartman wrote:
>>> On Wed, Jan 29, 2025 at 10:06:49AM -0500, Chuck Lever wrote:
>>>> On 1/29/25 9:50 AM, Greg Kroah-Hartman wrote:
>>>>> On Wed, Jan 29, 2025 at 08:55:15AM -0500, Chuck Lever wrote:
>>>>>> On 1/24/25 2:19 PM, cel@kernel.org wrote:
>>>>>>> From: Chuck Lever <chuck.lever@oracle.com>
>>>>>>>
>>>>>>> This series backports several upstream fixes to origin/linux-6.6.y
>>>>>>> in order to address CVE-2024-46701:
>>>>>>>
>>>>>>>      https://nvd.nist.gov/vuln/detail/CVE-2024-46701
>>>>>>>
>>>>>>> As applied to origin/linux-6.6.y, this series passes fstests and the
>>>>>>> git regression suite.
>>>>>>>
>>>>>>> Before officially requesting that stable@ merge this series, I'd
>>>>>>> like to provide an opportunity for community review of the backport
>>>>>>> patches.
>>>>>>>
>>>>>>> You can also find them them in the "nfsd-6.6.y" branch in
>>>>>>>
>>>>>>>      https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
>>>>>>>
>>>>>>> Chuck Lever (10):
>>>>>>>      libfs: Re-arrange locking in offset_iterate_dir()
>>>>>>>      libfs: Define a minimum directory offset
>>>>>>>      libfs: Add simple_offset_empty()
>>>>>>>      libfs: Fix simple_offset_rename_exchange()
>>>>>>>      libfs: Add simple_offset_rename() API
>>>>>>>      shmem: Fix shmem_rename2()
>>>>>>>      libfs: Return ENOSPC when the directory offset range is exhausted
>>>>>>>      Revert "libfs: Add simple_offset_empty()"
>>>>>>>      libfs: Replace simple_offset end-of-directory detection
>>>>>>>      libfs: Use d_children list to iterate simple_offset directories
>>>>>>>
>>>>>>>     fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
>>>>>>>     include/linux/fs.h |   2 +
>>>>>>>     mm/shmem.c         |   3 +-
>>>>>>>     3 files changed, 134 insertions(+), 48 deletions(-)
>>>>>>>
>>>>>>
>>>>>> I've heard no objections or other comments. Greg, Sasha, shall we
>>>>>> proceed with merging this patch series into v6.6 ?
>>>>>
>>>>> Um, but not all of these are in a released kernel yet, so we can't take
>>>>> them all yet.
>>>>
>>>> Hi Greg -
>>>>
>>>> The new patches are in v6.14 now. I'm asking stable to take these
>>>> whenever you are ready. Would that be v6.14-rc1? I can send a reminder
>>>> if you like.
>>>
>>> Yes, we have to wait until changes are in a -rc release unless there are
>>> "real reasons to take it now" :)
>>>
>>>>> Also what about 6.12.y and 6.13.y for those commits that
>>>>> will be showing up in 6.14-rc1?  We can't have regressions for people
>>>>> moving to those releases from 6.6.y, right?
>>>>
>>>> The upstream commits have Fixes tags. I assumed that your automation
>>>> will find those and apply them to those kernels -- the upstream versions
>>>> of these patches I expect will apply cleanly to recent LTS.
>>>
>>> "Fixes:" are never guaranteed to show up in stable kernels, they are
>>> only a "maybe when we get some spare cycles and get around to it we
>>> might do a simple pass to see what works or doesn't."
>>>
>>> If you KNOW a change is a bugfix for stable kernels, please mark it as
>>> such!  "Fixes:" is NOT how to do that, and never has been.  It's only
>>> additional meta-data that helps us out.
>>>
>>> So please send us a list of the commits that need to go to 6.12.y and
>>> 6.13.y, we have to have that before we could take the 6.6.y changes.
>>
>> 903dc9c43a15 ("libfs: Return ENOSPC when the directory offset range is
>> exhausted")
>> d7bde4f27cee ("Revert "libfs: Add simple_offset_empty()"")
>> b662d858131d ("Revert "libfs: fix infinite directory reads for offset dir"")
>> 68a3a6500314 ("libfs: Replace simple_offset end-of-directory detection")
>> b9b588f22a0c ("libfs: Use d_children list to iterate simple_offset
>> directories")
> 
> Cool, thanks for the list (and not all were marked with fixes, i.e.
> those reverts, I guess we need to start checking for reverts better.  I
> have tooling set up for that but not integrated yet...)
> 
> I'll just queue them all up now.

My thinking was the patches marked "Fixes:" would show an obvious need
for applying the unmarked patches as pre-requisites first.

I promise to do better marking patches with "Cc: stable". But also let
me know if there's a way to label pre-req patches more clearly. Maybe
"Cc: stable" without "Fixes:" is the way to go there.

Thank you, Greg, for your time.


-- 
Chuck Lever


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RFC PATCH v6.6 00/10] Address CVE-2024-46701
  2025-01-30 14:02             ` Chuck Lever
@ 2025-01-30 14:24               ` Greg Kroah-Hartman
  0 siblings, 0 replies; 28+ messages in thread
From: Greg Kroah-Hartman @ 2025-01-30 14:24 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Hugh Dickins, Andrew Morten, Christian Brauner, Al Viro,
	Sasha Levin, linux-fsdevel, stable, linux-mm, yukuai3, yangerkun

On Thu, Jan 30, 2025 at 09:02:41AM -0500, Chuck Lever wrote:
> On 1/30/25 3:45 AM, Greg Kroah-Hartman wrote:
> > On Wed, Jan 29, 2025 at 11:37:51AM -0500, Chuck Lever wrote:
> >> On 1/29/25 10:21 AM, Greg Kroah-Hartman wrote:
> >>> On Wed, Jan 29, 2025 at 10:06:49AM -0500, Chuck Lever wrote:
> >>>> On 1/29/25 9:50 AM, Greg Kroah-Hartman wrote:
> >>>>> On Wed, Jan 29, 2025 at 08:55:15AM -0500, Chuck Lever wrote:
> >>>>>> On 1/24/25 2:19 PM, cel@kernel.org wrote:
> >>>>>>> From: Chuck Lever <chuck.lever@oracle.com>
> >>>>>>>
> >>>>>>> This series backports several upstream fixes to origin/linux-6.6.y
> >>>>>>> in order to address CVE-2024-46701:
> >>>>>>>
> >>>>>>>      https://nvd.nist.gov/vuln/detail/CVE-2024-46701
> >>>>>>>
> >>>>>>> As applied to origin/linux-6.6.y, this series passes fstests and the
> >>>>>>> git regression suite.
> >>>>>>>
> >>>>>>> Before officially requesting that stable@ merge this series, I'd
> >>>>>>> like to provide an opportunity for community review of the backport
> >>>>>>> patches.
> >>>>>>>
> >>>>>>> You can also find them them in the "nfsd-6.6.y" branch in
> >>>>>>>
> >>>>>>>      https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
> >>>>>>>
> >>>>>>> Chuck Lever (10):
> >>>>>>>      libfs: Re-arrange locking in offset_iterate_dir()
> >>>>>>>      libfs: Define a minimum directory offset
> >>>>>>>      libfs: Add simple_offset_empty()
> >>>>>>>      libfs: Fix simple_offset_rename_exchange()
> >>>>>>>      libfs: Add simple_offset_rename() API
> >>>>>>>      shmem: Fix shmem_rename2()
> >>>>>>>      libfs: Return ENOSPC when the directory offset range is exhausted
> >>>>>>>      Revert "libfs: Add simple_offset_empty()"
> >>>>>>>      libfs: Replace simple_offset end-of-directory detection
> >>>>>>>      libfs: Use d_children list to iterate simple_offset directories
> >>>>>>>
> >>>>>>>     fs/libfs.c         | 177 +++++++++++++++++++++++++++++++++------------
> >>>>>>>     include/linux/fs.h |   2 +
> >>>>>>>     mm/shmem.c         |   3 +-
> >>>>>>>     3 files changed, 134 insertions(+), 48 deletions(-)
> >>>>>>>
> >>>>>>
> >>>>>> I've heard no objections or other comments. Greg, Sasha, shall we
> >>>>>> proceed with merging this patch series into v6.6 ?
> >>>>>
> >>>>> Um, but not all of these are in a released kernel yet, so we can't take
> >>>>> them all yet.
> >>>>
> >>>> Hi Greg -
> >>>>
> >>>> The new patches are in v6.14 now. I'm asking stable to take these
> >>>> whenever you are ready. Would that be v6.14-rc1? I can send a reminder
> >>>> if you like.
> >>>
> >>> Yes, we have to wait until changes are in a -rc release unless there are
> >>> "real reasons to take it now" :)
> >>>
> >>>>> Also what about 6.12.y and 6.13.y for those commits that
> >>>>> will be showing up in 6.14-rc1?  We can't have regressions for people
> >>>>> moving to those releases from 6.6.y, right?
> >>>>
> >>>> The upstream commits have Fixes tags. I assumed that your automation
> >>>> will find those and apply them to those kernels -- the upstream versions
> >>>> of these patches I expect will apply cleanly to recent LTS.
> >>>
> >>> "Fixes:" are never guaranteed to show up in stable kernels, they are
> >>> only a "maybe when we get some spare cycles and get around to it we
> >>> might do a simple pass to see what works or doesn't."
> >>>
> >>> If you KNOW a change is a bugfix for stable kernels, please mark it as
> >>> such!  "Fixes:" is NOT how to do that, and never has been.  It's only
> >>> additional meta-data that helps us out.
> >>>
> >>> So please send us a list of the commits that need to go to 6.12.y and
> >>> 6.13.y, we have to have that before we could take the 6.6.y changes.
> >>
> >> 903dc9c43a15 ("libfs: Return ENOSPC when the directory offset range is
> >> exhausted")
> >> d7bde4f27cee ("Revert "libfs: Add simple_offset_empty()"")
> >> b662d858131d ("Revert "libfs: fix infinite directory reads for offset dir"")
> >> 68a3a6500314 ("libfs: Replace simple_offset end-of-directory detection")
> >> b9b588f22a0c ("libfs: Use d_children list to iterate simple_offset
> >> directories")
> > 
> > Cool, thanks for the list (and not all were marked with fixes, i.e.
> > those reverts, I guess we need to start checking for reverts better.  I
> > have tooling set up for that but not integrated yet...)
> > 
> > I'll just queue them all up now.
> 
> My thinking was the patches marked "Fixes:" would show an obvious need
> for applying the unmarked patches as pre-requisites first.

For when you send us a patch series for inclusion, sure, all is fine.  I
mean for when you merge stuff to Linus and expect us to pick them up.

> I promise to do better marking patches with "Cc: stable". But also let
> me know if there's a way to label pre-req patches more clearly. Maybe
> "Cc: stable" without "Fixes:" is the way to go there.

Both is best, that way if you have a Fixes: tag in it, and a patch does
not apply properly, you will get a "FAILED" email sent to you.  If you
only have the cc: stable then we just do a best-effort attempt and stop
backporting when it doesn't apply and don't notify you at all about any
failures.

thanks,

greg k-h


^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2025-01-30 14:31 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-24 19:19 [RFC PATCH v6.6 00/10] Address CVE-2024-46701 cel
2025-01-24 19:19 ` [RFC PATCH v6.6 01/10] libfs: Re-arrange locking in offset_iterate_dir() cel
2025-01-24 19:19 ` [RFC PATCH v6.6 02/10] libfs: Define a minimum directory offset cel
2025-01-30  8:59   ` Patch "libfs: Define a minimum directory offset" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 03/10] libfs: Add simple_offset_empty() cel
2025-01-30  8:59   ` Patch "libfs: Add simple_offset_empty()" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 04/10] libfs: Fix simple_offset_rename_exchange() cel
2025-01-30  8:59   ` Patch "libfs: Fix simple_offset_rename_exchange()" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 05/10] libfs: Add simple_offset_rename() API cel
2025-01-30  8:59   ` Patch "libfs: Add simple_offset_rename() API" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 06/10] shmem: Fix shmem_rename2() cel
2025-01-30  8:59   ` Patch "shmem: Fix shmem_rename2()" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 07/10] libfs: Return ENOSPC when the directory offset range is exhausted cel
2025-01-30  8:59   ` Patch "libfs: Return ENOSPC when the directory offset range is exhausted" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 08/10] Revert "libfs: Add simple_offset_empty()" cel
2025-01-30  8:59   ` Patch "Revert "libfs: Add simple_offset_empty()"" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 09/10] libfs: Replace simple_offset end-of-directory detection cel
2025-01-30  8:59   ` Patch "libfs: Replace simple_offset end-of-directory detection" has been added to the 6.6-stable tree gregkh
2025-01-24 19:19 ` [RFC PATCH v6.6 10/10] libfs: Use d_children list to iterate simple_offset directories cel
2025-01-30  8:59   ` Patch "libfs: Use d_children list to iterate simple_offset directories" has been added to the 6.6-stable tree gregkh
2025-01-29 13:55 ` [RFC PATCH v6.6 00/10] Address CVE-2024-46701 Chuck Lever
2025-01-29 14:50   ` Greg Kroah-Hartman
2025-01-29 15:06     ` Chuck Lever
2025-01-29 15:21       ` Greg Kroah-Hartman
2025-01-29 16:37         ` Chuck Lever
2025-01-30  8:45           ` Greg Kroah-Hartman
2025-01-30 14:02             ` Chuck Lever
2025-01-30 14:24               ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox