[ceph] parse_longname(): strrchr() expects NUL-terminated string

... 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: dd66df0053 "ceph: add support for encrypted snapshot names"
Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2025-02-18 17:57:17 -05:00
parent 19272b37aa
commit 101841c383

View File

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