Commit 0e1fc5ef470cc1d157005c437a434868d59fead4
Committed by
Tyler Hicks
1 parent
7762e230fd
Exists in
master
and in
4 other branches
eCryptfs: verify authentication tokens before their use
Authentication tokens content may change if another requestor calls the update() method of the corresponding key. The new function ecryptfs_verify_auth_tok_from_key() retrieves the authentication token from the provided key and verifies if it is still valid before being used to encrypt or decrypt an eCryptfs file. Signed-off-by: Roberto Sassu <roberto.sassu@polito.it> [tyhicks: Minor formatting changes] Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
Showing 3 changed files with 135 additions and 81 deletions Side-by-side Diff
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/keystore.c
... | ... | @@ -65,6 +65,24 @@ |
65 | 65 | return rc; |
66 | 66 | } |
67 | 67 | |
68 | +static int process_find_global_auth_tok_for_sig_err(int err_code) | |
69 | +{ | |
70 | + int rc = err_code; | |
71 | + | |
72 | + switch (err_code) { | |
73 | + case -ENOENT: | |
74 | + ecryptfs_printk(KERN_WARNING, "Missing auth tok\n"); | |
75 | + break; | |
76 | + case -EINVAL: | |
77 | + ecryptfs_printk(KERN_WARNING, "Invalid auth tok\n"); | |
78 | + break; | |
79 | + default: | |
80 | + rc = process_request_key_err(err_code); | |
81 | + break; | |
82 | + } | |
83 | + return rc; | |
84 | +} | |
85 | + | |
68 | 86 | /** |
69 | 87 | * ecryptfs_parse_packet_length |
70 | 88 | * @data: Pointer to memory containing length at offset |
71 | 89 | |
72 | 90 | |
73 | 91 | |
74 | 92 | |
75 | 93 | |
76 | 94 | |
... | ... | @@ -403,27 +421,117 @@ |
403 | 421 | return rc; |
404 | 422 | } |
405 | 423 | |
424 | +/** | |
425 | + * ecryptfs_verify_version | |
426 | + * @version: The version number to confirm | |
427 | + * | |
428 | + * Returns zero on good version; non-zero otherwise | |
429 | + */ | |
430 | +static int ecryptfs_verify_version(u16 version) | |
431 | +{ | |
432 | + int rc = 0; | |
433 | + unsigned char major; | |
434 | + unsigned char minor; | |
435 | + | |
436 | + major = ((version >> 8) & 0xFF); | |
437 | + minor = (version & 0xFF); | |
438 | + if (major != ECRYPTFS_VERSION_MAJOR) { | |
439 | + ecryptfs_printk(KERN_ERR, "Major version number mismatch. " | |
440 | + "Expected [%d]; got [%d]\n", | |
441 | + ECRYPTFS_VERSION_MAJOR, major); | |
442 | + rc = -EINVAL; | |
443 | + goto out; | |
444 | + } | |
445 | + if (minor != ECRYPTFS_VERSION_MINOR) { | |
446 | + ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " | |
447 | + "Expected [%d]; got [%d]\n", | |
448 | + ECRYPTFS_VERSION_MINOR, minor); | |
449 | + rc = -EINVAL; | |
450 | + goto out; | |
451 | + } | |
452 | +out: | |
453 | + return rc; | |
454 | +} | |
455 | + | |
456 | +/** | |
457 | + * ecryptfs_verify_auth_tok_from_key | |
458 | + * @auth_tok_key: key containing the authentication token | |
459 | + * @auth_tok: authentication token | |
460 | + * | |
461 | + * Returns zero on valid auth tok; -EINVAL otherwise | |
462 | + */ | |
406 | 463 | static int |
464 | +ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, | |
465 | + struct ecryptfs_auth_tok **auth_tok) | |
466 | +{ | |
467 | + int rc = 0; | |
468 | + | |
469 | + (*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key); | |
470 | + if (ecryptfs_verify_version((*auth_tok)->version)) { | |
471 | + printk(KERN_ERR "Data structure version mismatch. Userspace " | |
472 | + "tools must match eCryptfs kernel module with major " | |
473 | + "version [%d] and minor version [%d]\n", | |
474 | + ECRYPTFS_VERSION_MAJOR, ECRYPTFS_VERSION_MINOR); | |
475 | + rc = -EINVAL; | |
476 | + goto out; | |
477 | + } | |
478 | + if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD | |
479 | + && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) { | |
480 | + printk(KERN_ERR "Invalid auth_tok structure " | |
481 | + "returned from key query\n"); | |
482 | + rc = -EINVAL; | |
483 | + goto out; | |
484 | + } | |
485 | +out: | |
486 | + return rc; | |
487 | +} | |
488 | + | |
489 | +static int | |
407 | 490 | ecryptfs_find_global_auth_tok_for_sig( |
408 | - struct ecryptfs_global_auth_tok **global_auth_tok, | |
491 | + struct key **auth_tok_key, | |
492 | + struct ecryptfs_auth_tok **auth_tok, | |
409 | 493 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig) |
410 | 494 | { |
411 | 495 | struct ecryptfs_global_auth_tok *walker; |
412 | 496 | int rc = 0; |
413 | 497 | |
414 | - (*global_auth_tok) = NULL; | |
498 | + (*auth_tok_key) = NULL; | |
499 | + (*auth_tok) = NULL; | |
415 | 500 | mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); |
416 | 501 | list_for_each_entry(walker, |
417 | 502 | &mount_crypt_stat->global_auth_tok_list, |
418 | 503 | mount_crypt_stat_list) { |
419 | - if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX) == 0) { | |
420 | - rc = key_validate(walker->global_auth_tok_key); | |
421 | - if (!rc) | |
422 | - (*global_auth_tok) = walker; | |
504 | + if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX)) | |
505 | + continue; | |
506 | + | |
507 | + if (walker->flags & ECRYPTFS_AUTH_TOK_INVALID) { | |
508 | + rc = -EINVAL; | |
423 | 509 | goto out; |
424 | 510 | } |
511 | + | |
512 | + rc = key_validate(walker->global_auth_tok_key); | |
513 | + if (rc) { | |
514 | + if (rc == -EKEYEXPIRED) | |
515 | + goto out; | |
516 | + goto out_invalid_auth_tok; | |
517 | + } | |
518 | + | |
519 | + rc = ecryptfs_verify_auth_tok_from_key( | |
520 | + walker->global_auth_tok_key, auth_tok); | |
521 | + if (rc) | |
522 | + goto out_invalid_auth_tok; | |
523 | + | |
524 | + (*auth_tok_key) = walker->global_auth_tok_key; | |
525 | + key_get(*auth_tok_key); | |
526 | + goto out; | |
425 | 527 | } |
426 | - rc = -EINVAL; | |
528 | + rc = -ENOENT; | |
529 | + goto out; | |
530 | +out_invalid_auth_tok: | |
531 | + printk(KERN_WARNING "Invalidating auth tok with sig = [%s]\n", sig); | |
532 | + walker->flags |= ECRYPTFS_AUTH_TOK_INVALID; | |
533 | + key_put(walker->global_auth_tok_key); | |
534 | + walker->global_auth_tok_key = NULL; | |
427 | 535 | out: |
428 | 536 | mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); |
429 | 537 | return rc; |
430 | 538 | |
... | ... | @@ -451,14 +559,11 @@ |
451 | 559 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat, |
452 | 560 | char *sig) |
453 | 561 | { |
454 | - struct ecryptfs_global_auth_tok *global_auth_tok; | |
455 | 562 | int rc = 0; |
456 | 563 | |
457 | - (*auth_tok_key) = NULL; | |
458 | - (*auth_tok) = NULL; | |
459 | - if (ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, | |
460 | - mount_crypt_stat, sig)) { | |
461 | - | |
564 | + rc = ecryptfs_find_global_auth_tok_for_sig(auth_tok_key, auth_tok, | |
565 | + mount_crypt_stat, sig); | |
566 | + if (rc == -ENOENT) { | |
462 | 567 | /* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the |
463 | 568 | * mount_crypt_stat structure, we prevent to use auth toks that |
464 | 569 | * are not inserted through the ecryptfs_add_global_auth_tok |
... | ... | @@ -470,8 +575,7 @@ |
470 | 575 | |
471 | 576 | rc = ecryptfs_keyring_auth_tok_for_sig(auth_tok_key, auth_tok, |
472 | 577 | sig); |
473 | - } else | |
474 | - (*auth_tok) = global_auth_tok->global_auth_tok; | |
578 | + } | |
475 | 579 | return rc; |
476 | 580 | } |
477 | 581 | |
... | ... | @@ -1520,38 +1624,6 @@ |
1520 | 1624 | return rc; |
1521 | 1625 | } |
1522 | 1626 | |
1523 | -/** | |
1524 | - * ecryptfs_verify_version | |
1525 | - * @version: The version number to confirm | |
1526 | - * | |
1527 | - * Returns zero on good version; non-zero otherwise | |
1528 | - */ | |
1529 | -static int ecryptfs_verify_version(u16 version) | |
1530 | -{ | |
1531 | - int rc = 0; | |
1532 | - unsigned char major; | |
1533 | - unsigned char minor; | |
1534 | - | |
1535 | - major = ((version >> 8) & 0xFF); | |
1536 | - minor = (version & 0xFF); | |
1537 | - if (major != ECRYPTFS_VERSION_MAJOR) { | |
1538 | - ecryptfs_printk(KERN_ERR, "Major version number mismatch. " | |
1539 | - "Expected [%d]; got [%d]\n", | |
1540 | - ECRYPTFS_VERSION_MAJOR, major); | |
1541 | - rc = -EINVAL; | |
1542 | - goto out; | |
1543 | - } | |
1544 | - if (minor != ECRYPTFS_VERSION_MINOR) { | |
1545 | - ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " | |
1546 | - "Expected [%d]; got [%d]\n", | |
1547 | - ECRYPTFS_VERSION_MINOR, minor); | |
1548 | - rc = -EINVAL; | |
1549 | - goto out; | |
1550 | - } | |
1551 | -out: | |
1552 | - return rc; | |
1553 | -} | |
1554 | - | |
1555 | 1627 | int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, |
1556 | 1628 | struct ecryptfs_auth_tok **auth_tok, |
1557 | 1629 | char *sig) |
1558 | 1630 | |
... | ... | @@ -1566,29 +1638,12 @@ |
1566 | 1638 | (*auth_tok_key) = NULL; |
1567 | 1639 | goto out; |
1568 | 1640 | } |
1569 | - (*auth_tok) = ecryptfs_get_key_payload_data(*auth_tok_key); | |
1570 | - if (ecryptfs_verify_version((*auth_tok)->version)) { | |
1571 | - printk(KERN_ERR | |
1572 | - "Data structure version mismatch. " | |
1573 | - "Userspace tools must match eCryptfs " | |
1574 | - "kernel module with major version [%d] " | |
1575 | - "and minor version [%d]\n", | |
1576 | - ECRYPTFS_VERSION_MAJOR, | |
1577 | - ECRYPTFS_VERSION_MINOR); | |
1578 | - rc = -EINVAL; | |
1579 | - goto out_release_key; | |
1580 | - } | |
1581 | - if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD | |
1582 | - && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) { | |
1583 | - printk(KERN_ERR "Invalid auth_tok structure " | |
1584 | - "returned from key query\n"); | |
1585 | - rc = -EINVAL; | |
1586 | - goto out_release_key; | |
1587 | - } | |
1588 | -out_release_key: | |
1641 | + | |
1642 | + rc = ecryptfs_verify_auth_tok_from_key(*auth_tok_key, auth_tok); | |
1589 | 1643 | if (rc) { |
1590 | 1644 | key_put(*auth_tok_key); |
1591 | 1645 | (*auth_tok_key) = NULL; |
1646 | + goto out; | |
1592 | 1647 | } |
1593 | 1648 | out: |
1594 | 1649 | return rc; |
... | ... | @@ -2325,7 +2380,7 @@ |
2325 | 2380 | size_t max) |
2326 | 2381 | { |
2327 | 2382 | struct ecryptfs_auth_tok *auth_tok; |
2328 | - struct ecryptfs_global_auth_tok *global_auth_tok; | |
2383 | + struct key *auth_tok_key = NULL; | |
2329 | 2384 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat = |
2330 | 2385 | &ecryptfs_superblock_to_private( |
2331 | 2386 | ecryptfs_dentry->d_sb)->mount_crypt_stat; |
2332 | 2387 | |
2333 | 2388 | |
... | ... | @@ -2344,21 +2399,16 @@ |
2344 | 2399 | list_for_each_entry(key_sig, &crypt_stat->keysig_list, |
2345 | 2400 | crypt_stat_list) { |
2346 | 2401 | memset(key_rec, 0, sizeof(*key_rec)); |
2347 | - rc = ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, | |
2402 | + rc = ecryptfs_find_global_auth_tok_for_sig(&auth_tok_key, | |
2403 | + &auth_tok, | |
2348 | 2404 | mount_crypt_stat, |
2349 | 2405 | key_sig->keysig); |
2350 | 2406 | if (rc) { |
2351 | - printk(KERN_ERR "Error attempting to get the global " | |
2352 | - "auth_tok; rc = [%d]\n", rc); | |
2407 | + printk(KERN_WARNING "Unable to retrieve auth tok with " | |
2408 | + "sig = [%s]\n", key_sig->keysig); | |
2409 | + rc = process_find_global_auth_tok_for_sig_err(rc); | |
2353 | 2410 | goto out_free; |
2354 | 2411 | } |
2355 | - if (global_auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID) { | |
2356 | - printk(KERN_WARNING | |
2357 | - "Skipping invalid auth tok with sig = [%s]\n", | |
2358 | - global_auth_tok->sig); | |
2359 | - continue; | |
2360 | - } | |
2361 | - auth_tok = global_auth_tok->global_auth_tok; | |
2362 | 2412 | if (auth_tok->token_type == ECRYPTFS_PASSWORD) { |
2363 | 2413 | rc = write_tag_3_packet((dest_base + (*len)), |
2364 | 2414 | &max, auth_tok, |
... | ... | @@ -2396,6 +2446,8 @@ |
2396 | 2446 | rc = -EINVAL; |
2397 | 2447 | goto out_free; |
2398 | 2448 | } |
2449 | + key_put(auth_tok_key); | |
2450 | + auth_tok_key = NULL; | |
2399 | 2451 | } |
2400 | 2452 | if (likely(max > 0)) { |
2401 | 2453 | dest_base[(*len)] = 0x00; |
... | ... | @@ -2408,6 +2460,9 @@ |
2408 | 2460 | out: |
2409 | 2461 | if (rc) |
2410 | 2462 | (*len) = 0; |
2463 | + if (auth_tok_key) | |
2464 | + key_put(auth_tok_key); | |
2465 | + | |
2411 | 2466 | mutex_unlock(&crypt_stat->keysig_list_mutex); |
2412 | 2467 | return rc; |
2413 | 2468 | } |
fs/ecryptfs/main.c
... | ... | @@ -239,14 +239,14 @@ |
239 | 239 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat) |
240 | 240 | { |
241 | 241 | struct ecryptfs_global_auth_tok *global_auth_tok; |
242 | + struct ecryptfs_auth_tok *auth_tok; | |
242 | 243 | int rc = 0; |
243 | 244 | |
244 | 245 | list_for_each_entry(global_auth_tok, |
245 | 246 | &mount_crypt_stat->global_auth_tok_list, |
246 | 247 | mount_crypt_stat_list) { |
247 | 248 | rc = ecryptfs_keyring_auth_tok_for_sig( |
248 | - &global_auth_tok->global_auth_tok_key, | |
249 | - &global_auth_tok->global_auth_tok, | |
249 | + &global_auth_tok->global_auth_tok_key, &auth_tok, | |
250 | 250 | global_auth_tok->sig); |
251 | 251 | if (rc) { |
252 | 252 | printk(KERN_ERR "Could not find valid key in user " |