Commit 0e1fc5ef470cc1d157005c437a434868d59fead4

Authored by Roberto Sassu
Committed by Tyler Hicks
1 parent 7762e230fd

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
... ... @@ -331,7 +331,6 @@
331 331 u32 flags;
332 332 struct list_head mount_crypt_stat_list;
333 333 struct key *global_auth_tok_key;
334   - struct ecryptfs_auth_tok *global_auth_tok;
335 334 unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
336 335 };
337 336  
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 }
... ... @@ -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 "