From f18c87cb5362496a4baadaa14265471c992ca06a Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Thu, 25 Mar 2021 17:55:35 +0100 Subject: [PATCH] LU-13717 sec: handle null algo for filename encryption Encrypted files created with Lustre 2.14 have clear text file names. With new code implementing filename encryption, newly created files will have cipher text names, unless they are in an encrypted directory created in Lustre 2.14. So we need to make sure llcrypt library can properly handle the "null" algorithm for client side filename encryption, which is basically a no-op. Handling this "null" algo for filename encryption will not be possible with the in-kernel fscrypt library, so modify the behaviour of configure to build with embedded llcrypt by default, and only build against in-kernel fscrypt if explicitly specified via --enable-crypto=in-kernel configure option. The objective is to urge users to convert their encrypted directories to the new fashion that encrypts filenames. However, with the new code some operations on encrypted files created with 2.14 might not be possible, like migrate, so expressly forbid migrate on files that use the "null" algorithm for client side filename encryption. Finally, we revert commit 11fcbfa9de4a5170abc2c5df2a6e4e02f0f84268 ("LU-12275 sec: force file name encryption policy to null") so that new encrypted directories will enforce filename encryption. Signed-off-by: Sebastien Buisson Change-Id: I393945adc9b720a56544b5da0669cb2848507457 Reviewed-on: https://review.whamcloud.com/43388 Reviewed-by: James Simmons Reviewed-by: Patrick Farrell Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/crypto/llcrypt.h | 9 ++++++++- libcfs/libcfs/crypto/fname.c | 35 ++++++++++++++++++++++++++++------ libcfs/libcfs/crypto/hooks.c | 29 +++++++++++++++++++--------- libcfs/libcfs/crypto/keysetup.c | 9 +-------- libcfs/libcfs/crypto/policy.c | 34 ++++++++++++++++++--------------- lustre/autoconf/lustre-core.m4 | 22 +++++++++------------ lustre/include/lustre_crypto.h | 1 + lustre/llite/file.c | 6 ++++++ 8 files changed, 93 insertions(+), 52 deletions(-) diff --git a/libcfs/include/libcfs/crypto/llcrypt.h b/libcfs/include/libcfs/crypto/llcrypt.h index 038ed4b..b98e551 100644 --- a/libcfs/include/libcfs/crypto/llcrypt.h +++ b/libcfs/include/libcfs/crypto/llcrypt.h @@ -151,6 +151,7 @@ extern int llcrypt_ioctl_get_policy_ex(struct file *, void __user *); extern int llcrypt_has_permitted_context(struct inode *, struct inode *); extern int llcrypt_inherit_context(struct inode *, struct inode *, void *, bool); +extern bool llcrypt_policy_has_filename_enc(struct inode *inode); /* keyring.c */ extern void llcrypt_sb_free(struct super_block *sb); extern int llcrypt_ioctl_add_key(struct file *filp, void __user *arg); @@ -404,6 +405,10 @@ static inline int llcrypt_inherit_context(struct inode *parent, { return -EOPNOTSUPP; } +static inline bool llcrypt_policy_has_filename_enc(struct inode *inode) +{ + return false; +} /* keyring.c */ static inline void llcrypt_sb_free(struct super_block *sb) @@ -747,7 +752,9 @@ static inline int llcrypt_prepare_symlink(struct inode *dir, unsigned int max_len, struct llcrypt_str *disk_link) { - if (IS_ENCRYPTED(dir) || llcrypt_dummy_context_enabled(dir)) + if ((IS_ENCRYPTED(dir) && + likely(llcrypt_policy_has_filename_enc(dir))) || + llcrypt_dummy_context_enabled(dir)) return __llcrypt_prepare_symlink(dir, len, max_len, disk_link); disk_link->name = (unsigned char *)target; diff --git a/libcfs/libcfs/crypto/fname.c b/libcfs/libcfs/crypto/fname.c index d3f5832..6769930 100644 --- a/libcfs/libcfs/crypto/fname.c +++ b/libcfs/libcfs/crypto/fname.c @@ -196,15 +196,20 @@ bool llcrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, u32 max_len, u32 *encrypted_len_ret) { const struct llcrypt_info *ci = llcrypt_info(inode); + struct crypto_skcipher *tfm = ci->ci_ctfm; int padding = 4 << (llcrypt_policy_flags(&ci->ci_policy) & LLCRYPT_POLICY_FLAGS_PAD_MASK); u32 encrypted_len; if (orig_len > max_len) return false; - encrypted_len = max(orig_len, (u32)LL_CRYPTO_BLOCK_SIZE); - encrypted_len = round_up(encrypted_len, padding); - *encrypted_len_ret = min(encrypted_len, max_len); + if (tfm == NULL) { + *encrypted_len_ret = orig_len; + } else { + encrypted_len = max(orig_len, (u32)LL_CRYPTO_BLOCK_SIZE); + encrypted_len = round_up(encrypted_len, padding); + *encrypted_len_ret = min(encrypted_len, max_len); + } return true; } @@ -276,11 +281,22 @@ int llcrypt_fname_disk_to_usr(struct inode *inode, return 0; } - if (iname->len < LL_CRYPTO_BLOCK_SIZE) - return -EUCLEAN; + if (llcrypt_has_encryption_key(inode)) { + struct llcrypt_info *ci = llcrypt_info(inode); + struct crypto_skcipher *tfm = ci->ci_ctfm; + + if (tfm && iname->len < LL_CRYPTO_BLOCK_SIZE) + return -EUCLEAN; - if (llcrypt_has_encryption_key(inode)) return fname_decrypt(inode, iname, oname); + } + + if (unlikely(!llcrypt_policy_has_filename_enc(inode))) { + memcpy(oname->name, iname->name, iname->len); + oname->name[iname->len] = '\0'; + oname->len = iname->len; + return 0; + } if (iname->len <= LLCRYPT_FNAME_MAX_UNDIGESTED_SIZE) { oname->len = base64_encode(iname->name, iname->len, @@ -370,6 +386,13 @@ int llcrypt_setup_filename(struct inode *dir, const struct qstr *iname, } if (!lookup) return -ENOKEY; + + if (unlikely(!llcrypt_policy_has_filename_enc(dir))) { + fname->disk_name.name = (unsigned char *)iname->name; + fname->disk_name.len = iname->len; + return 0; + } + fname->is_ciphertext_name = true; /* diff --git a/libcfs/libcfs/crypto/hooks.c b/libcfs/libcfs/crypto/hooks.c index 10a837f..4e26fb3 100644 --- a/libcfs/libcfs/crypto/hooks.c +++ b/libcfs/libcfs/crypto/hooks.c @@ -177,6 +177,9 @@ int __llcrypt_encrypt_symlink(struct inode *inode, const char *target, struct llcrypt_symlink_data *sd; unsigned int ciphertext_len; + if (unlikely(!llcrypt_policy_has_filename_enc(inode))) + return 0; + err = llcrypt_require_key(inode); if (err) return err; @@ -266,17 +269,25 @@ const char *llcrypt_get_symlink(struct inode *inode, const void *caddr, * the ciphertext length, even though this is redundant with i_size. */ - if (max_size < sizeof(*sd)) - return ERR_PTR(-EUCLEAN); - sd = caddr; - cstr.name = (unsigned char *)sd->encrypted_path; - cstr.len = le16_to_cpu(sd->len); + if (unlikely(!llcrypt_policy_has_filename_enc(inode))) { + cstr.name = (unsigned char *)caddr; + cstr.len = strlen(cstr.name); + + if (cstr.len == 0) + return ERR_PTR(-EUCLEAN); + } else { + if (max_size < sizeof(*sd)) + return ERR_PTR(-EUCLEAN); + sd = caddr; + cstr.name = (unsigned char *)sd->encrypted_path; + cstr.len = le16_to_cpu(sd->len); - if (cstr.len == 0) - return ERR_PTR(-EUCLEAN); + if (cstr.len == 0) + return ERR_PTR(-EUCLEAN); - if (cstr.len + sizeof(*sd) - 1 > max_size) - return ERR_PTR(-EUCLEAN); + if (cstr.len + sizeof(*sd) - 1 > max_size) + return ERR_PTR(-EUCLEAN); + } err = llcrypt_fname_alloc_buffer(inode, cstr.len, &pstr); if (err) diff --git a/libcfs/libcfs/crypto/keysetup.c b/libcfs/libcfs/crypto/keysetup.c index aa793df..0beab0c 100644 --- a/libcfs/libcfs/crypto/keysetup.c +++ b/libcfs/libcfs/crypto/keysetup.c @@ -463,15 +463,8 @@ int llcrypt_get_encryption_info(struct inode *inode) /* Fake up a context for an unencrypted directory */ memset(&ctx, 0, sizeof(ctx)); ctx.version = LLCRYPT_CONTEXT_V1; - /* Force file/directory name encryption policy to null. - * This is needed for interoperability with future versions. - * Change to be reverted back when Lustre supports name - * encryption. - */ - CWARN("inode %lu: setting policy filenames_encryption_mode to null\n", - inode->i_ino); ctx.v1.contents_encryption_mode = LLCRYPT_MODE_AES_256_XTS; - ctx.v1.filenames_encryption_mode = LLCRYPT_MODE_NULL; + ctx.v1.filenames_encryption_mode = LLCRYPT_MODE_AES_256_CTS; memset(ctx.v1.master_key_descriptor, 0x42, LLCRYPT_KEY_DESCRIPTOR_SIZE); res = sizeof(ctx.v1); diff --git a/libcfs/libcfs/crypto/policy.c b/libcfs/libcfs/crypto/policy.c index 90e3907..5e74454 100644 --- a/libcfs/libcfs/crypto/policy.c +++ b/libcfs/libcfs/crypto/policy.c @@ -282,6 +282,25 @@ static int set_encryption_policy(struct inode *inode, return lsi->lsi_cop->set_context(inode, &ctx, ctxsize, NULL); } +/* Tell if an inode's encryption policy has filename encryption */ +bool llcrypt_policy_has_filename_enc(struct inode *inode) +{ + union llcrypt_policy policy; + int err; + + err = llcrypt_get_policy(inode, &policy); + if (err) + return true; + + if ((policy.version == LLCRYPT_POLICY_V1 && + policy.v1.filenames_encryption_mode == LLCRYPT_MODE_NULL) || + (policy.version == LLCRYPT_POLICY_V2 && + policy.v2.filenames_encryption_mode == LLCRYPT_MODE_NULL)) + return false; + return true; +} +EXPORT_SYMBOL(llcrypt_policy_has_filename_enc); + int llcrypt_ioctl_set_policy(struct file *filp, const void __user *arg) { union llcrypt_policy policy; @@ -314,21 +333,6 @@ int llcrypt_ioctl_set_policy(struct file *filp, const void __user *arg) return -EFAULT; policy.version = version; - /* Force file/directory name encryption policy to null. - * This is needed for interoperability with future versions. - * Code to be removed when Lustre supports name encryption. - */ - CWARN("inode %lu: forcing policy filenames_encryption_mode to null\n", - inode->i_ino); - switch (policy.version) { - case LLCRYPT_POLICY_V1: - policy.v1.filenames_encryption_mode = LLCRYPT_MODE_NULL; - break; - case LLCRYPT_POLICY_V2: - policy.v2.filenames_encryption_mode = LLCRYPT_MODE_NULL; - break; - } - if (!inode_owner_or_capable(inode)) return -EACCES; diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index f95ca26..b9bfbaa 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -2389,13 +2389,7 @@ fscrypt_support, [ ],[ fscrypt_ioctl_get_policy_ex(NULL, NULL); ],[ - dnl When Lustre supports file name encryption, restore "yes" value - dnl for has_fscrypt_support and remove warning message. - has_fscrypt_support="no" - AC_MSG_WARN([ -This version of Lustre lacks file name encryption support, -so it cannot make use of in-kernel fscrypt. -Will use embedded llcrypt if possible.]) + has_fscrypt_support="yes" ]) ]) # LC_FSCRYPT_SUPPORT @@ -2731,21 +2725,23 @@ AC_SUBST(OSDADDON) AC_DEFUN([LC_CONFIG_CRYPTO], [ AC_MSG_CHECKING([whether to enable Lustre client crypto]) AC_ARG_ENABLE([crypto], - AC_HELP_STRING([--enable-crypto], - [enable Lustre client crypto]), + AC_HELP_STRING([--enable-crypto=yes|no|in-kernel], + [enable Lustre client crypto (default is yes), use 'in-kernel' to force use of in-kernel fscrypt instead of embedded llcrypt]), [], [enable_crypto="auto"]) AS_IF([test "x$enable_crypto" != xno -a "x$enable_dist" = xno], [ AC_MSG_RESULT( ) LC_IS_ENCRYPTED LC_FSCRYPT_SUPPORT]) -AS_IF([test "x$has_fscrypt_support" = xyes], [ - AC_DEFINE(HAVE_LUSTRE_CRYPTO, 1, [Enable Lustre client crypto via in-kernel fscrypt]) - enable_crypto=yes], +AS_IF([test "x$enable_crypto" = xin-kernel], [ + AS_IF([test "x$has_fscrypt_support" = xyes], [ + AC_DEFINE(HAVE_LUSTRE_CRYPTO, 1, [Enable Lustre client crypto via in-kernel fscrypt])], [ + AC_MSG_ERROR([Lustre client crypto cannot be enabled via in-kernel fscrypt.]) + enable_crypto=no])], [AS_IF([test "x$has_is_encrypted" = xyes], [ AC_DEFINE(HAVE_LUSTRE_CRYPTO, 1, [Enable Lustre client crypto via embedded llcrypt]) AC_DEFINE(CONFIG_LL_ENCRYPTION, 1, [embedded llcrypt]) - enable_crypto=yes + enable_crypto="embedded llcrypt" enable_llcrypt=yes], [ AS_IF([test "x$enable_crypto" = xyes], [AC_MSG_ERROR([Lustre client crypto cannot be enabled because of lack of encryption support in your kernel.])]) diff --git a/lustre/include/lustre_crypto.h b/lustre/include/lustre_crypto.h index 9f76f87..284b9cc 100644 --- a/lustre/include/lustre_crypto.h +++ b/lustre/include/lustre_crypto.h @@ -132,6 +132,7 @@ static inline int critical_decode(const u8 *src, int len, char *dst) #define llcrypt_ioctl_set_policy(filp, arg) fscrypt_ioctl_set_policy(filp, arg) #define llcrypt_ioctl_get_policy_ex(filp, arg) \ fscrypt_ioctl_get_policy_ex(filp, arg) +#define llcrypt_policy_has_filename_enc(inode) true #define llcrypt_ioctl_add_key(filp, arg) fscrypt_ioctl_add_key(filp, arg) #define llcrypt_ioctl_remove_key(filp, arg) fscrypt_ioctl_remove_key(filp, arg) #define llcrypt_ioctl_remove_key_all_users(filp, arg) \ diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 9a63398..2e57c64 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -4819,6 +4819,12 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum, PFID(ll_inode2fid(child_inode))); GOTO(out_iput, rc = -ENOKEY); } + if (unlikely(!llcrypt_policy_has_filename_enc(child_inode))) { + CDEBUG(D_SEC, + "cannot migrate old format encrypted "DFID", please move to new enc dir first\n", + PFID(ll_inode2fid(child_inode))); + GOTO(out_iput, rc = -EUCLEAN); + } } op_data = ll_prep_md_op_data(NULL, parent, NULL, name, namelen, -- 1.8.3.1