mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
prep for ceph_encode_encrypted_fname() fixes
ceph_encode_encrypted_dname() would be better off with plaintext name already copied into buffer; we'll lift that into the callers on the next step, which will allow to fix UAF on races with rename; for now copy it in the very beginning of ceph_encode_encrypted_dname(). That has a pleasant side benefit - we don't need to mess with tmp_buf anymore (i.e. that's 256 bytes off the stack footprint). 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:
parent
101841c383
commit
28032ef879
|
|
@ -258,31 +258,28 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
|
|||
{
|
||||
struct ceph_client *cl = ceph_inode_to_client(parent);
|
||||
struct inode *dir = parent;
|
||||
struct qstr iname;
|
||||
char *p = buf;
|
||||
u32 len;
|
||||
int name_len;
|
||||
int elen;
|
||||
int ret;
|
||||
u8 *cryptbuf = NULL;
|
||||
|
||||
iname.name = d_name->name;
|
||||
name_len = d_name->len;
|
||||
memcpy(buf, d_name->name, d_name->len);
|
||||
elen = d_name->len;
|
||||
|
||||
name_len = elen;
|
||||
|
||||
/* Handle the special case of snapshot names that start with '_' */
|
||||
if ((ceph_snap(dir) == CEPH_SNAPDIR) && (name_len > 0) &&
|
||||
(iname.name[0] == '_')) {
|
||||
dir = parse_longname(parent, iname.name, &name_len);
|
||||
if (ceph_snap(dir) == CEPH_SNAPDIR && *p == '_') {
|
||||
dir = parse_longname(parent, p, &name_len);
|
||||
if (IS_ERR(dir))
|
||||
return PTR_ERR(dir);
|
||||
iname.name++; /* skip initial '_' */
|
||||
p++; /* skip initial '_' */
|
||||
}
|
||||
iname.len = name_len;
|
||||
|
||||
if (!fscrypt_has_encryption_key(dir)) {
|
||||
memcpy(buf, d_name->name, d_name->len);
|
||||
elen = d_name->len;
|
||||
if (!fscrypt_has_encryption_key(dir))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert cleartext d_name to ciphertext. If result is longer than
|
||||
|
|
@ -290,7 +287,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
|
|||
*
|
||||
* See: fscrypt_setup_filename
|
||||
*/
|
||||
if (!fscrypt_fname_encrypted_size(dir, iname.len, NAME_MAX, &len)) {
|
||||
if (!fscrypt_fname_encrypted_size(dir, name_len, NAME_MAX, &len)) {
|
||||
elen = -ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -303,7 +300,9 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = fscrypt_fname_encrypt(dir, &iname, cryptbuf, len);
|
||||
ret = fscrypt_fname_encrypt(dir,
|
||||
&(struct qstr)QSTR_INIT(p, name_len),
|
||||
cryptbuf, len);
|
||||
if (ret) {
|
||||
elen = ret;
|
||||
goto out;
|
||||
|
|
@ -324,18 +323,13 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
|
|||
}
|
||||
|
||||
/* base64 encode the encrypted name */
|
||||
elen = ceph_base64_encode(cryptbuf, len, buf);
|
||||
doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, buf);
|
||||
elen = ceph_base64_encode(cryptbuf, len, p);
|
||||
doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, p);
|
||||
|
||||
/* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */
|
||||
WARN_ON(elen > 240);
|
||||
if ((elen > 0) && (dir != parent)) {
|
||||
char tmp_buf[NAME_MAX];
|
||||
|
||||
elen = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld",
|
||||
elen, buf, dir->i_ino);
|
||||
memcpy(buf, tmp_buf, elen);
|
||||
}
|
||||
if (dir != parent) // leading _ is already there; append _<inum>
|
||||
elen += 1 + sprintf(p + elen, "_%ld", dir->i_ino);
|
||||
|
||||
out:
|
||||
kfree(cryptbuf);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user