linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHES] ceph d_name race fixes
@ 2025-06-14  6:20 Al Viro
  2025-06-14  6:22 ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Al Viro
  0 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2025-06-14  6:20 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Viacheslav Dubeyko, ceph-devel

	Series of race fixes for d_name handling in ceph had been posted
back in February, but apparently had fallen through the cracks - I expected
ceph folks to pull (or cherry-pick) it, they apparently thought I'd send
it to Linus and nobody checked what actually went down...

	I've rebased it to 6.16-rc1, with a couple of cosmetical changes
suggested back then.  Currently it's in
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git work.ceph-d_name-fixes
Individual patches in followups.

	Folks, could you test and review it?  I really don't care which
tree would it go through, just let's make sure that everyone agrees who
pushes it out...

Shortlog:
Al Viro (3):
      [ceph] parse_longname(): strrchr() expects NUL-terminated string
      prep for ceph_encode_encrypted_fname() fixes
      ceph: fix a race with rename() in ceph_mdsc_build_path()

Diffstat:
 fs/ceph/caps.c       | 18 +++++-------
 fs/ceph/crypto.c     | 82 +++++++++++++++++-----------------------------------
 fs/ceph/crypto.h     | 18 +++---------
 fs/ceph/dir.c        |  7 ++---
 fs/ceph/mds_client.c |  4 +--
 5 files changed, 43 insertions(+), 86 deletions(-)

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

* [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string
  2025-06-14  6:20 [PATCHES] ceph d_name race fixes Al Viro
@ 2025-06-14  6:22 ` Al Viro
  2025-06-14  6:22   ` [PATCH 2/3] prep for ceph_encode_encrypted_fname() fixes Al Viro
                     ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Al Viro @ 2025-06-14  6:22 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Slava.Dubeyko, ceph-devel

... and parse_longname() is not guaranteed that.  That's the reason
why it uses kmemdup_nul() to build the argument for kstrtou64();
the problem is, kstrtou64() is not the only thing that need it.

Just get a NUL-terminated copy of the entire thing and be done
with that...

Fixes: dd66df0053ef "ceph: add support for encrypted snapshot names"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/ceph/crypto.c | 31 ++++++++++++-------------------
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
index 3b3c4d8d401e..9c7062245880 100644
--- a/fs/ceph/crypto.c
+++ b/fs/ceph/crypto.c
@@ -215,35 +215,31 @@ static struct inode *parse_longname(const struct inode *parent,
 	struct ceph_client *cl = ceph_inode_to_client(parent);
 	struct inode *dir = NULL;
 	struct ceph_vino vino = { .snap = CEPH_NOSNAP };
-	char *inode_number;
-	char *name_end;
-	int orig_len = *name_len;
+	char *name_end, *inode_number;
 	int ret = -EIO;
-
+	/* NUL-terminate */
+	char *str __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL);
+	if (!str)
+		return ERR_PTR(-ENOMEM);
 	/* Skip initial '_' */
-	name++;
-	name_end = strrchr(name, '_');
+	str++;
+	name_end = strrchr(str, '_');
 	if (!name_end) {
-		doutc(cl, "failed to parse long snapshot name: %s\n", name);
+		doutc(cl, "failed to parse long snapshot name: %s\n", str);
 		return ERR_PTR(-EIO);
 	}
-	*name_len = (name_end - name);
+	*name_len = (name_end - str);
 	if (*name_len <= 0) {
 		pr_err_client(cl, "failed to parse long snapshot name\n");
 		return ERR_PTR(-EIO);
 	}
 
 	/* Get the inode number */
-	inode_number = kmemdup_nul(name_end + 1,
-				   orig_len - *name_len - 2,
-				   GFP_KERNEL);
-	if (!inode_number)
-		return ERR_PTR(-ENOMEM);
+	inode_number = name_end + 1;
 	ret = kstrtou64(inode_number, 10, &vino.ino);
 	if (ret) {
-		doutc(cl, "failed to parse inode number: %s\n", name);
-		dir = ERR_PTR(ret);
-		goto out;
+		doutc(cl, "failed to parse inode number: %s\n", str);
+		return ERR_PTR(ret);
 	}
 
 	/* And finally the inode */
@@ -254,9 +250,6 @@ static struct inode *parse_longname(const struct inode *parent,
 		if (IS_ERR(dir))
 			doutc(cl, "can't find inode %s (%s)\n", inode_number, name);
 	}
-
-out:
-	kfree(inode_number);
 	return dir;
 }
 
-- 
2.39.5


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

* [PATCH 2/3] prep for ceph_encode_encrypted_fname() fixes
  2025-06-14  6:22 ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Al Viro
@ 2025-06-14  6:22   ` Al Viro
  2025-06-17 18:20     ` Viacheslav Dubeyko
  2025-06-14  6:22   ` [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path() Al Viro
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2025-06-14  6:22 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Slava.Dubeyko, ceph-devel

ceph_encode_encrypted_dname() would be better off with plaintext name
already copied into buffer; we'll lift that into the callers on the
next step, which will allow to fix UAF on races with rename; for now
copy it in the very beginning of ceph_encode_encrypted_dname().

That has a pleasant side benefit - we don't need to mess with tmp_buf
anymore (i.e. that's 256 bytes off the stack footprint).

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/ceph/crypto.c | 40 +++++++++++++++++-----------------------
 1 file changed, 17 insertions(+), 23 deletions(-)

diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
index 9c7062245880..2aef56fc6275 100644
--- a/fs/ceph/crypto.c
+++ b/fs/ceph/crypto.c
@@ -258,31 +258,28 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
 {
 	struct ceph_client *cl = ceph_inode_to_client(parent);
 	struct inode *dir = parent;
-	struct qstr iname;
+	char *p = buf;
 	u32 len;
 	int name_len;
 	int elen;
 	int ret;
 	u8 *cryptbuf = NULL;
 
-	iname.name = d_name->name;
-	name_len = d_name->len;
+	memcpy(buf, d_name->name, d_name->len);
+	elen = d_name->len;
+
+	name_len = elen;
 
 	/* Handle the special case of snapshot names that start with '_' */
-	if ((ceph_snap(dir) == CEPH_SNAPDIR) && (name_len > 0) &&
-	    (iname.name[0] == '_')) {
-		dir = parse_longname(parent, iname.name, &name_len);
+	if (ceph_snap(dir) == CEPH_SNAPDIR && *p == '_') {
+		dir = parse_longname(parent, p, &name_len);
 		if (IS_ERR(dir))
 			return PTR_ERR(dir);
-		iname.name++; /* skip initial '_' */
+		p++; /* skip initial '_' */
 	}
-	iname.len = name_len;
 
-	if (!fscrypt_has_encryption_key(dir)) {
-		memcpy(buf, d_name->name, d_name->len);
-		elen = d_name->len;
+	if (!fscrypt_has_encryption_key(dir))
 		goto out;
-	}
 
 	/*
 	 * Convert cleartext d_name to ciphertext. If result is longer than
@@ -290,7 +287,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
 	 *
 	 * See: fscrypt_setup_filename
 	 */
-	if (!fscrypt_fname_encrypted_size(dir, iname.len, NAME_MAX, &len)) {
+	if (!fscrypt_fname_encrypted_size(dir, name_len, NAME_MAX, &len)) {
 		elen = -ENAMETOOLONG;
 		goto out;
 	}
@@ -303,7 +300,9 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
 		goto out;
 	}
 
-	ret = fscrypt_fname_encrypt(dir, &iname, cryptbuf, len);
+	ret = fscrypt_fname_encrypt(dir,
+				    &(struct qstr)QSTR_INIT(p, name_len),
+				    cryptbuf, len);
 	if (ret) {
 		elen = ret;
 		goto out;
@@ -324,18 +323,13 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
 	}
 
 	/* base64 encode the encrypted name */
-	elen = ceph_base64_encode(cryptbuf, len, buf);
-	doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, buf);
+	elen = ceph_base64_encode(cryptbuf, len, p);
+	doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, p);
 
 	/* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */
 	WARN_ON(elen > 240);
-	if ((elen > 0) && (dir != parent)) {
-		char tmp_buf[NAME_MAX];
-
-		elen = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld",
-				elen, buf, dir->i_ino);
-		memcpy(buf, tmp_buf, elen);
-	}
+	if (dir != parent) // leading _ is already there; append _<inum>
+		elen += 1 + sprintf(p + elen, "_%ld", dir->i_ino);
 
 out:
 	kfree(cryptbuf);
-- 
2.39.5


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

* [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path()
  2025-06-14  6:22 ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Al Viro
  2025-06-14  6:22   ` [PATCH 2/3] prep for ceph_encode_encrypted_fname() fixes Al Viro
@ 2025-06-14  6:22   ` Al Viro
  2025-06-17 18:21     ` Viacheslav Dubeyko
  2025-06-16 17:42   ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Viacheslav Dubeyko
  2025-06-17 18:20   ` Viacheslav Dubeyko
  3 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2025-06-14  6:22 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Slava.Dubeyko, ceph-devel

Lift copying the name into callers of ceph_encode_encrypted_dname()
that do not have it already copied; ceph_encode_encrypted_fname()
disappears.

That fixes a UAF in ceph_mdsc_build_path() - while the initial copy
of plaintext into buf is done under ->d_lock, we access the
original name again in ceph_encode_encrypted_fname() and that is
done without any locking.  With ceph_encode_encrypted_dname() using
the stable copy the problem goes away.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/ceph/caps.c       | 18 +++++++-----------
 fs/ceph/crypto.c     | 19 ++-----------------
 fs/ceph/crypto.h     | 18 ++++--------------
 fs/ceph/dir.c        |  7 +++----
 fs/ceph/mds_client.c |  4 ++--
 5 files changed, 18 insertions(+), 48 deletions(-)

diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index a8d8b56cf9d2..b1a8ff612c41 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -4957,24 +4957,20 @@ int ceph_encode_dentry_release(void **p, struct dentry *dentry,
 	cl = ceph_inode_to_client(dir);
 	spin_lock(&dentry->d_lock);
 	if (ret && di->lease_session && di->lease_session->s_mds == mds) {
+		int len = dentry->d_name.len;
 		doutc(cl, "%p mds%d seq %d\n",  dentry, mds,
 		      (int)di->lease_seq);
 		rel->dname_seq = cpu_to_le32(di->lease_seq);
 		__ceph_mdsc_drop_dentry_lease(dentry);
+		memcpy(*p, dentry->d_name.name, len);
 		spin_unlock(&dentry->d_lock);
 		if (IS_ENCRYPTED(dir) && fscrypt_has_encryption_key(dir)) {
-			int ret2 = ceph_encode_encrypted_fname(dir, dentry, *p);
-
-			if (ret2 < 0)
-				return ret2;
-
-			rel->dname_len = cpu_to_le32(ret2);
-			*p += ret2;
-		} else {
-			rel->dname_len = cpu_to_le32(dentry->d_name.len);
-			memcpy(*p, dentry->d_name.name, dentry->d_name.len);
-			*p += dentry->d_name.len;
+			len = ceph_encode_encrypted_dname(dir, *p, len);
+			if (len < 0)
+				return len;
 		}
+		rel->dname_len = cpu_to_le32(len);
+		*p += len;
 	} else {
 		spin_unlock(&dentry->d_lock);
 	}
diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
index 2aef56fc6275..e312f52f48e4 100644
--- a/fs/ceph/crypto.c
+++ b/fs/ceph/crypto.c
@@ -253,23 +253,16 @@ static struct inode *parse_longname(const struct inode *parent,
 	return dir;
 }
 
-int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
-				char *buf)
+int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen)
 {
 	struct ceph_client *cl = ceph_inode_to_client(parent);
 	struct inode *dir = parent;
 	char *p = buf;
 	u32 len;
-	int name_len;
-	int elen;
+	int name_len = elen;
 	int ret;
 	u8 *cryptbuf = NULL;
 
-	memcpy(buf, d_name->name, d_name->len);
-	elen = d_name->len;
-
-	name_len = elen;
-
 	/* Handle the special case of snapshot names that start with '_' */
 	if (ceph_snap(dir) == CEPH_SNAPDIR && *p == '_') {
 		dir = parse_longname(parent, p, &name_len);
@@ -342,14 +335,6 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
 	return elen;
 }
 
-int ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentry,
-				char *buf)
-{
-	WARN_ON_ONCE(!fscrypt_has_encryption_key(parent));
-
-	return ceph_encode_encrypted_dname(parent, &dentry->d_name, buf);
-}
-
 /**
  * ceph_fname_to_usr - convert a filename for userland presentation
  * @fname: ceph_fname to be converted
diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h
index d0768239a1c9..f752bbb2eb06 100644
--- a/fs/ceph/crypto.h
+++ b/fs/ceph/crypto.h
@@ -102,10 +102,7 @@ int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode,
 				 struct ceph_acl_sec_ctx *as);
 void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
 				struct ceph_acl_sec_ctx *as);
-int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
-				char *buf);
-int ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentry,
-				char *buf);
+int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int len);
 
 static inline int ceph_fname_alloc_buffer(struct inode *parent,
 					  struct fscrypt_str *fname)
@@ -194,17 +191,10 @@ static inline void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
 {
 }
 
-static inline int ceph_encode_encrypted_dname(struct inode *parent,
-					      struct qstr *d_name, char *buf)
+static inline int ceph_encode_encrypted_dname(struct inode *parent, char *buf,
+					      int len)
 {
-	memcpy(buf, d_name->name, d_name->len);
-	return d_name->len;
-}
-
-static inline int ceph_encode_encrypted_fname(struct inode *parent,
-					      struct dentry *dentry, char *buf)
-{
-	return -EOPNOTSUPP;
+	return len;
 }
 
 static inline int ceph_fname_alloc_buffer(struct inode *parent,
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index a321aa6d0ed2..8478e7e75df6 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -423,17 +423,16 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
 			req->r_inode_drop = CEPH_CAP_FILE_EXCL;
 		}
 		if (dfi->last_name) {
-			struct qstr d_name = { .name = dfi->last_name,
-					       .len = strlen(dfi->last_name) };
+			int len = strlen(dfi->last_name);
 
 			req->r_path2 = kzalloc(NAME_MAX + 1, GFP_KERNEL);
 			if (!req->r_path2) {
 				ceph_mdsc_put_request(req);
 				return -ENOMEM;
 			}
+			memcpy(req->r_path2, dfi->last_name, len);
 
-			err = ceph_encode_encrypted_dname(inode, &d_name,
-							  req->r_path2);
+			err = ceph_encode_encrypted_dname(inode, req->r_path2, len);
 			if (err < 0) {
 				ceph_mdsc_put_request(req);
 				return err;
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 230e0c3f341f..0f497c39ff82 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2766,8 +2766,8 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
 			}
 
 			if (fscrypt_has_encryption_key(d_inode(parent))) {
-				len = ceph_encode_encrypted_fname(d_inode(parent),
-								  cur, buf);
+				len = ceph_encode_encrypted_dname(d_inode(parent),
+								  buf, len);
 				if (len < 0) {
 					dput(parent);
 					dput(cur);
-- 
2.39.5


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

* Re:  [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string
  2025-06-14  6:22 ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Al Viro
  2025-06-14  6:22   ` [PATCH 2/3] prep for ceph_encode_encrypted_fname() fixes Al Viro
  2025-06-14  6:22   ` [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path() Al Viro
@ 2025-06-16 17:42   ` Viacheslav Dubeyko
  2025-06-17 18:20   ` Viacheslav Dubeyko
  3 siblings, 0 replies; 13+ messages in thread
From: Viacheslav Dubeyko @ 2025-06-16 17:42 UTC (permalink / raw)
  To: linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk
  Cc: ceph-devel@vger.kernel.org

On Sat, 2025-06-14 at 07:22 +0100, Al Viro wrote:
> ... and parse_longname() is not guaranteed that.  That's the reason
> why it uses kmemdup_nul() to build the argument for kstrtou64();
> the problem is, kstrtou64() is not the only thing that need it.
> 
> Just get a NUL-terminated copy of the entire thing and be done
> with that...
> 
> Fixes: dd66df0053ef "ceph: add support for encrypted snapshot names"
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---

The patch set looks well and reasonable. Let me spend some time for testing it.
I'll be back ASAP.

Thanks,
Slava.

>  fs/ceph/crypto.c | 31 ++++++++++++-------------------
>  1 file changed, 12 insertions(+), 19 deletions(-)
> 
> diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
> index 3b3c4d8d401e..9c7062245880 100644
> --- a/fs/ceph/crypto.c
> +++ b/fs/ceph/crypto.c
> @@ -215,35 +215,31 @@ static struct inode *parse_longname(const struct inode *parent,
>  	struct ceph_client *cl = ceph_inode_to_client(parent);
>  	struct inode *dir = NULL;
>  	struct ceph_vino vino = { .snap = CEPH_NOSNAP };
> -	char *inode_number;
> -	char *name_end;
> -	int orig_len = *name_len;
> +	char *name_end, *inode_number;
>  	int ret = -EIO;
> -
> +	/* NUL-terminate */
> +	char *str __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL);
> +	if (!str)
> +		return ERR_PTR(-ENOMEM);
>  	/* Skip initial '_' */
> -	name++;
> -	name_end = strrchr(name, '_');
> +	str++;
> +	name_end = strrchr(str, '_');
>  	if (!name_end) {
> -		doutc(cl, "failed to parse long snapshot name: %s\n", name);
> +		doutc(cl, "failed to parse long snapshot name: %s\n", str);
>  		return ERR_PTR(-EIO);
>  	}
> -	*name_len = (name_end - name);
> +	*name_len = (name_end - str);
>  	if (*name_len <= 0) {
>  		pr_err_client(cl, "failed to parse long snapshot name\n");
>  		return ERR_PTR(-EIO);
>  	}
>  
>  	/* Get the inode number */
> -	inode_number = kmemdup_nul(name_end + 1,
> -				   orig_len - *name_len - 2,
> -				   GFP_KERNEL);
> -	if (!inode_number)
> -		return ERR_PTR(-ENOMEM);
> +	inode_number = name_end + 1;
>  	ret = kstrtou64(inode_number, 10, &vino.ino);
>  	if (ret) {
> -		doutc(cl, "failed to parse inode number: %s\n", name);
> -		dir = ERR_PTR(ret);
> -		goto out;
> +		doutc(cl, "failed to parse inode number: %s\n", str);
> +		return ERR_PTR(ret);
>  	}
>  
>  	/* And finally the inode */
> @@ -254,9 +250,6 @@ static struct inode *parse_longname(const struct inode *parent,
>  		if (IS_ERR(dir))
>  			doutc(cl, "can't find inode %s (%s)\n", inode_number, name);
>  	}
> -
> -out:
> -	kfree(inode_number);
>  	return dir;
>  }
>  

-- 
Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>

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

* Re:  [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string
  2025-06-14  6:22 ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Al Viro
                     ` (2 preceding siblings ...)
  2025-06-16 17:42   ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Viacheslav Dubeyko
@ 2025-06-17 18:20   ` Viacheslav Dubeyko
  3 siblings, 0 replies; 13+ messages in thread
From: Viacheslav Dubeyko @ 2025-06-17 18:20 UTC (permalink / raw)
  To: linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk
  Cc: ceph-devel@vger.kernel.org

On Sat, 2025-06-14 at 07:22 +0100, Al Viro wrote:
> ... and parse_longname() is not guaranteed that.  That's the reason
> why it uses kmemdup_nul() to build the argument for kstrtou64();
> the problem is, kstrtou64() is not the only thing that need it.
> 
> Just get a NUL-terminated copy of the entire thing and be done
> with that...
> 
> Fixes: dd66df0053ef "ceph: add support for encrypted snapshot names"
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
>  fs/ceph/crypto.c | 31 ++++++++++++-------------------
>  1 file changed, 12 insertions(+), 19 deletions(-)
> 

I did run xfstests with the patch set. I don't see any issues.

Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>

Thanks,
Slava.

> diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
> index 3b3c4d8d401e..9c7062245880 100644
> --- a/fs/ceph/crypto.c
> +++ b/fs/ceph/crypto.c
> @@ -215,35 +215,31 @@ static struct inode *parse_longname(const struct inode *parent,
>  	struct ceph_client *cl = ceph_inode_to_client(parent);
>  	struct inode *dir = NULL;
>  	struct ceph_vino vino = { .snap = CEPH_NOSNAP };
> -	char *inode_number;
> -	char *name_end;
> -	int orig_len = *name_len;
> +	char *name_end, *inode_number;
>  	int ret = -EIO;
> -
> +	/* NUL-terminate */
> +	char *str __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL);
> +	if (!str)
> +		return ERR_PTR(-ENOMEM);
>  	/* Skip initial '_' */
> -	name++;
> -	name_end = strrchr(name, '_');
> +	str++;
> +	name_end = strrchr(str, '_');
>  	if (!name_end) {
> -		doutc(cl, "failed to parse long snapshot name: %s\n", name);
> +		doutc(cl, "failed to parse long snapshot name: %s\n", str);
>  		return ERR_PTR(-EIO);
>  	}
> -	*name_len = (name_end - name);
> +	*name_len = (name_end - str);
>  	if (*name_len <= 0) {
>  		pr_err_client(cl, "failed to parse long snapshot name\n");
>  		return ERR_PTR(-EIO);
>  	}
>  
>  	/* Get the inode number */
> -	inode_number = kmemdup_nul(name_end + 1,
> -				   orig_len - *name_len - 2,
> -				   GFP_KERNEL);
> -	if (!inode_number)
> -		return ERR_PTR(-ENOMEM);
> +	inode_number = name_end + 1;
>  	ret = kstrtou64(inode_number, 10, &vino.ino);
>  	if (ret) {
> -		doutc(cl, "failed to parse inode number: %s\n", name);
> -		dir = ERR_PTR(ret);
> -		goto out;
> +		doutc(cl, "failed to parse inode number: %s\n", str);
> +		return ERR_PTR(ret);
>  	}
>  
>  	/* And finally the inode */
> @@ -254,9 +250,6 @@ static struct inode *parse_longname(const struct inode *parent,
>  		if (IS_ERR(dir))
>  			doutc(cl, "can't find inode %s (%s)\n", inode_number, name);
>  	}
> -
> -out:
> -	kfree(inode_number);
>  	return dir;
>  }
>  

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

* Re:  [PATCH 2/3] prep for ceph_encode_encrypted_fname() fixes
  2025-06-14  6:22   ` [PATCH 2/3] prep for ceph_encode_encrypted_fname() fixes Al Viro
@ 2025-06-17 18:20     ` Viacheslav Dubeyko
  0 siblings, 0 replies; 13+ messages in thread
From: Viacheslav Dubeyko @ 2025-06-17 18:20 UTC (permalink / raw)
  To: linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk
  Cc: ceph-devel@vger.kernel.org

On Sat, 2025-06-14 at 07:22 +0100, Al Viro wrote:
> ceph_encode_encrypted_dname() would be better off with plaintext name
> already copied into buffer; we'll lift that into the callers on the
> next step, which will allow to fix UAF on races with rename; for now
> copy it in the very beginning of ceph_encode_encrypted_dname().
> 
> That has a pleasant side benefit - we don't need to mess with tmp_buf
> anymore (i.e. that's 256 bytes off the stack footprint).
> 
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
>  fs/ceph/crypto.c | 40 +++++++++++++++++-----------------------
>  1 file changed, 17 insertions(+), 23 deletions(-)
> 

Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>

Thanks,
Slava.

> diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
> index 9c7062245880..2aef56fc6275 100644
> --- a/fs/ceph/crypto.c
> +++ b/fs/ceph/crypto.c
> @@ -258,31 +258,28 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
>  {
>  	struct ceph_client *cl = ceph_inode_to_client(parent);
>  	struct inode *dir = parent;
> -	struct qstr iname;
> +	char *p = buf;
>  	u32 len;
>  	int name_len;
>  	int elen;
>  	int ret;
>  	u8 *cryptbuf = NULL;
>  
> -	iname.name = d_name->name;
> -	name_len = d_name->len;
> +	memcpy(buf, d_name->name, d_name->len);
> +	elen = d_name->len;
> +
> +	name_len = elen;
>  
>  	/* Handle the special case of snapshot names that start with '_' */
> -	if ((ceph_snap(dir) == CEPH_SNAPDIR) && (name_len > 0) &&
> -	    (iname.name[0] == '_')) {
> -		dir = parse_longname(parent, iname.name, &name_len);
> +	if (ceph_snap(dir) == CEPH_SNAPDIR && *p == '_') {
> +		dir = parse_longname(parent, p, &name_len);
>  		if (IS_ERR(dir))
>  			return PTR_ERR(dir);
> -		iname.name++; /* skip initial '_' */
> +		p++; /* skip initial '_' */
>  	}
> -	iname.len = name_len;
>  
> -	if (!fscrypt_has_encryption_key(dir)) {
> -		memcpy(buf, d_name->name, d_name->len);
> -		elen = d_name->len;
> +	if (!fscrypt_has_encryption_key(dir))
>  		goto out;
> -	}
>  
>  	/*
>  	 * Convert cleartext d_name to ciphertext. If result is longer than
> @@ -290,7 +287,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
>  	 *
>  	 * See: fscrypt_setup_filename
>  	 */
> -	if (!fscrypt_fname_encrypted_size(dir, iname.len, NAME_MAX, &len)) {
> +	if (!fscrypt_fname_encrypted_size(dir, name_len, NAME_MAX, &len)) {
>  		elen = -ENAMETOOLONG;
>  		goto out;
>  	}
> @@ -303,7 +300,9 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
>  		goto out;
>  	}
>  
> -	ret = fscrypt_fname_encrypt(dir, &iname, cryptbuf, len);
> +	ret = fscrypt_fname_encrypt(dir,
> +				    &(struct qstr)QSTR_INIT(p, name_len),
> +				    cryptbuf, len);
>  	if (ret) {
>  		elen = ret;
>  		goto out;
> @@ -324,18 +323,13 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
>  	}
>  
>  	/* base64 encode the encrypted name */
> -	elen = ceph_base64_encode(cryptbuf, len, buf);
> -	doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, buf);
> +	elen = ceph_base64_encode(cryptbuf, len, p);
> +	doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, p);
>  
>  	/* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */
>  	WARN_ON(elen > 240);
> -	if ((elen > 0) && (dir != parent)) {
> -		char tmp_buf[NAME_MAX];
> -
> -		elen = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld",
> -				elen, buf, dir->i_ino);
> -		memcpy(buf, tmp_buf, elen);
> -	}
> +	if (dir != parent) // leading _ is already there; append _<inum>
> +		elen += 1 + sprintf(p + elen, "_%ld", dir->i_ino);
>  
>  out:
>  	kfree(cryptbuf);

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

* Re:  [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path()
  2025-06-14  6:22   ` [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path() Al Viro
@ 2025-06-17 18:21     ` Viacheslav Dubeyko
  2025-06-17 22:01       ` Al Viro
  0 siblings, 1 reply; 13+ messages in thread
From: Viacheslav Dubeyko @ 2025-06-17 18:21 UTC (permalink / raw)
  To: linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk
  Cc: ceph-devel@vger.kernel.org

On Sat, 2025-06-14 at 07:22 +0100, Al Viro wrote:
> Lift copying the name into callers of ceph_encode_encrypted_dname()
> that do not have it already copied; ceph_encode_encrypted_fname()
> disappears.
> 
> That fixes a UAF in ceph_mdsc_build_path() - while the initial copy
> of plaintext into buf is done under ->d_lock, we access the
> original name again in ceph_encode_encrypted_fname() and that is
> done without any locking.  With ceph_encode_encrypted_dname() using
> the stable copy the problem goes away.
> 
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
>  fs/ceph/caps.c       | 18 +++++++-----------
>  fs/ceph/crypto.c     | 19 ++-----------------
>  fs/ceph/crypto.h     | 18 ++++--------------
>  fs/ceph/dir.c        |  7 +++----
>  fs/ceph/mds_client.c |  4 ++--
>  5 files changed, 18 insertions(+), 48 deletions(-)
> 

Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>

Thanks,
Slava.

> diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
> index a8d8b56cf9d2..b1a8ff612c41 100644
> --- a/fs/ceph/caps.c
> +++ b/fs/ceph/caps.c
> @@ -4957,24 +4957,20 @@ int ceph_encode_dentry_release(void **p, struct dentry *dentry,
>  	cl = ceph_inode_to_client(dir);
>  	spin_lock(&dentry->d_lock);
>  	if (ret && di->lease_session && di->lease_session->s_mds == mds) {
> +		int len = dentry->d_name.len;
>  		doutc(cl, "%p mds%d seq %d\n",  dentry, mds,
>  		      (int)di->lease_seq);
>  		rel->dname_seq = cpu_to_le32(di->lease_seq);
>  		__ceph_mdsc_drop_dentry_lease(dentry);
> +		memcpy(*p, dentry->d_name.name, len);
>  		spin_unlock(&dentry->d_lock);
>  		if (IS_ENCRYPTED(dir) && fscrypt_has_encryption_key(dir)) {
> -			int ret2 = ceph_encode_encrypted_fname(dir, dentry, *p);
> -
> -			if (ret2 < 0)
> -				return ret2;
> -
> -			rel->dname_len = cpu_to_le32(ret2);
> -			*p += ret2;
> -		} else {
> -			rel->dname_len = cpu_to_le32(dentry->d_name.len);
> -			memcpy(*p, dentry->d_name.name, dentry->d_name.len);
> -			*p += dentry->d_name.len;
> +			len = ceph_encode_encrypted_dname(dir, *p, len);
> +			if (len < 0)
> +				return len;
>  		}
> +		rel->dname_len = cpu_to_le32(len);
> +		*p += len;
>  	} else {
>  		spin_unlock(&dentry->d_lock);
>  	}
> diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
> index 2aef56fc6275..e312f52f48e4 100644
> --- a/fs/ceph/crypto.c
> +++ b/fs/ceph/crypto.c
> @@ -253,23 +253,16 @@ static struct inode *parse_longname(const struct inode *parent,
>  	return dir;
>  }
>  
> -int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
> -				char *buf)
> +int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen)
>  {
>  	struct ceph_client *cl = ceph_inode_to_client(parent);
>  	struct inode *dir = parent;
>  	char *p = buf;
>  	u32 len;
> -	int name_len;
> -	int elen;
> +	int name_len = elen;
>  	int ret;
>  	u8 *cryptbuf = NULL;
>  
> -	memcpy(buf, d_name->name, d_name->len);
> -	elen = d_name->len;
> -
> -	name_len = elen;
> -
>  	/* Handle the special case of snapshot names that start with '_' */
>  	if (ceph_snap(dir) == CEPH_SNAPDIR && *p == '_') {
>  		dir = parse_longname(parent, p, &name_len);
> @@ -342,14 +335,6 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
>  	return elen;
>  }
>  
> -int ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentry,
> -				char *buf)
> -{
> -	WARN_ON_ONCE(!fscrypt_has_encryption_key(parent));
> -
> -	return ceph_encode_encrypted_dname(parent, &dentry->d_name, buf);
> -}
> -
>  /**
>   * ceph_fname_to_usr - convert a filename for userland presentation
>   * @fname: ceph_fname to be converted
> diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h
> index d0768239a1c9..f752bbb2eb06 100644
> --- a/fs/ceph/crypto.h
> +++ b/fs/ceph/crypto.h
> @@ -102,10 +102,7 @@ int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode,
>  				 struct ceph_acl_sec_ctx *as);
>  void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
>  				struct ceph_acl_sec_ctx *as);
> -int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
> -				char *buf);
> -int ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentry,
> -				char *buf);
> +int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int len);
>  
>  static inline int ceph_fname_alloc_buffer(struct inode *parent,
>  					  struct fscrypt_str *fname)
> @@ -194,17 +191,10 @@ static inline void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
>  {
>  }
>  
> -static inline int ceph_encode_encrypted_dname(struct inode *parent,
> -					      struct qstr *d_name, char *buf)
> +static inline int ceph_encode_encrypted_dname(struct inode *parent, char *buf,
> +					      int len)
>  {
> -	memcpy(buf, d_name->name, d_name->len);
> -	return d_name->len;
> -}
> -
> -static inline int ceph_encode_encrypted_fname(struct inode *parent,
> -					      struct dentry *dentry, char *buf)
> -{
> -	return -EOPNOTSUPP;
> +	return len;
>  }
>  
>  static inline int ceph_fname_alloc_buffer(struct inode *parent,
> diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
> index a321aa6d0ed2..8478e7e75df6 100644
> --- a/fs/ceph/dir.c
> +++ b/fs/ceph/dir.c
> @@ -423,17 +423,16 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
>  			req->r_inode_drop = CEPH_CAP_FILE_EXCL;
>  		}
>  		if (dfi->last_name) {
> -			struct qstr d_name = { .name = dfi->last_name,
> -					       .len = strlen(dfi->last_name) };
> +			int len = strlen(dfi->last_name);
>  
>  			req->r_path2 = kzalloc(NAME_MAX + 1, GFP_KERNEL);
>  			if (!req->r_path2) {
>  				ceph_mdsc_put_request(req);
>  				return -ENOMEM;
>  			}
> +			memcpy(req->r_path2, dfi->last_name, len);
>  
> -			err = ceph_encode_encrypted_dname(inode, &d_name,
> -							  req->r_path2);
> +			err = ceph_encode_encrypted_dname(inode, req->r_path2, len);
>  			if (err < 0) {
>  				ceph_mdsc_put_request(req);
>  				return err;
> diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
> index 230e0c3f341f..0f497c39ff82 100644
> --- a/fs/ceph/mds_client.c
> +++ b/fs/ceph/mds_client.c
> @@ -2766,8 +2766,8 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
>  			}
>  
>  			if (fscrypt_has_encryption_key(d_inode(parent))) {
> -				len = ceph_encode_encrypted_fname(d_inode(parent),
> -								  cur, buf);
> +				len = ceph_encode_encrypted_dname(d_inode(parent),
> +								  buf, len);
>  				if (len < 0) {
>  					dput(parent);
>  					dput(cur);

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

* Re: [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path()
  2025-06-17 18:21     ` Viacheslav Dubeyko
@ 2025-06-17 22:01       ` Al Viro
  2025-06-17 22:12         ` Viacheslav Dubeyko
  0 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2025-06-17 22:01 UTC (permalink / raw)
  To: Viacheslav Dubeyko
  Cc: linux-fsdevel@vger.kernel.org, ceph-devel@vger.kernel.org

On Tue, Jun 17, 2025 at 06:21:38PM +0000, Viacheslav Dubeyko wrote:

> Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
> Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>

OK, tested-by/reviewed-by applied to commits in that branch, branch
force-pushed to the same place
(git.kernel.org:/pub/scm/linux/kernel/git/viro/vfs.git work.ceph-d_name-fixes)

Would you prefer to merge it via the ceph tree?  Or I could throw it
into my #for-next and push it to Linus come the next window - up to you...

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

* RE: [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path()
  2025-06-17 22:01       ` Al Viro
@ 2025-06-17 22:12         ` Viacheslav Dubeyko
  2025-06-17 22:15           ` Al Viro
  0 siblings, 1 reply; 13+ messages in thread
From: Viacheslav Dubeyko @ 2025-06-17 22:12 UTC (permalink / raw)
  To: idryomov@gmail.com, viro@zeniv.linux.org.uk
  Cc: ceph-devel@vger.kernel.org, linux-fsdevel@vger.kernel.org

On Tue, 2025-06-17 at 23:01 +0100, Al Viro wrote:
> On Tue, Jun 17, 2025 at 06:21:38PM +0000, Viacheslav Dubeyko wrote:
> 
> > Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
> > Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
> 
> OK, tested-by/reviewed-by applied to commits in that branch, branch
> force-pushed to the same place
> (git.kernel.org:/pub/scm/linux/kernel/git/viro/vfs.git work.ceph-d_name-fixes)
> 
> Would you prefer to merge it via the ceph tree?  Or I could throw it
> into my #for-next and push it to Linus come the next window - up to you...

Frankly speaking, your tree could be the faster way to upstream. However, I can
push this patch set into the ceph tree for more deeper testing in the internal
testing infrastructure. But I don't expect any serious issues in the patches
that could introduce some bugs.

Ilya,

What is your opinion on this? Would you prefer to go through the ceph tree?

Thanks,
Slava.

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

* Re: [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path()
  2025-06-17 22:12         ` Viacheslav Dubeyko
@ 2025-06-17 22:15           ` Al Viro
  2025-06-19 18:04             ` Viacheslav Dubeyko
  0 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2025-06-17 22:15 UTC (permalink / raw)
  To: Viacheslav Dubeyko
  Cc: idryomov@gmail.com, ceph-devel@vger.kernel.org,
	linux-fsdevel@vger.kernel.org

On Tue, Jun 17, 2025 at 10:12:08PM +0000, Viacheslav Dubeyko wrote:
> On Tue, 2025-06-17 at 23:01 +0100, Al Viro wrote:
> > On Tue, Jun 17, 2025 at 06:21:38PM +0000, Viacheslav Dubeyko wrote:
> > 
> > > Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
> > > Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
> > 
> > OK, tested-by/reviewed-by applied to commits in that branch, branch
> > force-pushed to the same place
> > (git.kernel.org:/pub/scm/linux/kernel/git/viro/vfs.git work.ceph-d_name-fixes)
> > 
> > Would you prefer to merge it via the ceph tree?  Or I could throw it
> > into my #for-next and push it to Linus come the next window - up to you...
> 
> Frankly speaking, your tree could be the faster way to upstream. However, I can
> push this patch set into the ceph tree for more deeper testing in the internal
> testing infrastructure. But I don't expect any serious issues in the patches
> that could introduce some bugs.
> 
> Ilya,
> 
> What is your opinion on this? Would you prefer to go through the ceph tree?

I can send a pull request to you now just as easily as I could send it to Linus
a month and a half down the road... ;-)  Up to you, guys.

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

* RE: [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path()
  2025-06-17 22:15           ` Al Viro
@ 2025-06-19 18:04             ` Viacheslav Dubeyko
  2025-06-19 19:53               ` Al Viro
  0 siblings, 1 reply; 13+ messages in thread
From: Viacheslav Dubeyko @ 2025-06-19 18:04 UTC (permalink / raw)
  To: viro@zeniv.linux.org.uk
  Cc: idryomov@gmail.com, ceph-devel@vger.kernel.org,
	linux-fsdevel@vger.kernel.org

On Tue, 2025-06-17 at 23:15 +0100, Al Viro wrote:
> On Tue, Jun 17, 2025 at 10:12:08PM +0000, Viacheslav Dubeyko wrote:
> > On Tue, 2025-06-17 at 23:01 +0100, Al Viro wrote:
> > > On Tue, Jun 17, 2025 at 06:21:38PM +0000, Viacheslav Dubeyko wrote:
> > > 
> > > > Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
> > > > Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
> > > 
> > > OK, tested-by/reviewed-by applied to commits in that branch, branch
> > > force-pushed to the same place
> > > (git.kernel.org:/pub/scm/linux/kernel/git/viro/vfs.git work.ceph-d_name-fixes)
> > > 
> > > Would you prefer to merge it via the ceph tree?  Or I could throw it
> > > into my #for-next and push it to Linus come the next window - up to you...
> > 
> > Frankly speaking, your tree could be the faster way to upstream. However, I can
> > push this patch set into the ceph tree for more deeper testing in the internal
> > testing infrastructure. But I don't expect any serious issues in the patches
> > that could introduce some bugs.
> > 
> > Ilya,
> > 
> > What is your opinion on this? Would you prefer to go through the ceph tree?
> 
> I can send a pull request to you now just as easily as I could send it to Linus
> a month and a half down the road... ;-)  Up to you, guys.

So, if we don't have any other opinion, then let's send the patch set through
your tree.

Thanks,
Slava.

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

* Re: [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path()
  2025-06-19 18:04             ` Viacheslav Dubeyko
@ 2025-06-19 19:53               ` Al Viro
  0 siblings, 0 replies; 13+ messages in thread
From: Al Viro @ 2025-06-19 19:53 UTC (permalink / raw)
  To: Viacheslav Dubeyko
  Cc: idryomov@gmail.com, ceph-devel@vger.kernel.org,
	linux-fsdevel@vger.kernel.org

On Thu, Jun 19, 2025 at 06:04:37PM +0000, Viacheslav Dubeyko wrote:

> > I can send a pull request to you now just as easily as I could send it to Linus
> > a month and a half down the road... ;-)  Up to you, guys.
> 
> So, if we don't have any other opinion, then let's send the patch set through
> your tree.

merged into #for-next, will go to Linus at the next window...

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

end of thread, other threads:[~2025-06-19 19:53 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-14  6:20 [PATCHES] ceph d_name race fixes Al Viro
2025-06-14  6:22 ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Al Viro
2025-06-14  6:22   ` [PATCH 2/3] prep for ceph_encode_encrypted_fname() fixes Al Viro
2025-06-17 18:20     ` Viacheslav Dubeyko
2025-06-14  6:22   ` [PATCH 3/3] ceph: fix a race with rename() in ceph_mdsc_build_path() Al Viro
2025-06-17 18:21     ` Viacheslav Dubeyko
2025-06-17 22:01       ` Al Viro
2025-06-17 22:12         ` Viacheslav Dubeyko
2025-06-17 22:15           ` Al Viro
2025-06-19 18:04             ` Viacheslav Dubeyko
2025-06-19 19:53               ` Al Viro
2025-06-16 17:42   ` [PATCH 1/3] [ceph] parse_longname(): strrchr() expects NUL-terminated string Viacheslav Dubeyko
2025-06-17 18:20   ` Viacheslav Dubeyko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).