@@ -343,8 +343,7 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci,
}
static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
- struct fscrypt_master_key *mk,
- bool need_dirhash_key)
+ struct fscrypt_master_key *mk)
{
int err;
@@ -386,25 +385,15 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
err = fscrypt_set_per_file_enc_key(ci, derived_key);
memzero_explicit(derived_key, ci->ci_mode->keysize);
}
- if (err)
- return err;
- /* Derive a secret dirhash key for directories that need it. */
- if (need_dirhash_key) {
- err = fscrypt_derive_dirhash_key(ci, mk);
- if (err)
- return err;
- }
-
- return 0;
+ return err;
}
/*
* Find or create the appropriate prepared key for an info.
*/
static int fscrypt_setup_file_key(struct fscrypt_info *ci,
- struct fscrypt_master_key *mk,
- bool need_dirhash_key)
+ struct fscrypt_master_key *mk)
{
int err;
@@ -426,7 +415,7 @@ static int fscrypt_setup_file_key(struct fscrypt_info *ci,
err = fscrypt_setup_v1_file_key(ci, mk->mk_secret.raw);
break;
case FSCRYPT_POLICY_V2:
- err = fscrypt_setup_v2_file_key(ci, mk, need_dirhash_key);
+ err = fscrypt_setup_v2_file_key(ci, mk);
break;
default:
WARN_ON_ONCE(1);
@@ -620,10 +609,26 @@ fscrypt_setup_encryption_info(struct inode *inode,
if (res)
goto out;
- res = fscrypt_setup_file_key(crypt_info, mk, need_dirhash_key);
+ res = fscrypt_setup_file_key(crypt_info, mk);
if (res)
goto out;
+ /*
+ * Derive a secret dirhash key for directories that need it. It
+ * should be impossible to set flags such that a v1 policy sets
+ * need_dirhash_key, but check it anyway.
+ */
+ if (need_dirhash_key) {
+ if (WARN_ON_ONCE(policy->version == FSCRYPT_POLICY_V1)) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ res = fscrypt_derive_dirhash_key(crypt_info, mk);
+ if (res)
+ goto out;
+ }
+
/*
* For existing inodes, multiple tasks may race to set ->i_crypt_info.
* So use cmpxchg_release(). This pairs with the smp_load_acquire() in
The function named fscrypt_setup_v2_file_key() has as its main focus the setting up of the fscrypt_info's ci_enc_key member, the prepared key with which filenames or file contents are encrypted or decrypted. However, it currently also sets up the dirhash key, used by some directories, based on a parameter. There are no dependencies on setting up the dirhash key beyond having the master key locked, and it's clearer having fscrypt_setup_file_key() be only about setting up the prepared key for IO. Thus, move dirhash key setup to fscrypt_setup_encryption_info(), which calls out to each function setting up parts of the fscrypt_info, and stop passing the need_dirhash_key parameter around. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> --- fs/crypto/keysetup.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-)