diff options
| -rw-r--r-- | fs/ext4/crypto.c | 56 | ||||
| -rw-r--r-- | fs/ext4/dir.c | 6 | ||||
| -rw-r--r-- | fs/ext4/ext4.h | 1 | ||||
| -rw-r--r-- | fs/ext4/namei.c | 18 |
4 files changed, 81 insertions, 0 deletions
diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index c8021208a7eb..38f7562489bb 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c | |||
| @@ -467,3 +467,59 @@ uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size) | |||
| 467 | return size; | 467 | return size; |
| 468 | return 0; | 468 | return 0; |
| 469 | } | 469 | } |
| 470 | |||
| 471 | /* | ||
| 472 | * Validate dentries for encrypted directories to make sure we aren't | ||
| 473 | * potentially caching stale data after a key has been added or | ||
| 474 | * removed. | ||
| 475 | */ | ||
| 476 | static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags) | ||
| 477 | { | ||
| 478 | struct inode *dir = d_inode(dentry->d_parent); | ||
| 479 | struct ext4_crypt_info *ci = EXT4_I(dir)->i_crypt_info; | ||
| 480 | int dir_has_key, cached_with_key; | ||
| 481 | |||
| 482 | if (!ext4_encrypted_inode(dir)) | ||
| 483 | return 0; | ||
| 484 | |||
| 485 | if (ci && ci->ci_keyring_key && | ||
| 486 | (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | | ||
| 487 | (1 << KEY_FLAG_REVOKED) | | ||
| 488 | (1 << KEY_FLAG_DEAD)))) | ||
| 489 | ci = NULL; | ||
| 490 | |||
| 491 | /* this should eventually be an flag in d_flags */ | ||
| 492 | cached_with_key = dentry->d_fsdata != NULL; | ||
| 493 | dir_has_key = (ci != NULL); | ||
| 494 | |||
| 495 | /* | ||
| 496 | * If the dentry was cached without the key, and it is a | ||
| 497 | * negative dentry, it might be a valid name. We can't check | ||
| 498 | * if the key has since been made available due to locking | ||
| 499 | * reasons, so we fail the validation so ext4_lookup() can do | ||
| 500 | * this check. | ||
| 501 | * | ||
| 502 | * We also fail the validation if the dentry was created with | ||
| 503 | * the key present, but we no longer have the key, or vice versa. | ||
| 504 | */ | ||
| 505 | if ((!cached_with_key && d_is_negative(dentry)) || | ||
| 506 | (!cached_with_key && dir_has_key) || | ||
| 507 | (cached_with_key && !dir_has_key)) { | ||
| 508 | #if 0 /* Revalidation debug */ | ||
| 509 | char buf[80]; | ||
| 510 | char *cp = simple_dname(dentry, buf, sizeof(buf)); | ||
| 511 | |||
| 512 | if (IS_ERR(cp)) | ||
| 513 | cp = (char *) "???"; | ||
| 514 | pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata, | ||
| 515 | cached_with_key, d_is_negative(dentry), | ||
| 516 | dir_has_key); | ||
| 517 | #endif | ||
| 518 | return 0; | ||
| 519 | } | ||
| 520 | return 1; | ||
| 521 | } | ||
| 522 | |||
| 523 | const struct dentry_operations ext4_encrypted_d_ops = { | ||
| 524 | .d_revalidate = ext4_d_revalidate, | ||
| 525 | }; | ||
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 1d1bca74f844..6d17f31a31d7 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
| @@ -111,6 +111,12 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) | |||
| 111 | int dir_has_error = 0; | 111 | int dir_has_error = 0; |
| 112 | struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; | 112 | struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; |
| 113 | 113 | ||
| 114 | if (ext4_encrypted_inode(inode)) { | ||
| 115 | err = ext4_get_encryption_info(inode); | ||
| 116 | if (err && err != -ENOKEY) | ||
| 117 | return err; | ||
| 118 | } | ||
| 119 | |||
| 114 | if (is_dx_dir(inode)) { | 120 | if (is_dx_dir(inode)) { |
| 115 | err = ext4_dx_readdir(file, ctx); | 121 | err = ext4_dx_readdir(file, ctx); |
| 116 | if (err != ERR_BAD_DX_DIR) { | 122 | if (err != ERR_BAD_DX_DIR) { |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0662b285dc8a..157b458a69d4 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -2302,6 +2302,7 @@ struct page *ext4_encrypt(struct inode *inode, | |||
| 2302 | int ext4_decrypt(struct page *page); | 2302 | int ext4_decrypt(struct page *page); |
| 2303 | int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk, | 2303 | int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk, |
| 2304 | ext4_fsblk_t pblk, ext4_lblk_t len); | 2304 | ext4_fsblk_t pblk, ext4_lblk_t len); |
| 2305 | extern const struct dentry_operations ext4_encrypted_d_ops; | ||
| 2305 | 2306 | ||
| 2306 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | 2307 | #ifdef CONFIG_EXT4_FS_ENCRYPTION |
| 2307 | int ext4_init_crypto(void); | 2308 | int ext4_init_crypto(void); |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 06574dd77614..5de8483f0062 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -1558,6 +1558,24 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi | |||
| 1558 | struct ext4_dir_entry_2 *de; | 1558 | struct ext4_dir_entry_2 *de; |
| 1559 | struct buffer_head *bh; | 1559 | struct buffer_head *bh; |
| 1560 | 1560 | ||
| 1561 | if (ext4_encrypted_inode(dir)) { | ||
| 1562 | int res = ext4_get_encryption_info(dir); | ||
| 1563 | |||
| 1564 | /* | ||
| 1565 | * This should be a properly defined flag for | ||
| 1566 | * dentry->d_flags when we uplift this to the VFS. | ||
| 1567 | * d_fsdata is set to (void *) 1 if if the dentry is | ||
| 1568 | * created while the directory was encrypted and we | ||
| 1569 | * don't have access to the key. | ||
| 1570 | */ | ||
| 1571 | dentry->d_fsdata = NULL; | ||
| 1572 | if (ext4_encryption_info(dir)) | ||
| 1573 | dentry->d_fsdata = (void *) 1; | ||
| 1574 | d_set_d_op(dentry, &ext4_encrypted_d_ops); | ||
| 1575 | if (res && res != -ENOKEY) | ||
| 1576 | return ERR_PTR(res); | ||
| 1577 | } | ||
| 1578 | |||
| 1561 | if (dentry->d_name.len > EXT4_NAME_LEN) | 1579 | if (dentry->d_name.len > EXT4_NAME_LEN) |
| 1562 | return ERR_PTR(-ENAMETOOLONG); | 1580 | return ERR_PTR(-ENAMETOOLONG); |
| 1563 | 1581 | ||
