Skip to content

Commit 28032ef

Browse files
author
Al Viro
committed
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>
1 parent 101841c commit 28032ef

1 file changed

Lines changed: 17 additions & 23 deletions

File tree

fs/ceph/crypto.c

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -258,39 +258,36 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
258258
{
259259
struct ceph_client *cl = ceph_inode_to_client(parent);
260260
struct inode *dir = parent;
261-
struct qstr iname;
261+
char *p = buf;
262262
u32 len;
263263
int name_len;
264264
int elen;
265265
int ret;
266266
u8 *cryptbuf = NULL;
267267

268-
iname.name = d_name->name;
269-
name_len = d_name->len;
268+
memcpy(buf, d_name->name, d_name->len);
269+
elen = d_name->len;
270+
271+
name_len = elen;
270272

271273
/* Handle the special case of snapshot names that start with '_' */
272-
if ((ceph_snap(dir) == CEPH_SNAPDIR) && (name_len > 0) &&
273-
(iname.name[0] == '_')) {
274-
dir = parse_longname(parent, iname.name, &name_len);
274+
if (ceph_snap(dir) == CEPH_SNAPDIR && *p == '_') {
275+
dir = parse_longname(parent, p, &name_len);
275276
if (IS_ERR(dir))
276277
return PTR_ERR(dir);
277-
iname.name++; /* skip initial '_' */
278+
p++; /* skip initial '_' */
278279
}
279-
iname.len = name_len;
280280

281-
if (!fscrypt_has_encryption_key(dir)) {
282-
memcpy(buf, d_name->name, d_name->len);
283-
elen = d_name->len;
281+
if (!fscrypt_has_encryption_key(dir))
284282
goto out;
285-
}
286283

287284
/*
288285
* Convert cleartext d_name to ciphertext. If result is longer than
289286
* CEPH_NOHASH_NAME_MAX, sha256 the remaining bytes
290287
*
291288
* See: fscrypt_setup_filename
292289
*/
293-
if (!fscrypt_fname_encrypted_size(dir, iname.len, NAME_MAX, &len)) {
290+
if (!fscrypt_fname_encrypted_size(dir, name_len, NAME_MAX, &len)) {
294291
elen = -ENAMETOOLONG;
295292
goto out;
296293
}
@@ -303,7 +300,9 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
303300
goto out;
304301
}
305302

306-
ret = fscrypt_fname_encrypt(dir, &iname, cryptbuf, len);
303+
ret = fscrypt_fname_encrypt(dir,
304+
&(struct qstr)QSTR_INIT(p, name_len),
305+
cryptbuf, len);
307306
if (ret) {
308307
elen = ret;
309308
goto out;
@@ -324,18 +323,13 @@ int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
324323
}
325324

326325
/* base64 encode the encrypted name */
327-
elen = ceph_base64_encode(cryptbuf, len, buf);
328-
doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, buf);
326+
elen = ceph_base64_encode(cryptbuf, len, p);
327+
doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, p);
329328

330329
/* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */
331330
WARN_ON(elen > 240);
332-
if ((elen > 0) && (dir != parent)) {
333-
char tmp_buf[NAME_MAX];
334-
335-
elen = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld",
336-
elen, buf, dir->i_ino);
337-
memcpy(buf, tmp_buf, elen);
338-
}
331+
if (dir != parent) // leading _ is already there; append _<inum>
332+
elen += 1 + sprintf(p + elen, "_%ld", dir->i_ino);
339333

340334
out:
341335
kfree(cryptbuf);

0 commit comments

Comments
 (0)