aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2017-04-24 13:00:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2017-05-04 11:44:37 -0400
commit17159420a6c18bb3515ff85598b5ccf1a572763d (patch)
tree562afc39b20e061cbdfaaf6e2db7854da95fbb45
parent6b06cdee81d68a8a829ad8e8d0f31d6836744af9 (diff)
fscrypt: introduce helper function for filename matching
Introduce a helper function fscrypt_match_name() which tests whether a fscrypt_name matches a directory entry. Also clean up the magic numbers and document things properly. Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/crypto/fname.c90
-rw-r--r--fs/crypto/fscrypt_private.h2
-rw-r--r--include/linux/fscrypt_notsupp.h9
-rw-r--r--include/linux/fscrypt_supp.h78
4 files changed, 157 insertions, 22 deletions
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 15bf9c31a34d..d1bb02b1ee58 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -159,6 +159,8 @@ static int fname_decrypt(struct inode *inode,
159static const char *lookup_table = 159static const char *lookup_table =
160 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; 160 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
161 161
162#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
163
162/** 164/**
163 * digest_encode() - 165 * digest_encode() -
164 * 166 *
@@ -230,11 +232,14 @@ EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
230int fscrypt_fname_alloc_buffer(const struct inode *inode, 232int fscrypt_fname_alloc_buffer(const struct inode *inode,
231 u32 ilen, struct fscrypt_str *crypto_str) 233 u32 ilen, struct fscrypt_str *crypto_str)
232{ 234{
233 unsigned int olen = fscrypt_fname_encrypted_size(inode, ilen); 235 u32 olen = fscrypt_fname_encrypted_size(inode, ilen);
236 const u32 max_encoded_len =
237 max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
238 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
234 239
235 crypto_str->len = olen; 240 crypto_str->len = olen;
236 if (olen < FS_FNAME_CRYPTO_DIGEST_SIZE * 2) 241 olen = max(olen, max_encoded_len);
237 olen = FS_FNAME_CRYPTO_DIGEST_SIZE * 2; 242
238 /* 243 /*
239 * Allocated buffer can hold one more character to null-terminate the 244 * Allocated buffer can hold one more character to null-terminate the
240 * string 245 * string
@@ -266,6 +271,10 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer);
266 * 271 *
267 * The caller must have allocated sufficient memory for the @oname string. 272 * The caller must have allocated sufficient memory for the @oname string.
268 * 273 *
274 * If the key is available, we'll decrypt the disk name; otherwise, we'll encode
275 * it for presentation. Short names are directly base64-encoded, while long
276 * names are encoded in fscrypt_digested_name format.
277 *
269 * Return: 0 on success, -errno on failure 278 * Return: 0 on success, -errno on failure
270 */ 279 */
271int fscrypt_fname_disk_to_usr(struct inode *inode, 280int fscrypt_fname_disk_to_usr(struct inode *inode,
@@ -274,7 +283,7 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
274 struct fscrypt_str *oname) 283 struct fscrypt_str *oname)
275{ 284{
276 const struct qstr qname = FSTR_TO_QSTR(iname); 285 const struct qstr qname = FSTR_TO_QSTR(iname);
277 char buf[24]; 286 struct fscrypt_digested_name digested_name;
278 287
279 if (fscrypt_is_dot_dotdot(&qname)) { 288 if (fscrypt_is_dot_dotdot(&qname)) {
280 oname->name[0] = '.'; 289 oname->name[0] = '.';
@@ -289,20 +298,24 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
289 if (inode->i_crypt_info) 298 if (inode->i_crypt_info)
290 return fname_decrypt(inode, iname, oname); 299 return fname_decrypt(inode, iname, oname);
291 300
292 if (iname->len <= FS_FNAME_CRYPTO_DIGEST_SIZE) { 301 if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
293 oname->len = digest_encode(iname->name, iname->len, 302 oname->len = digest_encode(iname->name, iname->len,
294 oname->name); 303 oname->name);
295 return 0; 304 return 0;
296 } 305 }
297 if (hash) { 306 if (hash) {
298 memcpy(buf, &hash, 4); 307 digested_name.hash = hash;
299 memcpy(buf + 4, &minor_hash, 4); 308 digested_name.minor_hash = minor_hash;
300 } else { 309 } else {
301 memset(buf, 0, 8); 310 digested_name.hash = 0;
311 digested_name.minor_hash = 0;
302 } 312 }
303 memcpy(buf + 8, iname->name + ((iname->len - 17) & ~15), 16); 313 memcpy(digested_name.digest,
314 FSCRYPT_FNAME_DIGEST(iname->name, iname->len),
315 FSCRYPT_FNAME_DIGEST_SIZE);
304 oname->name[0] = '_'; 316 oname->name[0] = '_';
305 oname->len = 1 + digest_encode(buf, 24, oname->name + 1); 317 oname->len = 1 + digest_encode((const char *)&digested_name,
318 sizeof(digested_name), oname->name + 1);
306 return 0; 319 return 0;
307} 320}
308EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); 321EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
@@ -336,10 +349,35 @@ int fscrypt_fname_usr_to_disk(struct inode *inode,
336} 349}
337EXPORT_SYMBOL(fscrypt_fname_usr_to_disk); 350EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
338 351
352/**
353 * fscrypt_setup_filename() - prepare to search a possibly encrypted directory
354 * @dir: the directory that will be searched
355 * @iname: the user-provided filename being searched for
356 * @lookup: 1 if we're allowed to proceed without the key because it's
357 * ->lookup() or we're finding the dir_entry for deletion; 0 if we cannot
358 * proceed without the key because we're going to create the dir_entry.
359 * @fname: the filename information to be filled in
360 *
361 * Given a user-provided filename @iname, this function sets @fname->disk_name
362 * to the name that would be stored in the on-disk directory entry, if possible.
363 * If the directory is unencrypted this is simply @iname. Else, if we have the
364 * directory's encryption key, then @iname is the plaintext, so we encrypt it to
365 * get the disk_name.
366 *
367 * Else, for keyless @lookup operations, @iname is the presented ciphertext, so
368 * we decode it to get either the ciphertext disk_name (for short names) or the
369 * fscrypt_digested_name (for long names). Non-@lookup operations will be
370 * impossible in this case, so we fail them with ENOKEY.
371 *
372 * If successful, fscrypt_free_filename() must be called later to clean up.
373 *
374 * Return: 0 on success, -errno on failure
375 */
339int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, 376int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
340 int lookup, struct fscrypt_name *fname) 377 int lookup, struct fscrypt_name *fname)
341{ 378{
342 int ret = 0, bigname = 0; 379 int ret;
380 int digested;
343 381
344 memset(fname, 0, sizeof(struct fscrypt_name)); 382 memset(fname, 0, sizeof(struct fscrypt_name));
345 fname->usr_fname = iname; 383 fname->usr_fname = iname;
@@ -373,25 +411,37 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
373 * We don't have the key and we are doing a lookup; decode the 411 * We don't have the key and we are doing a lookup; decode the
374 * user-supplied name 412 * user-supplied name
375 */ 413 */
376 if (iname->name[0] == '_') 414 if (iname->name[0] == '_') {
377 bigname = 1; 415 if (iname->len !=
378 if ((bigname && (iname->len != 33)) || (!bigname && (iname->len > 43))) 416 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)))
379 return -ENOENT; 417 return -ENOENT;
418 digested = 1;
419 } else {
420 if (iname->len >
421 BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE))
422 return -ENOENT;
423 digested = 0;
424 }
380 425
381 fname->crypto_buf.name = kmalloc(32, GFP_KERNEL); 426 fname->crypto_buf.name =
427 kmalloc(max_t(size_t, FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE,
428 sizeof(struct fscrypt_digested_name)),
429 GFP_KERNEL);
382 if (fname->crypto_buf.name == NULL) 430 if (fname->crypto_buf.name == NULL)
383 return -ENOMEM; 431 return -ENOMEM;
384 432
385 ret = digest_decode(iname->name + bigname, iname->len - bigname, 433 ret = digest_decode(iname->name + digested, iname->len - digested,
386 fname->crypto_buf.name); 434 fname->crypto_buf.name);
387 if (ret < 0) { 435 if (ret < 0) {
388 ret = -ENOENT; 436 ret = -ENOENT;
389 goto errout; 437 goto errout;
390 } 438 }
391 fname->crypto_buf.len = ret; 439 fname->crypto_buf.len = ret;
392 if (bigname) { 440 if (digested) {
393 memcpy(&fname->hash, fname->crypto_buf.name, 4); 441 const struct fscrypt_digested_name *n =
394 memcpy(&fname->minor_hash, fname->crypto_buf.name + 4, 4); 442 (const void *)fname->crypto_buf.name;
443 fname->hash = n->hash;
444 fname->minor_hash = n->minor_hash;
395 } else { 445 } else {
396 fname->disk_name.name = fname->crypto_buf.name; 446 fname->disk_name.name = fname->crypto_buf.name;
397 fname->disk_name.len = fname->crypto_buf.len; 447 fname->disk_name.len = fname->crypto_buf.len;
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index e08ca6d1ca0f..1e1f8a361b75 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -13,8 +13,6 @@
13 13
14#include <linux/fscrypt_supp.h> 14#include <linux/fscrypt_supp.h>
15 15
16#define FS_FNAME_CRYPTO_DIGEST_SIZE 32
17
18/* Encryption parameters */ 16/* Encryption parameters */
19#define FS_XTS_TWEAK_SIZE 16 17#define FS_XTS_TWEAK_SIZE 16
20#define FS_AES_128_ECB_KEY_SIZE 16 18#define FS_AES_128_ECB_KEY_SIZE 16
diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h
index 3511ca798804..ec406aed2f2f 100644
--- a/include/linux/fscrypt_notsupp.h
+++ b/include/linux/fscrypt_notsupp.h
@@ -147,6 +147,15 @@ static inline int fscrypt_fname_usr_to_disk(struct inode *inode,
147 return -EOPNOTSUPP; 147 return -EOPNOTSUPP;
148} 148}
149 149
150static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
151 const u8 *de_name, u32 de_name_len)
152{
153 /* Encryption support disabled; use standard comparison */
154 if (de_name_len != fname->disk_name.len)
155 return false;
156 return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
157}
158
150/* bio.c */ 159/* bio.c */
151static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, 160static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx,
152 struct bio *bio) 161 struct bio *bio)
diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h
index a140f47e9b27..e12c224a0d1e 100644
--- a/include/linux/fscrypt_supp.h
+++ b/include/linux/fscrypt_supp.h
@@ -57,6 +57,84 @@ extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
57extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, 57extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
58 struct fscrypt_str *); 58 struct fscrypt_str *);
59 59
60#define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32
61
62/* Extracts the second-to-last ciphertext block; see explanation below */
63#define FSCRYPT_FNAME_DIGEST(name, len) \
64 ((name) + round_down((len) - FS_CRYPTO_BLOCK_SIZE - 1, \
65 FS_CRYPTO_BLOCK_SIZE))
66
67#define FSCRYPT_FNAME_DIGEST_SIZE FS_CRYPTO_BLOCK_SIZE
68
69/**
70 * fscrypt_digested_name - alternate identifier for an on-disk filename
71 *
72 * When userspace lists an encrypted directory without access to the key,
73 * filenames whose ciphertext is longer than FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE
74 * bytes are shown in this abbreviated form (base64-encoded) rather than as the
75 * full ciphertext (base64-encoded). This is necessary to allow supporting
76 * filenames up to NAME_MAX bytes, since base64 encoding expands the length.
77 *
78 * To make it possible for filesystems to still find the correct directory entry
79 * despite not knowing the full on-disk name, we encode any filesystem-specific
80 * 'hash' and/or 'minor_hash' which the filesystem may need for its lookups,
81 * followed by the second-to-last ciphertext block of the filename. Due to the
82 * use of the CBC-CTS encryption mode, the second-to-last ciphertext block
83 * depends on the full plaintext. (Note that ciphertext stealing causes the
84 * last two blocks to appear "flipped".) This makes collisions very unlikely:
85 * just a 1 in 2^128 chance for two filenames to collide even if they share the
86 * same filesystem-specific hashes.
87 *
88 * This scheme isn't strictly immune to intentional collisions because it's
89 * basically like a CBC-MAC, which isn't secure on variable-length inputs.
90 * However, generating a CBC-MAC collision requires the ability to choose
91 * arbitrary ciphertext, which won't normally be possible with filename
92 * encryption since it would require write access to the raw disk.
93 *
94 * Taking a real cryptographic hash like SHA-256 over the full ciphertext would
95 * be better in theory but would be less efficient and more complicated to
96 * implement, especially since the filesystem would need to calculate it for
97 * each directory entry examined during a search.
98 */
99struct fscrypt_digested_name {
100 u32 hash;
101 u32 minor_hash;
102 u8 digest[FSCRYPT_FNAME_DIGEST_SIZE];
103};
104
105/**
106 * fscrypt_match_name() - test whether the given name matches a directory entry
107 * @fname: the name being searched for
108 * @de_name: the name from the directory entry
109 * @de_name_len: the length of @de_name in bytes
110 *
111 * Normally @fname->disk_name will be set, and in that case we simply compare
112 * that to the name stored in the directory entry. The only exception is that
113 * if we don't have the key for an encrypted directory and a filename in it is
114 * very long, then we won't have the full disk_name and we'll instead need to
115 * match against the fscrypt_digested_name.
116 *
117 * Return: %true if the name matches, otherwise %false.
118 */
119static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
120 const u8 *de_name, u32 de_name_len)
121{
122 if (unlikely(!fname->disk_name.name)) {
123 const struct fscrypt_digested_name *n =
124 (const void *)fname->crypto_buf.name;
125 if (WARN_ON_ONCE(fname->usr_fname->name[0] != '_'))
126 return false;
127 if (de_name_len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE)
128 return false;
129 return !memcmp(FSCRYPT_FNAME_DIGEST(de_name, de_name_len),
130 n->digest, FSCRYPT_FNAME_DIGEST_SIZE);
131 }
132
133 if (de_name_len != fname->disk_name.len)
134 return false;
135 return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
136}
137
60/* bio.c */ 138/* bio.c */
61extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); 139extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
62extern void fscrypt_pullback_bio_page(struct page **, bool); 140extern void fscrypt_pullback_bio_page(struct page **, bool);