Loading fs/crypto/crypto.c +18 −12 Original line number Diff line number Diff line Loading @@ -89,25 +89,31 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, #endif memset(iv, 0, ci->ci_mode->ivsize); if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { WARN_ON_ONCE(lblk_num > U32_MAX); WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); lblk_num |= (u64)ci->ci_inode->i_ino << 32; } else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); } else if ((fscrypt_policy_contents_mode(&ci->ci_policy) == if ((fscrypt_policy_contents_mode(&ci->ci_policy) == FSCRYPT_MODE_PRIVATE) && inlinecrypt) { if (ci->ci_inode->i_sb->s_type->name) { if (!strcmp(ci->ci_inode->i_sb->s_type->name, "f2fs")) { if (ci->ci_inode->i_sb->s_type->name && !strcmp(ci->ci_inode->i_sb->s_type->name, "f2fs")) { if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); } else { WARN_ON_ONCE(lblk_num > U32_MAX); WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); lblk_num |= (u64)ci->ci_inode->i_ino << 32; } } } else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { WARN_ON_ONCE(lblk_num > U32_MAX); WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); lblk_num |= (u64)ci->ci_inode->i_ino << 32; } else if ((flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) && !(fscrypt_policy_contents_mode(&ci->ci_policy) == FSCRYPT_MODE_PRIVATE)) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); } iv->lblk_num = cpu_to_le64(lblk_num); } Loading fs/crypto/fscrypt_private.h +7 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,8 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, return READ_ONCE(prep_key->tfm) != NULL; } extern int fscrypt_find_storage_type(char **device); #else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ static inline int fscrypt_select_encryption_impl(struct fscrypt_info *ci, Loading Loading @@ -417,6 +419,11 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, { return READ_ONCE(prep_key->tfm) != NULL; } static inline int fscrypt_find_storage_type(char **device) { return -EOPNOTSUPP; } #endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ /* keyring.c */ Loading fs/crypto/inline_crypt.c +2 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ static void fscrypt_get_devices(struct super_block *sb, int num_devs, #define SDHCI "sdhci" static int fscrypt_find_storage_type(char **device) int fscrypt_find_storage_type(char **device) { char boot[20] = {'\0'}; char *match = (char *)strnstr(saved_command_line, Loading @@ -61,6 +61,7 @@ static int fscrypt_find_storage_type(char **device) } return -EINVAL; } EXPORT_SYMBOL(fscrypt_find_storage_type); static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci) { Loading fs/crypto/keysetup_v1.c +54 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ #include <linux/hashtable.h> #include <linux/scatterlist.h> #include <linux/bio-crypt-ctx.h> #include <linux/siphash.h> #include <crypto/sha.h> #include "fscrypt_private.h" Loading @@ -33,6 +35,8 @@ static DEFINE_HASHTABLE(fscrypt_direct_keys, 6); /* 6 bits = 64 buckets */ static DEFINE_SPINLOCK(fscrypt_direct_keys_lock); static struct crypto_shash *essiv_hash_tfm; /* * v1 key derivation function. This generates the derived key by encrypting the * master key with AES-128-ECB using the nonce as the AES key. This provides a Loading Loading @@ -84,6 +88,37 @@ static int derive_key_aes(const u8 *master_key, return res; } static int fscrypt_do_sha256(const u8 *src, int srclen, u8 *dst) { struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm); /* init hash transform on demand */ if (unlikely(!tfm)) { struct crypto_shash *prev_tfm; tfm = crypto_alloc_shash("sha256", 0, 0); if (IS_ERR(tfm)) { fscrypt_warn(NULL, "error allocating SHA-256 transform: %ld", PTR_ERR(tfm)); return PTR_ERR(tfm); } prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm); if (prev_tfm) { crypto_free_shash(tfm); tfm = prev_tfm; } } { SHASH_DESC_ON_STACK(desc, tfm); desc->tfm = tfm; desc->flags = 0; return crypto_shash_digest(desc, src, srclen, dst); } } /* * Search the current task's subscribed keyrings for a "logon" key with * description prefix:descriptor, and if found acquire a read lock on it and Loading Loading @@ -280,6 +315,25 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci, FSCRYPT_MODE_PRIVATE) && fscrypt_using_inline_encryption(ci)) { ci->ci_owns_key = true; if (ci->ci_policy.v1.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { union { siphash_key_t k; u8 bytes[SHA256_DIGEST_SIZE]; } ino_hash_key; int err; /* hashed_ino = SipHash(key=SHA256(master_key), * data=i_ino) */ err = fscrypt_do_sha256(raw_master_key, ci->ci_mode->keysize / 2, ino_hash_key.bytes); if (err) return err; ci->ci_hashed_ino = siphash_1u64(ci->ci_inode->i_ino, &ino_hash_key.k); } memcpy(key_new.bytes, raw_master_key, ci->ci_mode->keysize); for (i = 0; i < ARRAY_SIZE(key_new.words); i++) Loading fs/crypto/policy.c +36 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,19 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1, if (policy1->version != policy2->version) return false; if (fscrypt_policy_contents_mode(policy1) == FSCRYPT_MODE_PRIVATE) return(!memcmp(policy1->v1.master_key_descriptor, policy2->v1.master_key_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE)) && (fscrypt_policy_contents_mode(policy1) == fscrypt_policy_contents_mode(policy2)) && (fscrypt_policy_fnames_mode(policy1) == fscrypt_policy_fnames_mode(policy2)) && ((fscrypt_policy_flags(policy1) & ~FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) == (fscrypt_policy_flags(policy2) & ~FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)); else return !memcmp(policy1, policy2, fscrypt_policy_size(policy1)); } Loading Loading @@ -122,7 +135,8 @@ static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy, } if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK | FSCRYPT_POLICY_FLAG_DIRECT_KEY)) { FSCRYPT_POLICY_FLAG_DIRECT_KEY | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) { fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)", policy->flags); return false; Loading Loading @@ -610,6 +624,20 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) } EXPORT_SYMBOL(fscrypt_has_permitted_context); #define SDHCI "sdhci" static int fscrypt_update_context(union fscrypt_context *ctx) { char *boot = "ufs"; if (!fscrypt_find_storage_type(&boot)) { if (!strcmp(boot, SDHCI)) ctx->v1.flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32; return 0; } return -EINVAL; } /** * fscrypt_inherit_context() - Sets a child context from its parent * @parent: Parent inode from which the context is inherited. Loading @@ -636,7 +664,12 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, return -ENOKEY; ctxsize = fscrypt_new_context_from_policy(&ctx, &ci->ci_policy); if (fscrypt_policy_contents_mode(&ci->ci_policy) == FSCRYPT_MODE_PRIVATE) { res = fscrypt_update_context(&ctx); if (res) return res; } BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE); res = parent->i_sb->s_cop->set_context(child, &ctx, ctxsize, fs_data); if (res) Loading Loading
fs/crypto/crypto.c +18 −12 Original line number Diff line number Diff line Loading @@ -89,25 +89,31 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, #endif memset(iv, 0, ci->ci_mode->ivsize); if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { WARN_ON_ONCE(lblk_num > U32_MAX); WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); lblk_num |= (u64)ci->ci_inode->i_ino << 32; } else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); } else if ((fscrypt_policy_contents_mode(&ci->ci_policy) == if ((fscrypt_policy_contents_mode(&ci->ci_policy) == FSCRYPT_MODE_PRIVATE) && inlinecrypt) { if (ci->ci_inode->i_sb->s_type->name) { if (!strcmp(ci->ci_inode->i_sb->s_type->name, "f2fs")) { if (ci->ci_inode->i_sb->s_type->name && !strcmp(ci->ci_inode->i_sb->s_type->name, "f2fs")) { if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); } else { WARN_ON_ONCE(lblk_num > U32_MAX); WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); lblk_num |= (u64)ci->ci_inode->i_ino << 32; } } } else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { WARN_ON_ONCE(lblk_num > U32_MAX); WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); lblk_num |= (u64)ci->ci_inode->i_ino << 32; } else if ((flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) && !(fscrypt_policy_contents_mode(&ci->ci_policy) == FSCRYPT_MODE_PRIVATE)) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); } iv->lblk_num = cpu_to_le64(lblk_num); } Loading
fs/crypto/fscrypt_private.h +7 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,8 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, return READ_ONCE(prep_key->tfm) != NULL; } extern int fscrypt_find_storage_type(char **device); #else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ static inline int fscrypt_select_encryption_impl(struct fscrypt_info *ci, Loading Loading @@ -417,6 +419,11 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, { return READ_ONCE(prep_key->tfm) != NULL; } static inline int fscrypt_find_storage_type(char **device) { return -EOPNOTSUPP; } #endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ /* keyring.c */ Loading
fs/crypto/inline_crypt.c +2 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ static void fscrypt_get_devices(struct super_block *sb, int num_devs, #define SDHCI "sdhci" static int fscrypt_find_storage_type(char **device) int fscrypt_find_storage_type(char **device) { char boot[20] = {'\0'}; char *match = (char *)strnstr(saved_command_line, Loading @@ -61,6 +61,7 @@ static int fscrypt_find_storage_type(char **device) } return -EINVAL; } EXPORT_SYMBOL(fscrypt_find_storage_type); static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci) { Loading
fs/crypto/keysetup_v1.c +54 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ #include <linux/hashtable.h> #include <linux/scatterlist.h> #include <linux/bio-crypt-ctx.h> #include <linux/siphash.h> #include <crypto/sha.h> #include "fscrypt_private.h" Loading @@ -33,6 +35,8 @@ static DEFINE_HASHTABLE(fscrypt_direct_keys, 6); /* 6 bits = 64 buckets */ static DEFINE_SPINLOCK(fscrypt_direct_keys_lock); static struct crypto_shash *essiv_hash_tfm; /* * v1 key derivation function. This generates the derived key by encrypting the * master key with AES-128-ECB using the nonce as the AES key. This provides a Loading Loading @@ -84,6 +88,37 @@ static int derive_key_aes(const u8 *master_key, return res; } static int fscrypt_do_sha256(const u8 *src, int srclen, u8 *dst) { struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm); /* init hash transform on demand */ if (unlikely(!tfm)) { struct crypto_shash *prev_tfm; tfm = crypto_alloc_shash("sha256", 0, 0); if (IS_ERR(tfm)) { fscrypt_warn(NULL, "error allocating SHA-256 transform: %ld", PTR_ERR(tfm)); return PTR_ERR(tfm); } prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm); if (prev_tfm) { crypto_free_shash(tfm); tfm = prev_tfm; } } { SHASH_DESC_ON_STACK(desc, tfm); desc->tfm = tfm; desc->flags = 0; return crypto_shash_digest(desc, src, srclen, dst); } } /* * Search the current task's subscribed keyrings for a "logon" key with * description prefix:descriptor, and if found acquire a read lock on it and Loading Loading @@ -280,6 +315,25 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci, FSCRYPT_MODE_PRIVATE) && fscrypt_using_inline_encryption(ci)) { ci->ci_owns_key = true; if (ci->ci_policy.v1.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { union { siphash_key_t k; u8 bytes[SHA256_DIGEST_SIZE]; } ino_hash_key; int err; /* hashed_ino = SipHash(key=SHA256(master_key), * data=i_ino) */ err = fscrypt_do_sha256(raw_master_key, ci->ci_mode->keysize / 2, ino_hash_key.bytes); if (err) return err; ci->ci_hashed_ino = siphash_1u64(ci->ci_inode->i_ino, &ino_hash_key.k); } memcpy(key_new.bytes, raw_master_key, ci->ci_mode->keysize); for (i = 0; i < ARRAY_SIZE(key_new.words); i++) Loading
fs/crypto/policy.c +36 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,19 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1, if (policy1->version != policy2->version) return false; if (fscrypt_policy_contents_mode(policy1) == FSCRYPT_MODE_PRIVATE) return(!memcmp(policy1->v1.master_key_descriptor, policy2->v1.master_key_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE)) && (fscrypt_policy_contents_mode(policy1) == fscrypt_policy_contents_mode(policy2)) && (fscrypt_policy_fnames_mode(policy1) == fscrypt_policy_fnames_mode(policy2)) && ((fscrypt_policy_flags(policy1) & ~FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) == (fscrypt_policy_flags(policy2) & ~FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)); else return !memcmp(policy1, policy2, fscrypt_policy_size(policy1)); } Loading Loading @@ -122,7 +135,8 @@ static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy, } if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK | FSCRYPT_POLICY_FLAG_DIRECT_KEY)) { FSCRYPT_POLICY_FLAG_DIRECT_KEY | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) { fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)", policy->flags); return false; Loading Loading @@ -610,6 +624,20 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) } EXPORT_SYMBOL(fscrypt_has_permitted_context); #define SDHCI "sdhci" static int fscrypt_update_context(union fscrypt_context *ctx) { char *boot = "ufs"; if (!fscrypt_find_storage_type(&boot)) { if (!strcmp(boot, SDHCI)) ctx->v1.flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32; return 0; } return -EINVAL; } /** * fscrypt_inherit_context() - Sets a child context from its parent * @parent: Parent inode from which the context is inherited. Loading @@ -636,7 +664,12 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, return -ENOKEY; ctxsize = fscrypt_new_context_from_policy(&ctx, &ci->ci_policy); if (fscrypt_policy_contents_mode(&ci->ci_policy) == FSCRYPT_MODE_PRIVATE) { res = fscrypt_update_context(&ctx); if (res) return res; } BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE); res = parent->i_sb->s_cop->set_context(child, &ctx, ctxsize, fs_data); if (res) Loading