Skip to content

Commit edc440e

Browse files
drosen-googleebiggers
authored andcommitted
fscrypt: improve format of no-key names
When an encrypted directory is listed without the key, the filesystem must show "no-key names" that uniquely identify directory entries, are at most 255 (NAME_MAX) bytes long, and don't contain '/' or '\0'. Currently, for short names the no-key name is the base64 encoding of the ciphertext filename, while for long names it's the base64 encoding of the ciphertext filename's dirhash and second-to-last 16-byte block. This format has the following problems: - Since it doesn't always include the dirhash, it's incompatible with directories that will use a secret-keyed dirhash over the plaintext filenames. In this case, the dirhash won't be computable from the ciphertext name without the key, so it instead must be retrieved from the directory entry and always included in the no-key name. Casefolded encrypted directories will use this type of dirhash. - It's ambiguous: it's possible to craft two filenames that map to the same no-key name, since the method used to abbreviate long filenames doesn't use a proper cryptographic hash function. Solve both these problems by switching to a new no-key name format that is the base64 encoding of a variable-length structure that contains the dirhash, up to 149 bytes of the ciphertext filename, and (if any bytes remain) the SHA-256 of the remaining bytes of the ciphertext filename. This ensures that each no-key name contains everything needed to find the directory entry again, contains only legal characters, doesn't exceed NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only take the performance hit of SHA-256 on very long filenames. Note: this change does *not* address the existing issue where users can modify the 'dirhash' part of a no-key name and the filesystem may still accept the name. Signed-off-by: Daniel Rosenberg <[email protected]> [EB: improved comments and commit message, fixed checking return value of base64_decode(), check for SHA-256 error, continue to set disk_name for short names to keep matching simpler, and many other cleanups] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Eric Biggers <[email protected]>
1 parent aec992a commit edc440e

File tree

4 files changed

+171
-127
lines changed

4 files changed

+171
-127
lines changed

Documentation/filesystems/fscrypt.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,7 @@ filesystem-specific hash(es) needed for directory lookups. This
12021202
allows the filesystem to still, with a high degree of confidence, map
12031203
the filename given in ->lookup() back to a particular directory entry
12041204
that was previously listed by readdir(). See :c:type:`struct
1205-
fscrypt_digested_name` in the source for more details.
1205+
fscrypt_nokey_name` in the source for more details.
12061206

12071207
Note that the precise way that filenames are presented to userspace
12081208
without the key is subject to change in the future. It is only meant

fs/crypto/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ config FS_ENCRYPTION_ALGS
2121
select CRYPTO_CTS
2222
select CRYPTO_ECB
2323
select CRYPTO_HMAC
24+
select CRYPTO_SHA256
2425
select CRYPTO_SHA512
2526
select CRYPTO_XTS

fs/crypto/fname.c

Lines changed: 167 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,85 @@
1313

1414
#include <linux/namei.h>
1515
#include <linux/scatterlist.h>
16+
#include <crypto/hash.h>
17+
#include <crypto/sha.h>
1618
#include <crypto/skcipher.h>
1719
#include "fscrypt_private.h"
1820

21+
/**
22+
* struct fscrypt_nokey_name - identifier for directory entry when key is absent
23+
*
24+
* When userspace lists an encrypted directory without access to the key, the
25+
* filesystem must present a unique "no-key name" for each filename that allows
26+
* it to find the directory entry again if requested. Naively, that would just
27+
* mean using the ciphertext filenames. However, since the ciphertext filenames
28+
* can contain illegal characters ('\0' and '/'), they must be encoded in some
29+
* way. We use base64. But that can cause names to exceed NAME_MAX (255
30+
* bytes), so we also need to use a strong hash to abbreviate long names.
31+
*
32+
* The filesystem may also need another kind of hash, the "dirhash", to quickly
33+
* find the directory entry. Since filesystems normally compute the dirhash
34+
* over the on-disk filename (i.e. the ciphertext), it's not computable from
35+
* no-key names that abbreviate the ciphertext using the strong hash to fit in
36+
* NAME_MAX. It's also not computable if it's a keyed hash taken over the
37+
* plaintext (but it may still be available in the on-disk directory entry);
38+
* casefolded directories use this type of dirhash. At least in these cases,
39+
* each no-key name must include the name's dirhash too.
40+
*
41+
* To meet all these requirements, we base64-encode the following
42+
* variable-length structure. It contains the dirhash, or 0's if the filesystem
43+
* didn't provide one; up to 149 bytes of the ciphertext name; and for
44+
* ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes.
45+
*
46+
* This ensures that each no-key name contains everything needed to find the
47+
* directory entry again, contains only legal characters, doesn't exceed
48+
* NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only
49+
* take the performance hit of SHA-256 on very long filenames (which are rare).
50+
*/
51+
struct fscrypt_nokey_name {
52+
u32 dirhash[2];
53+
u8 bytes[149];
54+
u8 sha256[SHA256_DIGEST_SIZE];
55+
}; /* 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) */
56+
57+
/*
58+
* Decoded size of max-size nokey name, i.e. a name that was abbreviated using
59+
* the strong hash and thus includes the 'sha256' field. This isn't simply
60+
* sizeof(struct fscrypt_nokey_name), as the padding at the end isn't included.
61+
*/
62+
#define FSCRYPT_NOKEY_NAME_MAX offsetofend(struct fscrypt_nokey_name, sha256)
63+
64+
static struct crypto_shash *sha256_hash_tfm;
65+
66+
static int fscrypt_do_sha256(const u8 *data, unsigned int data_len, u8 *result)
67+
{
68+
struct crypto_shash *tfm = READ_ONCE(sha256_hash_tfm);
69+
70+
if (unlikely(!tfm)) {
71+
struct crypto_shash *prev_tfm;
72+
73+
tfm = crypto_alloc_shash("sha256", 0, 0);
74+
if (IS_ERR(tfm)) {
75+
fscrypt_err(NULL,
76+
"Error allocating SHA-256 transform: %ld",
77+
PTR_ERR(tfm));
78+
return PTR_ERR(tfm);
79+
}
80+
prev_tfm = cmpxchg(&sha256_hash_tfm, NULL, tfm);
81+
if (prev_tfm) {
82+
crypto_free_shash(tfm);
83+
tfm = prev_tfm;
84+
}
85+
}
86+
{
87+
SHASH_DESC_ON_STACK(desc, tfm);
88+
89+
desc->tfm = tfm;
90+
91+
return crypto_shash_digest(desc, data, data_len, result);
92+
}
93+
}
94+
1995
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
2096
{
2197
if (str->len == 1 && str->name[0] == '.')
@@ -207,9 +283,7 @@ int fscrypt_fname_alloc_buffer(const struct inode *inode,
207283
u32 max_encrypted_len,
208284
struct fscrypt_str *crypto_str)
209285
{
210-
const u32 max_encoded_len =
211-
max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
212-
1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
286+
const u32 max_encoded_len = BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX);
213287
u32 max_presented_len;
214288

215289
max_presented_len = max(max_encoded_len, max_encrypted_len);
@@ -242,9 +316,9 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer);
242316
*
243317
* The caller must have allocated sufficient memory for the @oname string.
244318
*
245-
* If the key is available, we'll decrypt the disk name; otherwise, we'll encode
246-
* it for presentation. Short names are directly base64-encoded, while long
247-
* names are encoded in fscrypt_digested_name format.
319+
* If the key is available, we'll decrypt the disk name. Otherwise, we'll
320+
* encode it for presentation in fscrypt_nokey_name format.
321+
* See struct fscrypt_nokey_name for details.
248322
*
249323
* Return: 0 on success, -errno on failure
250324
*/
@@ -254,7 +328,9 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
254328
struct fscrypt_str *oname)
255329
{
256330
const struct qstr qname = FSTR_TO_QSTR(iname);
257-
struct fscrypt_digested_name digested_name;
331+
struct fscrypt_nokey_name nokey_name;
332+
u32 size; /* size of the unencoded no-key name */
333+
int err;
258334

259335
if (fscrypt_is_dot_dotdot(&qname)) {
260336
oname->name[0] = '.';
@@ -269,24 +345,37 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
269345
if (fscrypt_has_encryption_key(inode))
270346
return fname_decrypt(inode, iname, oname);
271347

272-
if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
273-
oname->len = base64_encode(iname->name, iname->len,
274-
oname->name);
275-
return 0;
276-
}
348+
/*
349+
* Sanity check that struct fscrypt_nokey_name doesn't have padding
350+
* between fields and that its encoded size never exceeds NAME_MAX.
351+
*/
352+
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, dirhash) !=
353+
offsetof(struct fscrypt_nokey_name, bytes));
354+
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, bytes) !=
355+
offsetof(struct fscrypt_nokey_name, sha256));
356+
BUILD_BUG_ON(BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) > NAME_MAX);
357+
277358
if (hash) {
278-
digested_name.hash = hash;
279-
digested_name.minor_hash = minor_hash;
359+
nokey_name.dirhash[0] = hash;
360+
nokey_name.dirhash[1] = minor_hash;
361+
} else {
362+
nokey_name.dirhash[0] = 0;
363+
nokey_name.dirhash[1] = 0;
364+
}
365+
if (iname->len <= sizeof(nokey_name.bytes)) {
366+
memcpy(nokey_name.bytes, iname->name, iname->len);
367+
size = offsetof(struct fscrypt_nokey_name, bytes[iname->len]);
280368
} else {
281-
digested_name.hash = 0;
282-
digested_name.minor_hash = 0;
369+
memcpy(nokey_name.bytes, iname->name, sizeof(nokey_name.bytes));
370+
/* Compute strong hash of remaining part of name. */
371+
err = fscrypt_do_sha256(&iname->name[sizeof(nokey_name.bytes)],
372+
iname->len - sizeof(nokey_name.bytes),
373+
nokey_name.sha256);
374+
if (err)
375+
return err;
376+
size = FSCRYPT_NOKEY_NAME_MAX;
283377
}
284-
memcpy(digested_name.digest,
285-
FSCRYPT_FNAME_DIGEST(iname->name, iname->len),
286-
FSCRYPT_FNAME_DIGEST_SIZE);
287-
oname->name[0] = '_';
288-
oname->len = 1 + base64_encode((const u8 *)&digested_name,
289-
sizeof(digested_name), oname->name + 1);
378+
oname->len = base64_encode((const u8 *)&nokey_name, size, oname->name);
290379
return 0;
291380
}
292381
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
@@ -307,8 +396,7 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
307396
* get the disk_name.
308397
*
309398
* Else, for keyless @lookup operations, @iname is the presented ciphertext, so
310-
* we decode it to get either the ciphertext disk_name (for short names) or the
311-
* fscrypt_digested_name (for long names). Non-@lookup operations will be
399+
* we decode it to get the fscrypt_nokey_name. Non-@lookup operations will be
312400
* impossible in this case, so we fail them with ENOKEY.
313401
*
314402
* If successful, fscrypt_free_filename() must be called later to clean up.
@@ -318,8 +406,8 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
318406
int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
319407
int lookup, struct fscrypt_name *fname)
320408
{
409+
struct fscrypt_nokey_name *nokey_name;
321410
int ret;
322-
int digested;
323411

324412
memset(fname, 0, sizeof(struct fscrypt_name));
325413
fname->usr_fname = iname;
@@ -359,40 +447,31 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
359447
* We don't have the key and we are doing a lookup; decode the
360448
* user-supplied name
361449
*/
362-
if (iname->name[0] == '_') {
363-
if (iname->len !=
364-
1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)))
365-
return -ENOENT;
366-
digested = 1;
367-
} else {
368-
if (iname->len >
369-
BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE))
370-
return -ENOENT;
371-
digested = 0;
372-
}
373450

374-
fname->crypto_buf.name =
375-
kmalloc(max_t(size_t, FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE,
376-
sizeof(struct fscrypt_digested_name)),
377-
GFP_KERNEL);
451+
if (iname->len > BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX))
452+
return -ENOENT;
453+
454+
fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL);
378455
if (fname->crypto_buf.name == NULL)
379456
return -ENOMEM;
380457

381-
ret = base64_decode(iname->name + digested, iname->len - digested,
382-
fname->crypto_buf.name);
383-
if (ret < 0) {
458+
ret = base64_decode(iname->name, iname->len, fname->crypto_buf.name);
459+
if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||
460+
(ret > offsetof(struct fscrypt_nokey_name, sha256) &&
461+
ret != FSCRYPT_NOKEY_NAME_MAX)) {
384462
ret = -ENOENT;
385463
goto errout;
386464
}
387465
fname->crypto_buf.len = ret;
388-
if (digested) {
389-
const struct fscrypt_digested_name *n =
390-
(const void *)fname->crypto_buf.name;
391-
fname->hash = n->hash;
392-
fname->minor_hash = n->minor_hash;
393-
} else {
394-
fname->disk_name.name = fname->crypto_buf.name;
395-
fname->disk_name.len = fname->crypto_buf.len;
466+
467+
nokey_name = (void *)fname->crypto_buf.name;
468+
fname->hash = nokey_name->dirhash[0];
469+
fname->minor_hash = nokey_name->dirhash[1];
470+
if (ret != FSCRYPT_NOKEY_NAME_MAX) {
471+
/* The full ciphertext filename is available. */
472+
fname->disk_name.name = nokey_name->bytes;
473+
fname->disk_name.len =
474+
ret - offsetof(struct fscrypt_nokey_name, bytes);
396475
}
397476
return 0;
398477

@@ -402,6 +481,43 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
402481
}
403482
EXPORT_SYMBOL(fscrypt_setup_filename);
404483

484+
/**
485+
* fscrypt_match_name() - test whether the given name matches a directory entry
486+
* @fname: the name being searched for
487+
* @de_name: the name from the directory entry
488+
* @de_name_len: the length of @de_name in bytes
489+
*
490+
* Normally @fname->disk_name will be set, and in that case we simply compare
491+
* that to the name stored in the directory entry. The only exception is that
492+
* if we don't have the key for an encrypted directory and the name we're
493+
* looking for is very long, then we won't have the full disk_name and instead
494+
* we'll need to match against a fscrypt_nokey_name that includes a strong hash.
495+
*
496+
* Return: %true if the name matches, otherwise %false.
497+
*/
498+
bool fscrypt_match_name(const struct fscrypt_name *fname,
499+
const u8 *de_name, u32 de_name_len)
500+
{
501+
const struct fscrypt_nokey_name *nokey_name =
502+
(const void *)fname->crypto_buf.name;
503+
u8 sha256[SHA256_DIGEST_SIZE];
504+
505+
if (likely(fname->disk_name.name)) {
506+
if (de_name_len != fname->disk_name.len)
507+
return false;
508+
return !memcmp(de_name, fname->disk_name.name, de_name_len);
509+
}
510+
if (de_name_len <= sizeof(nokey_name->bytes))
511+
return false;
512+
if (memcmp(de_name, nokey_name->bytes, sizeof(nokey_name->bytes)))
513+
return false;
514+
if (fscrypt_do_sha256(&de_name[sizeof(nokey_name->bytes)],
515+
de_name_len - sizeof(nokey_name->bytes), sha256))
516+
return false;
517+
return !memcmp(sha256, nokey_name->sha256, sizeof(sha256));
518+
}
519+
EXPORT_SYMBOL_GPL(fscrypt_match_name);
520+
405521
/**
406522
* fscrypt_fname_siphash() - calculate the SipHash of a filename
407523
* @dir: the parent directory

include/linux/fscrypt.h

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -172,81 +172,8 @@ extern int fscrypt_fname_disk_to_usr(const struct inode *inode,
172172
u32 hash, u32 minor_hash,
173173
const struct fscrypt_str *iname,
174174
struct fscrypt_str *oname);
175-
176-
#define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32
177-
178-
/* Extracts the second-to-last ciphertext block; see explanation below */
179-
#define FSCRYPT_FNAME_DIGEST(name, len) \
180-
((name) + round_down((len) - FS_CRYPTO_BLOCK_SIZE - 1, \
181-
FS_CRYPTO_BLOCK_SIZE))
182-
183-
#define FSCRYPT_FNAME_DIGEST_SIZE FS_CRYPTO_BLOCK_SIZE
184-
185-
/**
186-
* fscrypt_digested_name - alternate identifier for an on-disk filename
187-
*
188-
* When userspace lists an encrypted directory without access to the key,
189-
* filenames whose ciphertext is longer than FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE
190-
* bytes are shown in this abbreviated form (base64-encoded) rather than as the
191-
* full ciphertext (base64-encoded). This is necessary to allow supporting
192-
* filenames up to NAME_MAX bytes, since base64 encoding expands the length.
193-
*
194-
* To make it possible for filesystems to still find the correct directory entry
195-
* despite not knowing the full on-disk name, we encode any filesystem-specific
196-
* 'hash' and/or 'minor_hash' which the filesystem may need for its lookups,
197-
* followed by the second-to-last ciphertext block of the filename. Due to the
198-
* use of the CBC-CTS encryption mode, the second-to-last ciphertext block
199-
* depends on the full plaintext. (Note that ciphertext stealing causes the
200-
* last two blocks to appear "flipped".) This makes accidental collisions very
201-
* unlikely: just a 1 in 2^128 chance for two filenames to collide even if they
202-
* share the same filesystem-specific hashes.
203-
*
204-
* However, this scheme isn't immune to intentional collisions, which can be
205-
* created by anyone able to create arbitrary plaintext filenames and view them
206-
* without the key. Making the "digest" be a real cryptographic hash like
207-
* SHA-256 over the full ciphertext would prevent this, although it would be
208-
* less efficient and harder to implement, especially since the filesystem would
209-
* need to calculate it for each directory entry examined during a search.
210-
*/
211-
struct fscrypt_digested_name {
212-
u32 hash;
213-
u32 minor_hash;
214-
u8 digest[FSCRYPT_FNAME_DIGEST_SIZE];
215-
};
216-
217-
/**
218-
* fscrypt_match_name() - test whether the given name matches a directory entry
219-
* @fname: the name being searched for
220-
* @de_name: the name from the directory entry
221-
* @de_name_len: the length of @de_name in bytes
222-
*
223-
* Normally @fname->disk_name will be set, and in that case we simply compare
224-
* that to the name stored in the directory entry. The only exception is that
225-
* if we don't have the key for an encrypted directory and a filename in it is
226-
* very long, then we won't have the full disk_name and we'll instead need to
227-
* match against the fscrypt_digested_name.
228-
*
229-
* Return: %true if the name matches, otherwise %false.
230-
*/
231-
static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
232-
const u8 *de_name, u32 de_name_len)
233-
{
234-
if (unlikely(!fname->disk_name.name)) {
235-
const struct fscrypt_digested_name *n =
236-
(const void *)fname->crypto_buf.name;
237-
if (WARN_ON_ONCE(fname->usr_fname->name[0] != '_'))
238-
return false;
239-
if (de_name_len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE)
240-
return false;
241-
return !memcmp(FSCRYPT_FNAME_DIGEST(de_name, de_name_len),
242-
n->digest, FSCRYPT_FNAME_DIGEST_SIZE);
243-
}
244-
245-
if (de_name_len != fname->disk_name.len)
246-
return false;
247-
return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
248-
}
249-
175+
extern bool fscrypt_match_name(const struct fscrypt_name *fname,
176+
const u8 *de_name, u32 de_name_len);
250177
extern u64 fscrypt_fname_siphash(const struct inode *dir,
251178
const struct qstr *name);
252179

0 commit comments

Comments
 (0)