]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
ceph: bound encrypted snapshot suffix formatting
authorPengpeng Hou <pengpeng@iscas.ac.cn>
Thu, 9 Apr 2026 02:39:25 +0000 (10:39 +0800)
committerViacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Fri, 10 Apr 2026 20:42:34 +0000 (13:42 -0700)
ceph_encode_encrypted_dname() base64-encodes the encrypted snapshot
name into the caller buffer and then, for long snapshot names, appends
_<ino> 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 <pengpeng@iscas.ac.cn>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
fs/ceph/crypto.c

index dce6fdf700e1266882b20ca98cfad7bd95bdbcdd..8335543fcb5585cd6500bf1b6b0a908d9c0a9426 100644 (file)
 #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 _<inum>
-               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 _<inum> */
+               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);