From patchwork Tue Apr 18 17:04:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215944 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 90CBCC77B78 for ; Tue, 18 Apr 2023 17:04:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232001AbjDRRE5 (ORCPT ); Tue, 18 Apr 2023 13:04:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232563AbjDRRE4 (ORCPT ); Tue, 18 Apr 2023 13:04:56 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4D6C176A2 for ; Tue, 18 Apr 2023 10:04:53 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 2BEE2824C4; Tue, 18 Apr 2023 13:04:52 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837492; bh=ICxqBiWWNIPjhSuPacp2YUBjYU78VvV6ho2HQWm0wWs=; h=From:To:Cc:Subject:Date:From; b=lJFUdJlfgYWd/KBhRyMoYYDBtx8Pjj3YLSDWhXm320ebVhM92/5TLryeByMzN6f9N sWJMUuRUuO/+Mwvu8HVpJvNabJBk4Lg9yA9JM7jjP7dYVlxt627GF1pca68a8TrQA6 LOEDjgG035p/TAu8gdPfzAq17UNQKzZxd/9IgXSUU1sadUu8MENLnIkA4kWh1h6f5W OinglPpCvFWVGMqZkIvU3lOLNnW0ygvKWenUP8/oqHU05s3NwkgrbFX7Rj29pfqpX2 Qsm2Wq4aPlDvsRu5QDgp2zcYcw5wHj7t3JRFNDRsBk945Xk2g6Ee6OxR3yQVMGTf0T FtRtQlzm4ov3g== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 01/11] fscrypt: move inline crypt decision to info setup. Date: Tue, 18 Apr 2023 13:04:26 -0400 Message-Id: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org setup_file_encryption_key() is doing a lot of things at the moment -- setting the crypt_info's inline encryption bit, finding and locking a master key, and calling the functions to get the appropriate prepared key for this info. Since setting the inline encryption bit has nothing to do with finding the master key, it's easy and hopefully clearer to select the encryption implementation in fscrypt_setup_encryption_info(), the main fscrypt_info setup function, instead of in setup_file_encryption_key() which will long-term only deal in setting up the prepared key for the info. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 361f41ef46c7..b89c32ad19fb 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -443,10 +443,6 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, struct fscrypt_master_key *mk; int err; - err = fscrypt_select_encryption_impl(ci); - if (err) - return err; - err = fscrypt_policy_to_key_spec(&ci->ci_policy, &mk_spec); if (err) return err; @@ -580,6 +576,10 @@ fscrypt_setup_encryption_info(struct inode *inode, WARN_ON_ONCE(mode->ivsize > FSCRYPT_MAX_IV_SIZE); crypt_info->ci_mode = mode; + res = fscrypt_select_encryption_impl(crypt_info); + if (res) + goto out; + res = setup_file_encryption_key(crypt_info, need_dirhash_key, &mk); if (res) goto out; From patchwork Tue Apr 18 17:04:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215946 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3E1CCC77B7D for ; Tue, 18 Apr 2023 17:04:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232427AbjDRRE5 (ORCPT ); Tue, 18 Apr 2023 13:04:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48124 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231485AbjDRRE4 (ORCPT ); Tue, 18 Apr 2023 13:04:56 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 72DC086BC for ; Tue, 18 Apr 2023 10:04:54 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id C284D8258A; Tue, 18 Apr 2023 13:04:53 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837494; bh=3pMurlPip88FFbIjIA0xNOL2ptF3NUMocQCIVqbTd14=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mwNAxRVy+qBKS920Li8NK2BGXW7rwZSgspWxx1MsuEa2AEouUE/but6F4Pfr+Dy8A M9c8iaDcoubhPOp5s2VwKsd2LicAOGtYDO57PJTnybmSdio3j5m3KjUWVwitYSu02D Yjxa6lgcGD4gHf4J2YGIuTQR/UwzHLBZj15MFJ05B3n3teuDIzpG7uVPhW8VN1UxCh l2DJ35K0BEy7/0k8md6K83zoOyWdteigos3oHZwAGjgNfEgAFmxlYVQk1tKPE8K9fy dQAeiV5x8R+MIz7SWeo5HUCMmCH34wsig/voXcxgMDV6hAiqeJaf0E6pFmMf2gnGGg svxSu4Ad0KnXA== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 02/11] fscrypt: split and rename setup_file_encryption_key() Date: Tue, 18 Apr 2023 13:04:27 -0400 Message-Id: <15b622949a181033ffe07cfac1532adc7666da0e.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org At present, setup_file_encryption_key() does several things: it finds and locks the master key, and then calls into the appropriate functions to setup the prepared key for the fscrypt_info. The code is clearer to follow if these functions are divided. Thus, move calling the appropriate file key setup function into a new fscrypt_setup_file_key() function. After the file key setup functions are moved, the remaining function can take a const fscrypt_info, and is renamed find_and_lock_master_key() to precisely describe its action. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 77 ++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index b89c32ad19fb..727d473b6b03 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -386,6 +386,43 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, return 0; } +/* + * 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) +{ + int err; + + if (!mk) { + if (ci->ci_policy.version != FSCRYPT_POLICY_V1) + return -ENOKEY; + + /* + * As a legacy fallback for v1 policies, search for the key in + * the current task's subscribed keyrings too. Don't move this + * to before the search of ->s_master_keys, since users + * shouldn't be able to override filesystem-level keys. + */ + return fscrypt_setup_v1_file_key_via_subscribed_keyrings(ci); + } + + switch (ci->ci_policy.version) { + case FSCRYPT_POLICY_V1: + 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); + break; + default: + WARN_ON_ONCE(1); + err = -EINVAL; + break; + } + return err; +} + /* * Check whether the size of the given master key (@mk) is appropriate for the * encryption settings which a particular file will use (@ci). @@ -426,7 +463,7 @@ static bool fscrypt_valid_master_key_size(const struct fscrypt_master_key *mk, } /* - * Find the master key, then set up the inode's actual encryption key. + * Find and lock the master key. * * If the master key is found in the filesystem-level keyring, then it is * returned in *mk_ret with its semaphore read-locked. This is needed to ensure @@ -434,9 +471,8 @@ static bool fscrypt_valid_master_key_size(const struct fscrypt_master_key *mk, * multiple tasks may race to create an fscrypt_info for the same inode), and to * synchronize the master key being removed with a new inode starting to use it. */ -static int setup_file_encryption_key(struct fscrypt_info *ci, - bool need_dirhash_key, - struct fscrypt_master_key **mk_ret) +static int find_and_lock_master_key(const struct fscrypt_info *ci, + struct fscrypt_master_key **mk_ret) { struct super_block *sb = ci->ci_inode->i_sb; struct fscrypt_key_specifier mk_spec; @@ -466,17 +502,19 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, mk = fscrypt_find_master_key(sb, &mk_spec); } } + if (unlikely(!mk)) { if (ci->ci_policy.version != FSCRYPT_POLICY_V1) return -ENOKEY; /* - * As a legacy fallback for v1 policies, search for the key in - * the current task's subscribed keyrings too. Don't move this - * to before the search of ->s_master_keys, since users - * shouldn't be able to override filesystem-level keys. + * This might be the case of a v1 policy using a process + * subscribed keyring to get the key, so there may not be + * a relevant master key. */ - return fscrypt_setup_v1_file_key_via_subscribed_keyrings(ci); + + *mk_ret = NULL; + return 0; } down_read(&mk->mk_sem); @@ -491,21 +529,6 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, goto out_release_key; } - switch (ci->ci_policy.version) { - case FSCRYPT_POLICY_V1: - 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); - break; - default: - WARN_ON_ONCE(1); - err = -EINVAL; - break; - } - if (err) - goto out_release_key; - *mk_ret = mk; return 0; @@ -580,7 +603,11 @@ fscrypt_setup_encryption_info(struct inode *inode, if (res) goto out; - res = setup_file_encryption_key(crypt_info, need_dirhash_key, &mk); + res = find_and_lock_master_key(crypt_info, &mk); + if (res) + goto out; + + res = fscrypt_setup_file_key(crypt_info, mk, need_dirhash_key); if (res) goto out; From patchwork Tue Apr 18 17:04:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215945 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3B853C77B75 for ; Tue, 18 Apr 2023 17:04:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232313AbjDRRE6 (ORCPT ); Tue, 18 Apr 2023 13:04:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48094 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231485AbjDRRE5 (ORCPT ); Tue, 18 Apr 2023 13:04:57 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EF288A270 for ; Tue, 18 Apr 2023 10:04:55 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 659B78258F; Tue, 18 Apr 2023 13:04:55 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837495; bh=dEb4cofQP0SC/9D0jU/fr3XiGsvihKGFpokT9e+n0h0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UV0kIGLWSgm+XD/bK9e3qOnabBUO5i5OnVYBQtF3GUVkaVjGqbcBEGe1yGiZQcUZk p7wuznOcy5CiTHg39D1C6D7kAXc3YPw/M5T8fZQeInv9zJNXEFwstZkHCKQ3Jd++nz gRBJdaAJAJTBnLkAb9Z5TzFtcGLmNg83zJf3tJtF8ENt1DhLDDis/zYY8X6Cn3YgLI w/4/PnXKA3IiqOoCiLlYNPoZMTrQsC33rfdiMuBSlSGxUdFhyRJSXbnzYmewL5HhTN 9qJ+oWaQj+Wn9bSMNsMwGbKI6gmvDSYuil2sIWilILyXM/GgfC5tgNlprODEMf4ogG t6BA0rwH1qIwg== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 03/11] fscrypt: split setup_per_mode_enc_key() Date: Tue, 18 Apr 2023 13:04:28 -0400 Message-Id: <26d53ea3abac1fddc7fee5e36fe512cd41d039fe.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org At present, setup_per_mode_enc_key() tries to find, within an array of mode keys in the master key, an already prepared key, and if it doesn't find a pre-prepared key, sets up a new one. This caching is not super clear, at least to me, and splitting this function makes it clearer. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 59 +++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 727d473b6b03..69bd27b7e9d8 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -184,34 +184,24 @@ int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key) return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci); } -static int setup_per_mode_enc_key(struct fscrypt_info *ci, - struct fscrypt_master_key *mk, - struct fscrypt_prepared_key *keys, - u8 hkdf_context, bool include_fs_uuid) +static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, + struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci, + u8 hkdf_context, bool include_fs_uuid) { const struct inode *inode = ci->ci_inode; const struct super_block *sb = inode->i_sb; struct fscrypt_mode *mode = ci->ci_mode; const u8 mode_num = mode - fscrypt_modes; - struct fscrypt_prepared_key *prep_key; u8 mode_key[FSCRYPT_MAX_KEY_SIZE]; u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)]; unsigned int hkdf_infolen = 0; int err; - if (WARN_ON_ONCE(mode_num > FSCRYPT_MODE_MAX)) - return -EINVAL; - - prep_key = &keys[mode_num]; - if (fscrypt_is_key_prepared(prep_key, ci)) { - ci->ci_enc_key = *prep_key; - return 0; - } - mutex_lock(&fscrypt_mode_key_setup_mutex); if (fscrypt_is_key_prepared(prep_key, ci)) - goto done_unlock; + goto out_unlock; BUILD_BUG_ON(sizeof(mode_num) != 1); BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); @@ -229,16 +219,39 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci, goto out_unlock; err = fscrypt_prepare_key(prep_key, mode_key, ci); memzero_explicit(mode_key, mode->keysize); - if (err) - goto out_unlock; -done_unlock: - ci->ci_enc_key = *prep_key; - err = 0; + out_unlock: mutex_unlock(&fscrypt_mode_key_setup_mutex); return err; } +static int find_mode_prepared_key(struct fscrypt_info *ci, + struct fscrypt_master_key *mk, + struct fscrypt_prepared_key *keys, + u8 hkdf_context, bool include_fs_uuid) +{ + struct fscrypt_mode *mode = ci->ci_mode; + const u8 mode_num = mode - fscrypt_modes; + struct fscrypt_prepared_key *prep_key; + int err; + + if (WARN_ON_ONCE(mode_num > FSCRYPT_MODE_MAX)) + return -EINVAL; + + prep_key = &keys[mode_num]; + if (fscrypt_is_key_prepared(prep_key, ci)) { + ci->ci_enc_key = *prep_key; + return 0; + } + err = setup_new_mode_prepared_key(mk, prep_key, ci, hkdf_context, + include_fs_uuid); + if (err) + return err; + + ci->ci_enc_key = *prep_key; + return 0; +} + /* * Derive a SipHash key from the given fscrypt master key and the given * application-specific information string. @@ -294,7 +307,7 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci, { int err; - err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys, + err = find_mode_prepared_key(ci, mk, mk->mk_iv_ino_lblk_32_keys, HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true); if (err) return err; @@ -344,7 +357,7 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, * encryption key. This ensures that the master key is * consistently used only for HKDF, avoiding key reuse issues. */ - err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys, + err = find_mode_prepared_key(ci, mk, mk->mk_direct_keys, HKDF_CONTEXT_DIRECT_KEY, false); } else if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { @@ -354,7 +367,7 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, * the IVs. This format is optimized for use with inline * encryption hardware compliant with the UFS standard. */ - err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys, + err = find_mode_prepared_key(ci, mk, mk->mk_iv_ino_lblk_64_keys, HKDF_CONTEXT_IV_INO_LBLK_64_KEY, true); } else if (ci->ci_policy.v2.flags & From patchwork Tue Apr 18 17:04:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215947 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A31E3C77B7E for ; Tue, 18 Apr 2023 17:04:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231485AbjDRRE7 (ORCPT ); Tue, 18 Apr 2023 13:04:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48168 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231537AbjDRRE6 (ORCPT ); Tue, 18 Apr 2023 13:04:58 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A67786BC for ; Tue, 18 Apr 2023 10:04:57 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id BB7DD825C6; Tue, 18 Apr 2023 13:04:56 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837497; bh=uRx7bHD8Ij+dgTOQA+c1S9zdeSABug3aN1jCY2/W2GQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=U55s7wV+Z1xMmMxKgU98vCjRQ5Vn/1JY39LcBUwHIkeBkdro3tKiQVPqjAfGk8gbg x7MsyD+Dm/jlsS1b9fDJCHoEeQeOMaN967mkNcVbW/JT/ooHFinkJSOinOoTqUDPhF y5iwzHMk2vWXC7EmykUWrcUm3VkuM/vC5iUX8m2g8bMRWMEKYv4vLPx6kVTtiE06C+ lrmm0GyyuAEcSz5YMwBKigQJj4+Ex8nC7/z4/h5B5hPmxpv5EB4nIj2AtGg586EGGV 5yJ8GjyWOooRYgMK6lSMW8K0dSyYrCrZBawYFAXzFgHrQEhQd8bkXwQGzKFtNWdWF0 50gcK5iWoDUDg== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 04/11] fscrypt: move dirhash key setup away from IO key setup Date: Tue, 18 Apr 2023 13:04:29 -0400 Message-Id: <0d3ae92ef973edcd70f18aa408de61e44dd7e28f.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org 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 --- fs/crypto/keysetup.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 69bd27b7e9d8..302a1ccde439 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -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 From patchwork Tue Apr 18 17:04:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215948 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ECDC0C6FD18 for ; Tue, 18 Apr 2023 17:05:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232443AbjDRRFB (ORCPT ); Tue, 18 Apr 2023 13:05:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48202 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231537AbjDRRFA (ORCPT ); Tue, 18 Apr 2023 13:05:00 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B3F88B46A for ; Tue, 18 Apr 2023 10:04:58 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 358AC82601; Tue, 18 Apr 2023 13:04:58 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837498; bh=sewHxX6NTQoGhPnQldAneRt3lxUgP4NYJQ1E6+fyytE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MRq5WzFwB8uPAIJhYbjNYoVgWhP24+pcQeuGCHhpCu2/lYw7hZZYb/RTVkAUABS8k 4y4oH8YUoYMdTiin6VQk30Lw1sTicOSBGjsLKvi+s/1i5x4KdplSk4oYyXqiKJZM5i LZ/eVUqE1qKxjcp5bg3zFd4u2BHqO1KN+tTbU0tjsg1KpDpjpA2CScrzuWzY0Rx7wd +4IBCCGos45rMjCE2aUGYsx6uupuS3Xj4Sb5hUDmAGk/iWG10C2sMVlQhni2FmeUa4 /UfStzzQIqtb8jHudds2rbmrrUsHzinDskP2iGmGop1g4aNp2bLNXsWbLrg0CJheCc AtaOPda/ra1zg== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 05/11] fscrypt: reduce special-casing of IV_INO_LBLK_32 Date: Tue, 18 Apr 2023 13:04:30 -0400 Message-Id: <41ed422224d7240e9d4686011534170c2008e834.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org Right now, the IV_INO_LBLK_32 policy is handled by its own function called in fscrypt_setup_v2_file_key(), different from all other policies which just call find_mode_prepared_key() with various parameters. The function additionally sets up the relevant inode hashing key in the master key, and uses it to hash the inode number if possible. This is not particularly relevant to setting up a prepared key, so this change tries to make it clear that every non-default policy uses basically the same setup mechanism for its prepared key. The other setup is moved to be called from the top crypt_info setup function. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 62 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 302a1ccde439..0648ae22ecc4 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -302,44 +302,30 @@ void fscrypt_hash_inode_number(struct fscrypt_info *ci, &mk->mk_ino_hash_key); } -static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci, - struct fscrypt_master_key *mk) +static int fscrypt_setup_ino_hash_key(struct fscrypt_master_key *mk) { int err; - err = find_mode_prepared_key(ci, mk, mk->mk_iv_ino_lblk_32_keys, - HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true); - if (err) - return err; - /* pairs with smp_store_release() below */ - if (!smp_load_acquire(&mk->mk_ino_hash_key_initialized)) { + if (smp_load_acquire(&mk->mk_ino_hash_key_initialized)) + return 0; - mutex_lock(&fscrypt_mode_key_setup_mutex); + mutex_lock(&fscrypt_mode_key_setup_mutex); - if (mk->mk_ino_hash_key_initialized) - goto unlock; + if (mk->mk_ino_hash_key_initialized) + goto unlock; - err = fscrypt_derive_siphash_key(mk, - HKDF_CONTEXT_INODE_HASH_KEY, - NULL, 0, &mk->mk_ino_hash_key); - if (err) - goto unlock; - /* pairs with smp_load_acquire() above */ - smp_store_release(&mk->mk_ino_hash_key_initialized, true); + err = fscrypt_derive_siphash_key(mk, + HKDF_CONTEXT_INODE_HASH_KEY, + NULL, 0, &mk->mk_ino_hash_key); + if (err) + goto unlock; + /* pairs with smp_load_acquire() above */ + smp_store_release(&mk->mk_ino_hash_key_initialized, true); unlock: - mutex_unlock(&fscrypt_mode_key_setup_mutex); - if (err) - return err; - } + mutex_unlock(&fscrypt_mode_key_setup_mutex); - /* - * New inodes may not have an inode number assigned yet. - * Hashing their inode number is delayed until later. - */ - if (ci->ci_inode->i_ino) - fscrypt_hash_inode_number(ci, mk); - return 0; + return err; } static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, @@ -371,7 +357,9 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, true); } else if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { - err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk); + err = find_mode_prepared_key(ci, mk, mk->mk_iv_ino_lblk_32_keys, + HKDF_CONTEXT_IV_INO_LBLK_32_KEY, + true); } else { u8 derived_key[FSCRYPT_MAX_KEY_SIZE]; @@ -629,6 +617,20 @@ fscrypt_setup_encryption_info(struct inode *inode, goto out; } + /* + * The IV_INO_LBLK_32 policy needs a hashed inode number, but new + * inodes may not have an inode number assigned yet. + */ + if (policy->version == FSCRYPT_POLICY_V2 && + (policy->v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) { + res = fscrypt_setup_ino_hash_key(mk); + if (res) + goto out; + + if (inode->i_ino) + fscrypt_hash_inode_number(crypt_info, mk); + } + /* * For existing inodes, multiple tasks may race to set ->i_crypt_info. * So use cmpxchg_release(). This pairs with the smp_load_acquire() in From patchwork Tue Apr 18 17:04:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215949 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2FC2AC77B78 for ; Tue, 18 Apr 2023 17:05:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231537AbjDRRFC (ORCPT ); Tue, 18 Apr 2023 13:05:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232475AbjDRRFB (ORCPT ); Tue, 18 Apr 2023 13:05:01 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2C069CC0B for ; Tue, 18 Apr 2023 10:05:00 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 91F74825C8; Tue, 18 Apr 2023 13:04:59 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837499; bh=7pewN1+MBZrvd0mgtOIdG86NbI2Ht22xcxez8wuJx2Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ac9zvEF2Eg5sC+S6MJC61hbmm42knJf845KvrBJYtbWvXlCITsoUxxAenb+WKQ3LO Q39+zu5vK+vvlenBnFuvod34dg0olUofgBOzODOBBieJoJl3SPJL6cukLq1Nc5dhaI 0KEdsFGrUMGJn7aktItDLvBHP00wlZmSJRr5W3ru9CLUFbllBtSFDMjIYBoqsQd3/i Cc9+u+ui6nNHYS4C0RTLJ5sIVy46zb5eK/GrzDRyR8WKDatatrCTMbHDIhy1d/mPuZ NlptozrZ4wM2OAMDJK4+Wxkc0ZfuswstvIoUlUMz/kApeooaAGZD86J0OqjhfGDcr6 ceT3GAkz53m4w== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 06/11] fscrypt: make infos have a pointer to prepared keys Date: Tue, 18 Apr 2023 13:04:31 -0400 Message-Id: <56441edbbf63869f40c1062bb58595499cc51f93.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org At present, it's not entirely clear who owns a prepared key. Under default policies, infos own the prepared key; but under any of the policy flag key policies, or with some v1 policies, the info merely has a copy of the authoritative prepared key; the authoritative copy of the prepared key lives in the master key or the direct key, but the info has no way to get to the authoritative key or get updates from it. A scenario which could occur is the following: -A directory tree is set up to use v2 policy DIRECT_KEY, mode adiantum. -One directory is opened, gets a prepared key with a crypto_skcipher. -A file within it is opened, sets up and gets the 'same' prepared key, but it's set up the blk_crypto_key in the prepared key. -Another directory in the tree is opened, and gets the 'same' prepared key, but it's now got a pointer to the blk_crypto_key too. -The two directories' ci_enc_key values are different, even though for practical purposes they are the same. While it has no correctness implications, it's confusing for debugging when two directories with the same mode/policy have different prepared key contents depending on what else happened. Adding a layer of indirection makes everything clearer at the cost of another pointer. Now everyone sharing a prepared key within a direct key or a master key have the same pointer to the single prepared key. Followups move information from the crypt_info into the prepared key, which ends up reducing memory usage slightly. And, it makes using pooled, pre-allocated objects which could be stolen from a dormant fscrypt_info much easier. So this change makes crypt_info->ci_enc_key a pointer and updates all users thereof. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 2 +- fs/crypto/fname.c | 4 ++-- fs/crypto/fscrypt_private.h | 2 +- fs/crypto/inline_crypt.c | 4 ++-- fs/crypto/keysetup.c | 16 +++++++++++----- fs/crypto/keysetup_v1.c | 2 +- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 6a837e4b80dc..9f3bda18c797 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -108,7 +108,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, DECLARE_CRYPTO_WAIT(wait); struct scatterlist dst, src; struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; + struct crypto_skcipher *tfm = ci->ci_enc_key->tfm; int res = 0; if (WARN_ON_ONCE(len <= 0)) diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 6eae3f12ad50..edb78cd1b0e7 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -101,7 +101,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); const struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; + struct crypto_skcipher *tfm = ci->ci_enc_key->tfm; union fscrypt_iv iv; struct scatterlist sg; int res; @@ -158,7 +158,7 @@ static int fname_decrypt(const struct inode *inode, DECLARE_CRYPTO_WAIT(wait); struct scatterlist src_sg, dst_sg; const struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; + struct crypto_skcipher *tfm = ci->ci_enc_key->tfm; union fscrypt_iv iv; int res; diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 7ab5a7b7eef8..5011737b60b3 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -198,7 +198,7 @@ struct fscrypt_prepared_key { struct fscrypt_info { /* The key in a form prepared for actual encryption/decryption */ - struct fscrypt_prepared_key ci_enc_key; + struct fscrypt_prepared_key *ci_enc_key; /* True if ci_enc_key should be freed when this fscrypt_info is freed */ bool ci_owns_key; diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 8bfb3ce86476..2063f7941ce6 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -273,7 +273,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, ci = inode->i_crypt_info; fscrypt_generate_dun(ci, first_lblk, dun); - bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask); + bio_crypt_set_ctx(bio, ci->ci_enc_key->blk_key, dun, gfp_mask); } EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx); @@ -360,7 +360,7 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, * uses the same pointer. I.e., there's currently no need to support * merging requests where the keys are the same but the pointers differ. */ - if (bc->bc_key != inode->i_crypt_info->ci_enc_key.blk_key) + if (bc->bc_key != inode->i_crypt_info->ci_enc_key->blk_key) return false; fscrypt_generate_dun(inode->i_crypt_info, next_lblk, next_dun); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 0648ae22ecc4..7f729ff25c38 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -181,7 +181,11 @@ void fscrypt_destroy_prepared_key(struct super_block *sb, int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key) { ci->ci_owns_key = true; - return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci); + ci->ci_enc_key = kzalloc(sizeof(*ci->ci_enc_key), GFP_KERNEL); + if (!ci->ci_enc_key) + return -ENOMEM; + + return fscrypt_prepare_key(ci->ci_enc_key, raw_key, ci); } static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, @@ -240,7 +244,7 @@ static int find_mode_prepared_key(struct fscrypt_info *ci, prep_key = &keys[mode_num]; if (fscrypt_is_key_prepared(prep_key, ci)) { - ci->ci_enc_key = *prep_key; + ci->ci_enc_key = prep_key; return 0; } err = setup_new_mode_prepared_key(mk, prep_key, ci, hkdf_context, @@ -248,7 +252,7 @@ static int find_mode_prepared_key(struct fscrypt_info *ci, if (err) return err; - ci->ci_enc_key = *prep_key; + ci->ci_enc_key = prep_key; return 0; } @@ -537,9 +541,11 @@ static void put_crypt_info(struct fscrypt_info *ci) if (ci->ci_direct_key) fscrypt_put_direct_key(ci->ci_direct_key); - else if (ci->ci_owns_key) + else if (ci->ci_owns_key) { fscrypt_destroy_prepared_key(ci->ci_inode->i_sb, - &ci->ci_enc_key); + ci->ci_enc_key); + kfree_sensitive(ci->ci_enc_key); + } mk = ci->ci_master_key; if (mk) { diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 75dabd9b27f9..e1d761e8067f 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -259,7 +259,7 @@ static int setup_v1_file_key_direct(struct fscrypt_info *ci, if (IS_ERR(dk)) return PTR_ERR(dk); ci->ci_direct_key = dk; - ci->ci_enc_key = dk->dk_key; + ci->ci_enc_key = &dk->dk_key; return 0; } From patchwork Tue Apr 18 17:04:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215950 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AD82EC77B75 for ; Tue, 18 Apr 2023 17:05:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232422AbjDRRFD (ORCPT ); Tue, 18 Apr 2023 13:05:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48286 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232327AbjDRRFD (ORCPT ); Tue, 18 Apr 2023 13:05:03 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA466A26B for ; Tue, 18 Apr 2023 10:05:01 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 2B627824C4; Tue, 18 Apr 2023 13:05:01 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837501; bh=33ed9ClBOkkr11rR1vDp7/GirCV3YEO/b3SkvUAtpao=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IzLE07oJ6ZJn386piOi88UneDU1r7NUTqhD1MoDUM9wJO5nbYM0owdAgTnfti5MlK E0q5u1aox6LzIsZJDaPseBVvUZKXNNZcyEPPWVvarpa0aftsVYhBvue75emcC2xphu My+mfdCUby8UyKk9Gci5qgOprX6CENO67lmQVNz/Gem3wHo5ecidX8fINunWFCQXs5 /2yEcYcxu3hhXyUXr0OsI8i3DEMgZkzBSOT3Kd8888Jl7U5bEUXYDiBNeieuScQo3Z JqId7ywDLnJ8Z0n0XkHPbZzfXdu0WqqxFvuTWCTB9LfliBvuDEFznvRKSCo0WDP56B PaOXyL7P3BC5g== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 07/11] fscrypt: move all the shared mode key setup deeper Date: Tue, 18 Apr 2023 13:04:32 -0400 Message-Id: <3d6999b3ea53cbedfd5a74c26c7c8deb9011f70f.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org Currently, fscrypt_setup_v2_file_key() has a set of ifs which encode various information about how to set up a new mode key if necessary for a shared-key policy (DIRECT or IV_INO_LBLK_*). This is somewhat awkward -- this information is only needed at the point that we need to setup a new key, which is not the common case; the setup details are recorded as function parameters relatively far from where they're actually used; and at the point we use the parameters, we can derive the information equally well. So this moves mode and policy checking as deep into the callstack as possible. mk_prepared_key_for_mode_policy() deals with the array lookup within a master key. And fill_hkdf_info_for mode_key() deals with filling in the hkdf info as necessary for a particular policy. These seem a little clearer in broad strokes, emphasizing the similarities between the policies, but it does spread out the information on how the key is derived for a particular policy more. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 131 +++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 43 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 7f729ff25c38..74c0b2b0db63 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -13,6 +13,17 @@ #include "fscrypt_private.h" +#define MAX_MODE_KEY_HKDF_INFO_SIZE 17 + +/* + * Constant defining the various policy flags which require a non-default key + * policy. + */ +#define FSCRYPT_POLICY_FLAGS_KEY_MASK \ + (FSCRYPT_POLICY_FLAG_DIRECT_KEY \ + | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 \ + | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) + struct fscrypt_mode fscrypt_modes[] = { [FSCRYPT_MODE_AES_256_XTS] = { .friendly_name = "AES-256-XTS", @@ -188,20 +199,83 @@ int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key) return fscrypt_prepare_key(ci->ci_enc_key, raw_key, ci); } +static struct fscrypt_prepared_key * +mk_prepared_key_for_mode_policy(struct fscrypt_master_key *mk, + union fscrypt_policy *policy, + struct fscrypt_mode *mode) +{ + const u8 mode_num = mode - fscrypt_modes; + + switch (policy->v2.flags & FSCRYPT_POLICY_FLAGS_KEY_MASK) { + case FSCRYPT_POLICY_FLAG_DIRECT_KEY: + return &mk->mk_direct_keys[mode_num]; + case FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: + return &mk->mk_iv_ino_lblk_64_keys[mode_num]; + case FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32: + return &mk->mk_iv_ino_lblk_32_keys[mode_num]; + default: + return ERR_PTR(-EINVAL); + } +} + +static size_t +fill_hkdf_info_for_mode_key(const struct fscrypt_info *ci, + u8 hkdf_info[MAX_MODE_KEY_HKDF_INFO_SIZE]) +{ + const u8 mode_num = ci->ci_mode - fscrypt_modes; + const struct super_block *sb = ci->ci_inode->i_sb; + u8 hkdf_infolen = 0; + + hkdf_info[hkdf_infolen++] = mode_num; + if (!(ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY)) { + memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid, + sizeof(sb->s_uuid)); + hkdf_infolen += sizeof(sb->s_uuid); + } + return hkdf_infolen; +} + static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, struct fscrypt_prepared_key *prep_key, - const struct fscrypt_info *ci, - u8 hkdf_context, bool include_fs_uuid) + const struct fscrypt_info *ci) { const struct inode *inode = ci->ci_inode; const struct super_block *sb = inode->i_sb; + unsigned int policy_flags = fscrypt_policy_flags(&ci->ci_policy); struct fscrypt_mode *mode = ci->ci_mode; const u8 mode_num = mode - fscrypt_modes; u8 mode_key[FSCRYPT_MAX_KEY_SIZE]; u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)]; unsigned int hkdf_infolen = 0; + u8 hkdf_context = 0; int err; + switch (policy_flags & FSCRYPT_POLICY_FLAGS_KEY_MASK) { + case FSCRYPT_POLICY_FLAG_DIRECT_KEY: + hkdf_context = HKDF_CONTEXT_DIRECT_KEY; + break; + case FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: + hkdf_context = HKDF_CONTEXT_IV_INO_LBLK_64_KEY; + break; + case FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32: + hkdf_context = HKDF_CONTEXT_IV_INO_LBLK_32_KEY; + break; + } + + /* + * For DIRECT_KEY policies: instead of deriving per-file encryption + * keys, the per-file nonce will be included in all the IVs. But + * unlike v1 policies, for v2 policies in this case we don't encrypt + * with the master key directly but rather derive a per-mode encryption + * key. This ensures that the master key is consistently used only for + * HKDF, avoiding key reuse issues. + * + * For IV_INO_LBLK policies: encryption keys are derived from + * (master_key, mode_num, filesystem_uuid), and inode number is + * included in the IVs. This format is optimized for use with inline + * encryption hardware compliant with the UFS standard. + */ + mutex_lock(&fscrypt_mode_key_setup_mutex); if (fscrypt_is_key_prepared(prep_key, ci)) @@ -209,13 +283,9 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, BUILD_BUG_ON(sizeof(mode_num) != 1); BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); - BUILD_BUG_ON(sizeof(hkdf_info) != 17); - hkdf_info[hkdf_infolen++] = mode_num; - if (include_fs_uuid) { - memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid, - sizeof(sb->s_uuid)); - hkdf_infolen += sizeof(sb->s_uuid); - } + BUILD_BUG_ON(sizeof(hkdf_info) != MAX_MODE_KEY_HKDF_INFO_SIZE); + hkdf_infolen = fill_hkdf_info_for_mode_key(ci, hkdf_info); + err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context, hkdf_info, hkdf_infolen, mode_key, mode->keysize); @@ -229,10 +299,8 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, return err; } -static int find_mode_prepared_key(struct fscrypt_info *ci, - struct fscrypt_master_key *mk, - struct fscrypt_prepared_key *keys, - u8 hkdf_context, bool include_fs_uuid) +static int setup_mode_prepared_key(struct fscrypt_info *ci, + struct fscrypt_master_key *mk) { struct fscrypt_mode *mode = ci->ci_mode; const u8 mode_num = mode - fscrypt_modes; @@ -242,13 +310,15 @@ static int find_mode_prepared_key(struct fscrypt_info *ci, if (WARN_ON_ONCE(mode_num > FSCRYPT_MODE_MAX)) return -EINVAL; - prep_key = &keys[mode_num]; + prep_key = mk_prepared_key_for_mode_policy(mk, &ci->ci_policy, mode); + if (IS_ERR(prep_key)) + return PTR_ERR(prep_key); + if (fscrypt_is_key_prepared(prep_key, ci)) { ci->ci_enc_key = prep_key; return 0; } - err = setup_new_mode_prepared_key(mk, prep_key, ci, hkdf_context, - include_fs_uuid); + err = setup_new_mode_prepared_key(mk, prep_key, ci); if (err) return err; @@ -337,33 +407,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, { int err; - if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { - /* - * DIRECT_KEY: instead of deriving per-file encryption keys, the - * per-file nonce will be included in all the IVs. But unlike - * v1 policies, for v2 policies in this case we don't encrypt - * with the master key directly but rather derive a per-mode - * encryption key. This ensures that the master key is - * consistently used only for HKDF, avoiding key reuse issues. - */ - err = find_mode_prepared_key(ci, mk, mk->mk_direct_keys, - HKDF_CONTEXT_DIRECT_KEY, false); - } else if (ci->ci_policy.v2.flags & - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { - /* - * IV_INO_LBLK_64: encryption keys are derived from (master_key, - * mode_num, filesystem_uuid), and inode number is included in - * the IVs. This format is optimized for use with inline - * encryption hardware compliant with the UFS standard. - */ - err = find_mode_prepared_key(ci, mk, mk->mk_iv_ino_lblk_64_keys, - HKDF_CONTEXT_IV_INO_LBLK_64_KEY, - true); - } else if (ci->ci_policy.v2.flags & - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { - err = find_mode_prepared_key(ci, mk, mk->mk_iv_ino_lblk_32_keys, - HKDF_CONTEXT_IV_INO_LBLK_32_KEY, - true); + if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAGS_KEY_MASK) { + err = setup_mode_prepared_key(ci, mk); } else { u8 derived_key[FSCRYPT_MAX_KEY_SIZE]; From patchwork Tue Apr 18 17:04:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215951 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B9CABC6FD18 for ; Tue, 18 Apr 2023 17:05:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230502AbjDRRFF (ORCPT ); Tue, 18 Apr 2023 13:05:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48314 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232332AbjDRRFE (ORCPT ); Tue, 18 Apr 2023 13:05:04 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2C8DB9ECC for ; Tue, 18 Apr 2023 10:05:03 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 933498262E; Tue, 18 Apr 2023 13:05:02 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837502; bh=broh0GYoLsGSEpMN2iEkC5oE1sb0NKn1szSVE/oMCKs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qMTFa3ypQa6vtOUPsJGk4UqFaVkLt9d4d00APlu6BollVgr7b3lrT+ujzPFIhTTyy gPyoWni4JcX6FTHwPCB/eDHhyG/IEAHg+5MqOiyUr+PQpOOwFQsksKforf2BRt15sl ZD/TGcgOhkdsrwrvHyX7wXXEUN1mQQ9YMxQgpWgqXvFgC2h8hFBKYC76w3fS8Iva0q szCiFRiCkSxag1nBUv1iCI1tLyHJb7pZWk3UZQTR1PsfnsqvxJckPGpbJz4PJWnLUw S6ZwXjuoCyr5hBuvASH5/oAqKl2yo5ik0N1hJ0+rsuO2HUUlLJj5DEjf8r1hXNB+6v qC0iz7niDCHWw== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 08/11] fscrypt: make prepared keys record their type. Date: Tue, 18 Apr 2023 13:04:33 -0400 Message-Id: In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org Right now fscrypt_infos have two fields dedicated solely to recording what type of prepared key the info has: whether it solely owns the prepared key, or has borrowed it from a master key, or from a direct key. The ci_direct_key field is only used for v1 direct key policies, recording the direct key that needs to have its refcount reduced when the crypt_info is freed. However, now that crypt_info->ci_enc_key is a pointer to the authoritative prepared key -- embedded in the direct key, in this case, we no longer need to keep a full pointer to the direct key -- we can use container_of() to go from the prepared key to its surrounding direct key. The key ownership information doesn't change during the lifetime of a prepared key. Since at worst there's a prepared key per info, and at best many infos share a single prepared key, it can be slightly more efficient to store this ownership info in the prepared key instead of in the fscrypt_info. Especially since we can squash both fields down into a single enum. This will also make it easy to record that a prepared key is part of the pooled prepared keys when extent-based encryption is used. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 31 +++++++++++++++++++++++-------- fs/crypto/keysetup.c | 19 ++++++++++++------- fs/crypto/keysetup_v1.c | 7 +++++-- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 5011737b60b3..e726a1fb9f7e 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -174,18 +174,39 @@ struct fscrypt_symlink_data { char encrypted_path[1]; } __packed; +/** + * enum fscrypt_prepared_key_type - records a prepared key's ownership + * + * @FSCRYPT_KEY_PER_INFO: this prepared key is allocated for a specific info + * and is never shared. + * @FSCRYPT_KEY_DIRECT_V1: this prepared key is embedded in a fscrypt_direct_key + * used in v1 direct key policies. + * @FSCRYPT_KEY_MASTER_KEY: this prepared key is a per-mode and policy key, + * part of a fscrypt_master_key, shared between all + * users of this master key having this mode and + * policy. + */ +enum fscrypt_prepared_key_type { + FSCRYPT_KEY_PER_INFO = 1, + FSCRYPT_KEY_DIRECT_V1, + FSCRYPT_KEY_MASTER_KEY, +} __packed; + /** * struct fscrypt_prepared_key - a key prepared for actual encryption/decryption * @tfm: crypto API transform object * @blk_key: key for blk-crypto + * @type: records the ownership type of the prepared key * - * Normally only one of the fields will be non-NULL. + * Normally only one of @tfm and @blk_key will be non-NULL, although it is + * possible if @type is FSCRYPT_KEY_MASTER_KEY. */ struct fscrypt_prepared_key { struct crypto_skcipher *tfm; #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT struct blk_crypto_key *blk_key; #endif + enum fscrypt_prepared_key_type type; }; /* @@ -233,12 +254,6 @@ struct fscrypt_info { */ struct list_head ci_master_key_link; - /* - * If non-NULL, then encryption is done using the master key directly - * and ci_enc_key will equal ci_direct_key->dk_key. - */ - struct fscrypt_direct_key *ci_direct_key; - /* * This inode's hash key for filenames. This is a 128-bit SipHash-2-4 * key. This is only set for directories that use a keyed dirhash over @@ -641,7 +656,7 @@ static inline int fscrypt_require_key(struct inode *inode) /* keysetup_v1.c */ -void fscrypt_put_direct_key(struct fscrypt_direct_key *dk); +void fscrypt_put_direct_key(struct fscrypt_prepared_key *prep_key); int fscrypt_setup_v1_file_key(struct fscrypt_info *ci, const u8 *raw_master_key); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 74c0b2b0db63..3c5ab1349247 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -191,11 +191,11 @@ void fscrypt_destroy_prepared_key(struct super_block *sb, /* Given a per-file encryption key, set up the file's crypto transform object */ int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key) { - ci->ci_owns_key = true; ci->ci_enc_key = kzalloc(sizeof(*ci->ci_enc_key), GFP_KERNEL); if (!ci->ci_enc_key) return -ENOMEM; + ci->ci_enc_key->type = FSCRYPT_KEY_PER_INFO; return fscrypt_prepare_key(ci->ci_enc_key, raw_key, ci); } @@ -291,6 +291,7 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, mode_key, mode->keysize); if (err) goto out_unlock; + prep_key->type = FSCRYPT_KEY_MASTER_KEY; err = fscrypt_prepare_key(prep_key, mode_key, ci); memzero_explicit(mode_key, mode->keysize); @@ -584,12 +585,16 @@ static void put_crypt_info(struct fscrypt_info *ci) if (!ci) return; - if (ci->ci_direct_key) - fscrypt_put_direct_key(ci->ci_direct_key); - else if (ci->ci_owns_key) { - fscrypt_destroy_prepared_key(ci->ci_inode->i_sb, - ci->ci_enc_key); - kfree_sensitive(ci->ci_enc_key); + if (ci->ci_enc_key) { + enum fscrypt_prepared_key_type type = ci->ci_enc_key->type; + + if (type == FSCRYPT_KEY_DIRECT_V1) + fscrypt_put_direct_key(ci->ci_enc_key); + if (type == FSCRYPT_KEY_PER_INFO) { + fscrypt_destroy_prepared_key(ci->ci_inode->i_sb, + ci->ci_enc_key); + kfree_sensitive(ci->ci_enc_key); + } } mk = ci->ci_master_key; diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index e1d761e8067f..1e785cedead0 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -160,8 +160,11 @@ static void free_direct_key(struct fscrypt_direct_key *dk) } } -void fscrypt_put_direct_key(struct fscrypt_direct_key *dk) +void fscrypt_put_direct_key(struct fscrypt_prepared_key *prep_key) { + struct fscrypt_direct_key *dk = + container_of(prep_key, struct fscrypt_direct_key, dk_key); + if (!refcount_dec_and_lock(&dk->dk_refcount, &fscrypt_direct_keys_lock)) return; hash_del(&dk->dk_node); @@ -235,6 +238,7 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) dk->dk_sb = ci->ci_inode->i_sb; refcount_set(&dk->dk_refcount, 1); dk->dk_mode = ci->ci_mode; + dk->dk_key.type = FSCRYPT_KEY_DIRECT_V1; err = fscrypt_prepare_key(&dk->dk_key, raw_key, ci); if (err) goto err_free_dk; @@ -258,7 +262,6 @@ static int setup_v1_file_key_direct(struct fscrypt_info *ci, dk = fscrypt_get_direct_key(ci, raw_master_key); if (IS_ERR(dk)) return PTR_ERR(dk); - ci->ci_direct_key = dk; ci->ci_enc_key = &dk->dk_key; return 0; } From patchwork Tue Apr 18 17:04:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215952 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 77F5EC77B7E for ; Tue, 18 Apr 2023 17:05:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231615AbjDRRFG (ORCPT ); Tue, 18 Apr 2023 13:05:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230445AbjDRRFG (ORCPT ); Tue, 18 Apr 2023 13:05:06 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EE2318A7F for ; Tue, 18 Apr 2023 10:05:04 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 191E18262C; Tue, 18 Apr 2023 13:05:03 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837504; bh=ORVmwNqbQKLCskjvXLbGb7Ibv0eWPRiWJyuZGGvLDAo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YuDlvRAkqGs96cizX9kvcRFFL/XvLDQdku+d5HTqMuIu/KMcDJjZ+BWAsAi2cbivD ZwYHNf+vMgxaM6hJZr6BOHHyKt/CSxUgld+vmyrl9sCOzCFftccRTonD259n3Jkapm 7u5Oft7gbV9+oAxB1pe+rY1hmkWnnIps6w+dBxEHj0wHnXMdVTATdMVHN4L48KUTcy HXEBXqvXUts950HWZ4/zoElSQpK8YsxuTKAiYRVuDdQYjGk+PW7blveCXHtsanxORA 7OX+lgw5MVSxYgMhwT3GJWT0ZUlC01On0V/gMqR3RpkHCu7EpiaQkBQrXk4EyzpduL Y2iMMS9EIehLQ== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 09/11] fscrypt: lock every time a info needs a mode key Date: Tue, 18 Apr 2023 13:04:34 -0400 Message-Id: <26631684ca79332e0c2fa57f6246c703d017637f.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org Currently, the non-NULL status of the sub-fields of the prepared key are used as booleans indicating whether the prepared key is ready for use. However, when allocation and preparation of prepared keys are split, the fields are set before the key is ready for use, so some other mechanism is needed. Since per-mode keys are not that common, if an info is using a per-mode key, just grab the setup mutex to check whether the key is set up. Since the setup mutex is held during key set up, this keeps any info from observing a half-setup key. If lock contention becomes an issue, the setup mutex could be split by policy or by mode+policy in the future. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 20 ++++++-------------- fs/crypto/inline_crypt.c | 8 +------- fs/crypto/keysetup.c | 26 +++++++------------------- fs/crypto/keysetup_v1.c | 2 +- 4 files changed, 15 insertions(+), 41 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index e726a1fb9f7e..46a756c8a66f 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -367,20 +367,12 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb, * @prep_key, depending on which encryption implementation the file will use. */ static inline bool -fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, +fscrypt_is_key_allocated(struct fscrypt_prepared_key *prep_key, const struct fscrypt_info *ci) { - /* - * The two smp_load_acquire()'s here pair with the smp_store_release()'s - * in fscrypt_prepare_inline_crypt_key() and fscrypt_prepare_key(). - * I.e., in some cases (namely, if this prep_key is a per-mode - * encryption key) another task can publish blk_key or tfm concurrently, - * executing a RELEASE barrier. We need to use smp_load_acquire() here - * to safely ACQUIRE the memory the other task published. - */ if (fscrypt_using_inline_encryption(ci)) - return smp_load_acquire(&prep_key->blk_key) != NULL; - return smp_load_acquire(&prep_key->tfm) != NULL; + return prep_key->blk_key != NULL; + return prep_key->tfm != NULL; } #else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ @@ -412,10 +404,10 @@ fscrypt_destroy_inline_crypt_key(struct super_block *sb, } static inline bool -fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key, - const struct fscrypt_info *ci) +fscrypt_is_key_allocated(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) { - return smp_load_acquire(&prep_key->tfm) != NULL; + return prep_key->tfm != NULL; } #endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */ diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 2063f7941ce6..ce952dedba77 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -191,13 +191,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, goto fail; } - /* - * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared(). - * I.e., here we publish ->blk_key with a RELEASE barrier so that - * concurrent tasks can ACQUIRE it. Note that this concurrency is only - * possible for per-mode keys, not for per-file keys. - */ - smp_store_release(&prep_key->blk_key, blk_key); + prep_key->blk_key = blk_key; return 0; fail: diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 3c5ab1349247..a5f23b996a23 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -169,13 +169,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode); if (IS_ERR(tfm)) return PTR_ERR(tfm); - /* - * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared(). - * I.e., here we publish ->tfm with a RELEASE barrier so that - * concurrent tasks can ACQUIRE it. Note that this concurrency is only - * possible for per-mode keys, not for per-file keys. - */ - smp_store_release(&prep_key->tfm, tfm); + prep_key->tfm = tfm; return 0; } @@ -276,10 +270,6 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, * encryption hardware compliant with the UFS standard. */ - mutex_lock(&fscrypt_mode_key_setup_mutex); - - if (fscrypt_is_key_prepared(prep_key, ci)) - goto out_unlock; BUILD_BUG_ON(sizeof(mode_num) != 1); BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); @@ -290,13 +280,11 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, hkdf_context, hkdf_info, hkdf_infolen, mode_key, mode->keysize); if (err) - goto out_unlock; + return err; prep_key->type = FSCRYPT_KEY_MASTER_KEY; err = fscrypt_prepare_key(prep_key, mode_key, ci); memzero_explicit(mode_key, mode->keysize); -out_unlock: - mutex_unlock(&fscrypt_mode_key_setup_mutex); return err; } @@ -315,11 +303,11 @@ static int setup_mode_prepared_key(struct fscrypt_info *ci, if (IS_ERR(prep_key)) return PTR_ERR(prep_key); - if (fscrypt_is_key_prepared(prep_key, ci)) { - ci->ci_enc_key = prep_key; - return 0; - } - err = setup_new_mode_prepared_key(mk, prep_key, ci); + mutex_lock(&fscrypt_mode_key_setup_mutex); + if (!fscrypt_is_key_allocated(prep_key, ci)) + err = setup_new_mode_prepared_key(mk, prep_key, ci); + + mutex_unlock(&fscrypt_mode_key_setup_mutex); if (err) return err; diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 1e785cedead0..119e80d6e81f 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -203,7 +203,7 @@ find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, continue; if (ci->ci_mode != dk->dk_mode) continue; - if (!fscrypt_is_key_prepared(&dk->dk_key, ci)) + if (!fscrypt_is_key_allocated(&dk->dk_key, ci)) continue; if (crypto_memneq(raw_key, dk->dk_raw, ci->ci_mode->keysize)) continue; From patchwork Tue Apr 18 17:04:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215953 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10FC3C6FD18 for ; Tue, 18 Apr 2023 17:05:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231262AbjDRRFJ (ORCPT ); Tue, 18 Apr 2023 13:05:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48416 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232332AbjDRRFI (ORCPT ); Tue, 18 Apr 2023 13:05:08 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BADAB76A2 for ; Tue, 18 Apr 2023 10:05:06 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 96EB180621; Tue, 18 Apr 2023 13:05:05 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837506; bh=tOJ7dlXm0qa8vPXqSZDDPl8bul11m2OmAWQoQ5R4rK0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xCLaYYpWVwyKLQzrewdvwwptU5th40sEZAOgbUBCgKdr2HMt4arQLTvLM6xqM+aD+ ePaQTR8GO7x3G+j4gtCCQ/483YOdXoJ9KA1LC3clcYlPsSC1eFJpv9lvXJwSAGK9R6 20xHC6m4sFS4wHMHy/y41Gk9j2q4Pnpe52dzNp2iMFwaGLfd0es3BUCepRqK8w7wLa 5IUdTi95nlqIF1MbMxF1rJnAjiKDDOpWYFcWccaseDztj9kwbUlS1rEzN1igtGckcs LuQx+J9vIs8C9pms/NJltP9P6ALtevzak7adtleac/cshi4wMD+7TLLaVsrYhsVzKx 6xQZIasW1JHgA== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 10/11] fscrypt: split key alloc and preparation Date: Tue, 18 Apr 2023 13:04:35 -0400 Message-Id: In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org For extent-based encryption, we plan to use pooled prepared keys, since it's unsafe to allocate a new crypto_skcipher when performing IO. This will require being able to set up a pre-allocated prepared key, while the current code requires allocating and setting up simultaneously. This pulls apart fscrypt_allocate_skcipher() to only allocate; pulls allocation out of fscrypt_prepare_inline_crypt_key(); creates a new function fscrypt_allocate_key_member() that allocates the appropriate member of a prepared key; and reflects these changes throughout. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 14 +++++++++ fs/crypto/inline_crypt.c | 19 +++++++++---- fs/crypto/keysetup.c | 57 ++++++++++++++++++++++++++----------- fs/crypto/keysetup_v1.c | 4 +++ 4 files changed, 72 insertions(+), 22 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 46a756c8a66f..eb302e342fb9 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -355,6 +355,9 @@ fscrypt_using_inline_encryption(const struct fscrypt_info *ci) return ci->ci_inlinecrypt; } +int fscrypt_allocate_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci); + int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, const struct fscrypt_info *ci); @@ -388,6 +391,14 @@ fscrypt_using_inline_encryption(const struct fscrypt_info *ci) return false; } +static inline int +fscrypt_allocate_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) +{ + WARN_ON(1); + return -EOPNOTSUPP; +} + static inline int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, @@ -604,6 +615,9 @@ struct fscrypt_mode { extern struct fscrypt_mode fscrypt_modes[]; +int fscrypt_allocate_key_member(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci); + int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, const struct fscrypt_info *ci); diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index ce952dedba77..b527323ddf88 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -157,16 +157,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const struct inode *inode = ci->ci_inode; struct super_block *sb = inode->i_sb; enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode; - struct blk_crypto_key *blk_key; + struct blk_crypto_key *blk_key = prep_key->blk_key; struct block_device **devs; unsigned int num_devs; unsigned int i; int err; - blk_key = kmalloc(sizeof(*blk_key), GFP_KERNEL); - if (!blk_key) - return -ENOMEM; - err = blk_crypto_init_key(blk_key, raw_key, crypto_mode, fscrypt_get_dun_bytes(ci), sb->s_blocksize); if (err) { @@ -191,7 +187,6 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, goto fail; } - prep_key->blk_key = blk_key; return 0; fail: @@ -199,6 +194,18 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, return err; } +int fscrypt_allocate_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) +{ + struct blk_crypto_key *blk_key = kmalloc(sizeof(*blk_key), GFP_KERNEL); + + if (!blk_key) + return -ENOMEM; + + prep_key->blk_key = blk_key; + return 0; +} + void fscrypt_destroy_inline_crypt_key(struct super_block *sb, struct fscrypt_prepared_key *prep_key) { diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index a5f23b996a23..55c416df6a71 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -106,9 +106,33 @@ select_encryption_mode(const union fscrypt_policy *policy, return ERR_PTR(-EINVAL); } -/* Create a symmetric cipher object for the given encryption mode and key */ +/* + * Prepare the crypto transform object or blk-crypto key in @prep_key, given the + * raw key, encryption mode (@ci->ci_mode), flag indicating which encryption + * implementation (fs-layer or blk-crypto) will be used (@ci->ci_inlinecrypt), + * and IV generation method (@ci->ci_policy.flags). The relevant member must + * already be allocated and set in @prep_key. + */ +int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, + const u8 *raw_key, const struct fscrypt_info *ci) +{ + int err; + bool inlinecrypt = fscrypt_using_inline_encryption(ci); + + if (inlinecrypt) { + err = fscrypt_prepare_inline_crypt_key(prep_key, raw_key, ci); + } else { + err = crypto_skcipher_setkey(prep_key->tfm, raw_key, + ci->ci_mode->keysize); + } + + return err; +} + + +/* Create a symmetric cipher object for the given encryption mode */ static struct crypto_skcipher * -fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, +fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const struct inode *inode) { struct crypto_skcipher *tfm; @@ -141,10 +165,6 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, goto err_free_tfm; } crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); - err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize); - if (err) - goto err_free_tfm; - return tfm; err_free_tfm: @@ -152,21 +172,16 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, return ERR_PTR(err); } -/* - * Prepare the crypto transform object or blk-crypto key in @prep_key, given the - * raw key, encryption mode (@ci->ci_mode), flag indicating which encryption - * implementation (fs-layer or blk-crypto) will be used (@ci->ci_inlinecrypt), - * and IV generation method (@ci->ci_policy.flags). - */ -int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, - const u8 *raw_key, const struct fscrypt_info *ci) +/* Allocate the relevant encryption member for the prepared key */ +int fscrypt_allocate_key_member(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) { struct crypto_skcipher *tfm; if (fscrypt_using_inline_encryption(ci)) - return fscrypt_prepare_inline_crypt_key(prep_key, raw_key, ci); + return fscrypt_allocate_inline_crypt_key(prep_key, ci); - tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode); + tfm = fscrypt_allocate_skcipher(ci->ci_mode, ci->ci_inode); if (IS_ERR(tfm)) return PTR_ERR(tfm); prep_key->tfm = tfm; @@ -185,11 +200,17 @@ void fscrypt_destroy_prepared_key(struct super_block *sb, /* Given a per-file encryption key, set up the file's crypto transform object */ int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key) { + int err; + ci->ci_enc_key = kzalloc(sizeof(*ci->ci_enc_key), GFP_KERNEL); if (!ci->ci_enc_key) return -ENOMEM; ci->ci_enc_key->type = FSCRYPT_KEY_PER_INFO; + err = fscrypt_allocate_key_member(ci->ci_enc_key, ci); + if (err) + return err; + return fscrypt_prepare_key(ci->ci_enc_key, raw_key, ci); } @@ -271,6 +292,10 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, */ + err = fscrypt_allocate_key_member(prep_key, ci); + if (err) + return err; + BUILD_BUG_ON(sizeof(mode_num) != 1); BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); BUILD_BUG_ON(sizeof(hkdf_info) != MAX_MODE_KEY_HKDF_INFO_SIZE); diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 119e80d6e81f..2db18bedfab5 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -239,6 +239,10 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) refcount_set(&dk->dk_refcount, 1); dk->dk_mode = ci->ci_mode; dk->dk_key.type = FSCRYPT_KEY_DIRECT_V1; + err = fscrypt_allocate_key_member(&dk->dk_key, ci); + if (err) + goto err_free_dk; + err = fscrypt_prepare_key(&dk->dk_key, raw_key, ci); if (err) goto err_free_dk; From patchwork Tue Apr 18 17:04:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13215954 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9590EC77B78 for ; Tue, 18 Apr 2023 17:05:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232277AbjDRRFJ (ORCPT ); Tue, 18 Apr 2023 13:05:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48406 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230445AbjDRRFI (ORCPT ); Tue, 18 Apr 2023 13:05:08 -0400 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 03C011719 for ; Tue, 18 Apr 2023 10:05:07 -0700 (PDT) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 348828023D; Tue, 18 Apr 2023 13:05:07 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1681837507; bh=DP5hlVvNjw2JROMJ6s6bshEcbxvK3Nx2/UIgbRvXRGk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vPH5aeFJ58RltTuRH9zBm+ERNqoW8WC4NNqmD2rIqwWQWCi4UV+d4CJhQfGebCupz S2v29m5XqGT43l+FGKUhR55U13N+vJ1T/OqNISv3yAZgh7OCqnstYVncei5aO7zw8i sDyw7lyynMXNNl5kM59rg/n82uelgrh9ZSkF7r//ros+radoLpPgKAIQrussj2QbHb pmCIzRhYk/fy3W4PiAUDagzk+o5tECgQvjJ94cNWA2WCr1hXsQAxh5rjhtJ7GpL/lm dl1XCDjadrTNICHJTnY2wOmvDjRwmIBKIu0Nw/6ZjMBFFaeUEHH+P7HX2uXo1NOVWK S/3kWlui7gZow== From: Sweet Tea Dorminy To: Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , linux-fscrypt@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [PATCH 11/11] fscrypt: factor helper for locking master key Date: Tue, 18 Apr 2023 13:04:36 -0400 Message-Id: <0624b444f5a952f27b9de209f28ce3c3387e2f35.1681837291.git.sweettea-kernel@dorminy.me> In-Reply-To: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> References: <1edeb5c4936667b6493b50776cd1cbf5e4cf2fdd.1681837291.git.sweettea-kernel@dorminy.me> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org When keys are prepared at the point of use, using a pooled prepared key, we'll need to lock and check the existence of the master key secret in multiple places. So go on and factor out the helper. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 55c416df6a71..9cd60e09b0c5 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -106,6 +106,17 @@ select_encryption_mode(const union fscrypt_policy *policy, return ERR_PTR(-EINVAL); } +static int lock_master_key(struct fscrypt_master_key *mk) +{ + down_read(&mk->mk_sem); + + /* Has the secret been removed (via FS_IOC_REMOVE_ENCRYPTION_KEY)? */ + if (!is_master_key_secret_present(&mk->mk_secret)) + return -ENOKEY; + + return 0; +} + /* * Prepare the crypto transform object or blk-crypto key in @prep_key, given the * raw key, encryption mode (@ci->ci_mode), flag indicating which encryption @@ -569,13 +580,10 @@ static int find_and_lock_master_key(const struct fscrypt_info *ci, *mk_ret = NULL; return 0; } - down_read(&mk->mk_sem); - /* Has the secret been removed (via FS_IOC_REMOVE_ENCRYPTION_KEY)? */ - if (!is_master_key_secret_present(&mk->mk_secret)) { - err = -ENOKEY; + err = lock_master_key(mk); + if (err) goto out_release_key; - } if (!fscrypt_valid_master_key_size(mk, ci)) { err = -ENOKEY;