[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 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;
}