From 71975d6e0db17646102488cf54480fda9de0f7a7 Mon Sep 17 00:00:00 2001 From: Jiangshan Yi Date: Tue, 8 Sep 2026 11:18:23 +0800 Subject: [PATCH] ceph: fix longname buffer overflow in ceph_fname_to_usr() Snapshot longname reconstruction formats "__" via snprintf() and memcpy()s the result into oname->name. Checking the length against NAME_MAX only protects the LOOKUPNAME/export callers, whose buffer is allocated with fscrypt_fname_alloc_buffer(NAME_MAX). The readdir path points oname->name straight at the altname in the MDS reply, whose capacity is altname_len; the reconstructed name can exceed that while still fitting under NAME_MAX, overflowing the in-place destination. Save the actual oname->len before the decryption overwrites it, and fail with -ENAMETOOLONG when the reconstructed name would not fit. Cc: stable@vger.kernel.org Fixes: dd66df0053ef ("ceph: add support for encrypted snapshot names") Suggested-by: Alex Markuze Signed-off-by: Jiangshan Yi Reviewed-by: Alex Markuze Signed-off-by: Ilya Dryomov --- fs/ceph/crypto.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index bc0a097a4cea..845b69ba890c 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -313,6 +313,7 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, unsigned char *tname, struct fscrypt_str iname; char *name = fname->name; int name_len = fname->name_len; + int dst_len; int ret; if (WARN_ON_ONCE(tname && is_vmalloc_addr(tname))) @@ -387,6 +388,9 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, unsigned char *tname, iname.len = fname->ctext_len; } + /* oname->len is overwritten by the decryption below */ + dst_len = oname->len; + _oname.name = unlikely(is_vmalloc_addr(oname->name)) ? tname : oname->name; _oname.len = oname->len; @@ -403,6 +407,10 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, unsigned char *tname, name_len = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%llu", oname->len, oname->name, dir->i_ino); + if (name_len > dst_len) { + ret = -ENAMETOOLONG; + goto out; + } memcpy(oname->name, tmp_buf, name_len); oname->len = name_len; }