From: Pengpeng Hou Date: Thu, 9 Apr 2026 02:39:25 +0000 (+0800) Subject: ceph: bound encrypted snapshot suffix formatting X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=94ea8c5309f4db4450b6847500932d112e1a32e3;p=ceph-client.git ceph: bound encrypted snapshot suffix formatting ceph_encode_encrypted_dname() base64-encodes the encrypted snapshot name into the caller buffer and then, for long snapshot names, appends _ with sprintf(p + elen, ...). Some callers only provide NAME_MAX bytes. For long snapshot names, a large inode suffix can push the final encoded name past NAME_MAX even though the encrypted prefix stayed within the documented 240-byte budget. Format the suffix into a small local buffer first and reject names whose suffix would exceed the caller's NAME_MAX output buffer. Signed-off-by: Pengpeng Hou Reviewed-by: Viacheslav Dubeyko Tested-by: Viacheslav Dubeyko --- diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index dce6fdf700e1..8335543fcb55 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -15,6 +15,12 @@ #include "mds_client.h" #include "crypto.h" +/* + * Reserve room for '_' + decimal 64-bit inode number + trailing NUL. + * ceph_encode_encrypted_dname() copies only the visible suffix bytes. + */ +#define CEPH_ENCRYPTED_SNAP_INO_SUFFIX_MAX sizeof("_18446744073709551615") + static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len) { struct ceph_inode_info *ci = ceph_inode(inode); @@ -209,6 +215,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen) struct inode *dir = parent; char *p = buf; u32 len; + int prefix_len = 0; int name_len = elen; int ret; u8 *cryptbuf = NULL; @@ -219,6 +226,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen) if (IS_ERR(dir)) return PTR_ERR(dir); p++; /* skip initial '_' */ + prefix_len = 1; } if (!fscrypt_has_encryption_key(dir)) @@ -271,8 +279,27 @@ int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen) /* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */ WARN_ON(elen > 240); - if (dir != parent) // leading _ is already there; append _ - elen += 1 + sprintf(p + elen, "_%ld", dir->i_ino); + if (elen > 240) { + elen = -ENAMETOOLONG; + goto out; + } + + if (dir != parent) { + int total_len; + /* leading '_' is already there; append _ */ + char suffix[CEPH_ENCRYPTED_SNAP_INO_SUFFIX_MAX]; + + ret = snprintf(suffix, sizeof(suffix), "_%lu", dir->i_ino); + total_len = prefix_len + elen + ret; + if (total_len > NAME_MAX) { + elen = -ENAMETOOLONG; + goto out; + } + + memcpy(p + elen, suffix, ret); + /* Include the leading '_' skipped by p. */ + elen = total_len; + } out: kfree(cryptbuf);