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