Skip to content

Commit 457117f

Browse files
jtlaytonidryomov
authored andcommitted
ceph: add helpers for converting names for userland presentation
Define a new ceph_fname struct that we can use to carry information about encrypted dentry names. Add helpers for working with these objects, including ceph_fname_to_usr which formats an encrypted filename for userland presentation. [ xiubli: fix resulting name length check -- neither name_len nor ctext_len should exceed NAME_MAX ] Signed-off-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Xiubo Li <xiubli@redhat.com> Reviewed-and-tested-by: Luís Henriques <lhenriques@suse.de> Reviewed-by: Milind Changire <mchangir@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
1 parent c526760 commit 457117f

2 files changed

Lines changed: 123 additions & 0 deletions

File tree

fs/ceph/crypto.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,80 @@ int ceph_encode_encrypted_fname(const struct inode *parent,
244244
dout("base64-encoded ciphertext name = %.*s\n", elen, buf);
245245
return elen;
246246
}
247+
248+
/**
249+
* ceph_fname_to_usr - convert a filename for userland presentation
250+
* @fname: ceph_fname to be converted
251+
* @tname: temporary name buffer to use for conversion (may be NULL)
252+
* @oname: where converted name should be placed
253+
* @is_nokey: set to true if key wasn't available during conversion (may be NULL)
254+
*
255+
* Given a filename (usually from the MDS), format it for presentation to
256+
* userland. If @parent is not encrypted, just pass it back as-is.
257+
*
258+
* Otherwise, base64 decode the string, and then ask fscrypt to format it
259+
* for userland presentation.
260+
*
261+
* Returns 0 on success or negative error code on error.
262+
*/
263+
int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
264+
struct fscrypt_str *oname, bool *is_nokey)
265+
{
266+
int ret;
267+
struct fscrypt_str _tname = FSTR_INIT(NULL, 0);
268+
struct fscrypt_str iname;
269+
270+
if (!IS_ENCRYPTED(fname->dir)) {
271+
oname->name = fname->name;
272+
oname->len = fname->name_len;
273+
return 0;
274+
}
275+
276+
/* Sanity check that the resulting name will fit in the buffer */
277+
if (fname->name_len > NAME_MAX || fname->ctext_len > NAME_MAX)
278+
return -EIO;
279+
280+
ret = __fscrypt_prepare_readdir(fname->dir);
281+
if (ret)
282+
return ret;
283+
284+
/*
285+
* Use the raw dentry name as sent by the MDS instead of
286+
* generating a nokey name via fscrypt.
287+
*/
288+
if (!fscrypt_has_encryption_key(fname->dir)) {
289+
memcpy(oname->name, fname->name, fname->name_len);
290+
oname->len = fname->name_len;
291+
if (is_nokey)
292+
*is_nokey = true;
293+
return 0;
294+
}
295+
296+
if (fname->ctext_len == 0) {
297+
int declen;
298+
299+
if (!tname) {
300+
ret = fscrypt_fname_alloc_buffer(NAME_MAX, &_tname);
301+
if (ret)
302+
return ret;
303+
tname = &_tname;
304+
}
305+
306+
declen = ceph_base64_decode(fname->name, fname->name_len,
307+
tname->name);
308+
if (declen <= 0) {
309+
ret = -EIO;
310+
goto out;
311+
}
312+
iname.name = tname->name;
313+
iname.len = declen;
314+
} else {
315+
iname.name = fname->ctext;
316+
iname.len = fname->ctext_len;
317+
}
318+
319+
ret = fscrypt_fname_disk_to_usr(fname->dir, 0, 0, &iname, oname);
320+
out:
321+
fscrypt_fname_free_buffer(&_tname);
322+
return ret;
323+
}

fs/ceph/crypto.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ struct ceph_fs_client;
1313
struct ceph_acl_sec_ctx;
1414
struct ceph_mds_request;
1515

16+
struct ceph_fname {
17+
struct inode *dir;
18+
char *name; // b64 encoded, possibly hashed
19+
unsigned char *ctext; // binary crypttext (if any)
20+
u32 name_len; // length of name buffer
21+
u32 ctext_len; // length of crypttext
22+
};
23+
1624
struct ceph_fscrypt_auth {
1725
__le32 cfa_version;
1826
__le32 cfa_blob_len;
@@ -71,6 +79,24 @@ void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
7179
int ceph_encode_encrypted_fname(const struct inode *parent,
7280
struct dentry *dentry, char *buf);
7381

82+
static inline int ceph_fname_alloc_buffer(struct inode *parent,
83+
struct fscrypt_str *fname)
84+
{
85+
if (!IS_ENCRYPTED(parent))
86+
return 0;
87+
return fscrypt_fname_alloc_buffer(NAME_MAX, fname);
88+
}
89+
90+
static inline void ceph_fname_free_buffer(struct inode *parent,
91+
struct fscrypt_str *fname)
92+
{
93+
if (IS_ENCRYPTED(parent))
94+
fscrypt_fname_free_buffer(fname);
95+
}
96+
97+
int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
98+
struct fscrypt_str *oname, bool *is_nokey);
99+
74100
#else /* CONFIG_FS_ENCRYPTION */
75101

76102
static inline void ceph_fscrypt_set_ops(struct super_block *sb)
@@ -100,6 +126,26 @@ static inline int ceph_encode_encrypted_fname(const struct inode *parent,
100126
{
101127
return -EOPNOTSUPP;
102128
}
129+
130+
static inline int ceph_fname_alloc_buffer(struct inode *parent,
131+
struct fscrypt_str *fname)
132+
{
133+
return 0;
134+
}
135+
136+
static inline void ceph_fname_free_buffer(struct inode *parent,
137+
struct fscrypt_str *fname)
138+
{
139+
}
140+
141+
static inline int ceph_fname_to_usr(const struct ceph_fname *fname,
142+
struct fscrypt_str *tname,
143+
struct fscrypt_str *oname, bool *is_nokey)
144+
{
145+
oname->name = fname->name;
146+
oname->len = fname->name_len;
147+
return 0;
148+
}
103149
#endif /* CONFIG_FS_ENCRYPTION */
104150

105151
#endif

0 commit comments

Comments
 (0)