From patchwork Fri Mar 26 17:32:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409587 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 63075C433E0 for ; Fri, 26 Mar 2021 17:33:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1B62561A28 for ; Fri, 26 Mar 2021 17:33:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230152AbhCZRck (ORCPT ); Fri, 26 Mar 2021 13:32:40 -0400 Received: from mail.kernel.org ([198.145.29.99]:48298 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230167AbhCZRce (ORCPT ); Fri, 26 Mar 2021 13:32:34 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id A827661A28; Fri, 26 Mar 2021 17:32:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779950; bh=FyLX2ywQ9BCPysDxrhOZANICT7CBoNn+Ctf/AjpJVlA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ivBSs3wh68STq4fXnIwRuVr9mdfDMwzPGcGrNZVTE+KfJlnnl96LqV65h4f3dRDTI KUsE7RICXABkp6Pv6VcHh4X9vrT/z9Ed92Sp4BifPgqTEnSXJ/EuHLRBTJ0L7oJ2/e v+ybZh1y810UmzzmiP6kg7Xn5O8xjVhq/KJApUXTi3XFSwqwGyWKdfFpxoNLBvwXvi mEnCLs2DVyCNZsP1KBW+J209N0VPxlDaQ2ukXjcqPRYDWvFenpJZ/3HOcRlolQaqwz m0twMZ4IPqg3gt6DuF81ZblvXrZyZRGmn4USR06xzzcgHz3HM9hljxZ7WNGzbnoIxw 7n56ieRBNW96Q== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org, Al Viro Subject: [RFC PATCH v5 01/19] vfs: export new_inode_pseudo Date: Fri, 26 Mar 2021 13:32:09 -0400 Message-Id: <20210326173227.96363-2-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org Ceph needs to be able to allocate inodes ahead of a create that might involve a fscrypt-encrypted inode. new_inode() almost fits the bill, but it puts the inode on the sb->s_inodes list and when we go to hash it, that might be done again. We could work around that by setting I_CREATING on the new inode, but that causes ilookup5 to return -ESTALE if something tries to find it before I_NEW is cleared. To work around all of this, just use new_inode_pseudo which doesn't add it to the list. Cc: Al Viro Signed-off-by: Jeff Layton --- fs/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/inode.c b/fs/inode.c index a047ab306f9a..0745dc5d0924 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -935,6 +935,7 @@ struct inode *new_inode_pseudo(struct super_block *sb) } return inode; } +EXPORT_SYMBOL(new_inode_pseudo); /** * new_inode - obtain an inode From patchwork Fri Mar 26 17:32:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409585 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D66AC433FC for ; Fri, 26 Mar 2021 17:33:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0ED3561A36 for ; Fri, 26 Mar 2021 17:33:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230298AbhCZRcs (ORCPT ); Fri, 26 Mar 2021 13:32:48 -0400 Received: from mail.kernel.org ([198.145.29.99]:48304 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230194AbhCZRce (ORCPT ); Fri, 26 Mar 2021 13:32:34 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 0AA9461A2D; Fri, 26 Mar 2021 17:32:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779951; bh=iWCG4tc8H/QYLqUEKJze1/TsM19IPhsOoX7DC8hmNbY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pSeBWxADp5e0orpuyz6LlhiJlWEoggMNeQW1by/xlH3WWG2f5j1XfPR4iwQzugCjL TgE6YDxg14FLDExQyal0kEwjSDxVbaUVUCBAUlkHFvKu7obdyWkNwlsLUQzPcntJeu p6XCzvLtVREtFMj/00ovY81ovbGijETKaJr9Oz19Ini42w6hht6I8iSe90KOFB+/RJ 8R02d66eewiPu4q9iL3BlKw/4JSmkTDua2g2WgXTOpgh2IIgwgag1uD3nyYinz2VTZ Uh3kFwx5g/mp74+gtNhomlDXVa2EiquY3gNq5Lj2yjCfm37qfwoinGId31hZfR6oFy ekQg3WJZykwag== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 03/19] fscrypt: export fscrypt_fname_encrypt and fscrypt_fname_encrypted_size Date: Fri, 26 Mar 2021 13:32:11 -0400 Message-Id: <20210326173227.96363-4-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org For ceph, we want to use our own scheme for handling filenames that are are longer than NAME_MAX after encryption and base64 encoding. This allows us to have a consistent view of the encrypted filenames for clients that don't support fscrypt and clients that do but that don't have the key. Export fscrypt_fname_encrypt. Rename fscrypt_fname_encrypted_size to __fscrypt_fname_encrypted_size and add a new wrapper called fscrypt_fname_encrypted_size that takes an inode argument rahter than a pointer to a fscrypt_policy union. Signed-off-by: Jeff Layton --- fs/crypto/fname.c | 19 ++++++++++++++----- fs/crypto/fscrypt_private.h | 9 +++------ fs/crypto/hooks.c | 6 +++--- include/linux/fscrypt.h | 4 ++++ 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 32b1f50433ba..5a794de7f61d 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -126,6 +126,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, return 0; } +EXPORT_SYMBOL(fscrypt_fname_encrypt); /** * fname_decrypt() - decrypt a filename @@ -244,9 +245,9 @@ int fscrypt_base64_decode(const char *src, int len, u8 *dst) } EXPORT_SYMBOL(fscrypt_base64_decode); -bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, - u32 orig_len, u32 max_len, - u32 *encrypted_len_ret) +bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, + u32 orig_len, u32 max_len, + u32 *encrypted_len_ret) { int padding = 4 << (fscrypt_policy_flags(policy) & FSCRYPT_POLICY_FLAGS_PAD_MASK); @@ -260,6 +261,15 @@ bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, return true; } +bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, + u32 max_len, u32 *encrypted_len_ret) +{ + return __fscrypt_fname_encrypted_size(&inode->i_crypt_info->ci_policy, + orig_len, max_len, + encrypted_len_ret); +} +EXPORT_SYMBOL(fscrypt_fname_encrypted_size); + /** * fscrypt_fname_alloc_buffer() - allocate a buffer for presented filenames * @max_encrypted_len: maximum length of encrypted filenames the buffer will be @@ -422,8 +432,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return ret; if (fscrypt_has_encryption_key(dir)) { - if (!fscrypt_fname_encrypted_size(&dir->i_crypt_info->ci_policy, - iname->len, + if (!fscrypt_fname_encrypted_size(dir, iname->len, dir->i_sb->s_cop->max_namelen, &fname->crypto_buf.len)) return -ENAMETOOLONG; diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 3fa965eb3336..195de6d0db40 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -292,14 +292,11 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci); /* fname.c */ -int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, - u8 *out, unsigned int olen); -bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, - u32 orig_len, u32 max_len, - u32 *encrypted_len_ret); +bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, + u32 orig_len, u32 max_len, + u32 *encrypted_len_ret); /* hkdf.c */ - struct fscrypt_hkdf { struct crypto_shash *hmac_tfm; }; diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index a73b0376e6f3..e65c19aae041 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -228,9 +228,9 @@ int fscrypt_prepare_symlink(struct inode *dir, const char *target, * counting it (even though it is meaningless for ciphertext) is simpler * for now since filesystems will assume it is there and subtract it. */ - if (!fscrypt_fname_encrypted_size(policy, len, - max_len - sizeof(struct fscrypt_symlink_data), - &disk_link->len)) + if (!__fscrypt_fname_encrypted_size(policy, len, + max_len - sizeof(struct fscrypt_symlink_data), + &disk_link->len)) return -ENAMETOOLONG; disk_link->len += sizeof(struct fscrypt_symlink_data); diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index e300f6145ddc..b5c31baaa8bf 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -212,6 +212,10 @@ int fscrypt_drop_inode(struct inode *inode); /* fname.c */ int fscrypt_base64_encode(const u8 *src, int len, char *dst); int fscrypt_base64_decode(const char *src, int len, u8 *dst); +bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, + u32 max_len, u32 *encrypted_len_ret); +int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen); int fscrypt_setup_filename(struct inode *inode, const struct qstr *iname, int lookup, struct fscrypt_name *fname); From patchwork Fri Mar 26 17:32:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409582 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3BC3DC43331 for ; Fri, 26 Mar 2021 17:33:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 141B861A28 for ; Fri, 26 Mar 2021 17:33:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230372AbhCZRc5 (ORCPT ); Fri, 26 Mar 2021 13:32:57 -0400 Received: from mail.kernel.org ([198.145.29.99]:48314 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230202AbhCZRcg (ORCPT ); Fri, 26 Mar 2021 13:32:36 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 591FD61A33; Fri, 26 Mar 2021 17:32:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779952; bh=jTm0xmy6Fzl31LCcweWdxmUSRCnZpsuRxHjdss4eq1w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rVkHS4D9eukYUVDJZmW7nOC1h/2DX7Hkcwo5nrXwcYT0rPLc2SOAE7sOvvDCSfcq9 VzlKZi5L52kfjOK3iRshla5POv4jmRIgbDkFdGYPNp9QKzNCXsWX/z5sO4A8QjBlQZ Ei+a0EF30ZYQGp/mjssM+hP/bGmDuk/ORylfNEobmBwI+UwNMun4sFPcC5khp9d03M LGG4SJk3wLbLvn+A9PTyRsovzs7W0Z5AkmRdWwiiqSG/wB589MSvQTLFUtdEKXaI1X 0PjVDN9Z1dFxu2UBu1aAFF1d4amXP2QUhmYxk0ddHoaKqBF6Ic72UkE4SBc8MukWER qh2vVMXyLSmhA== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 05/19] ceph: crypto context handling for ceph Date: Fri, 26 Mar 2021 13:32:13 -0400 Message-Id: <20210326173227.96363-6-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org Store the fscrypt context for an inode as an encryption.ctx xattr. When we get a new inode in a trace, set the S_ENCRYPTED bit if the xattr blob has an encryption.ctx xattr. Signed-off-by: Jeff Layton --- fs/ceph/Makefile | 1 + fs/ceph/crypto.c | 42 ++++++++++++++++++++++++++++++++++++++++++ fs/ceph/crypto.h | 24 ++++++++++++++++++++++++ fs/ceph/inode.c | 15 +++++++++++++++ fs/ceph/super.c | 3 +++ fs/ceph/super.h | 1 + fs/ceph/xattr.c | 32 ++++++++++++++++++++++++++++++++ 7 files changed, 118 insertions(+) create mode 100644 fs/ceph/crypto.c create mode 100644 fs/ceph/crypto.h diff --git a/fs/ceph/Makefile b/fs/ceph/Makefile index 50c635dc7f71..1f77ca04c426 100644 --- a/fs/ceph/Makefile +++ b/fs/ceph/Makefile @@ -12,3 +12,4 @@ ceph-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \ ceph-$(CONFIG_CEPH_FSCACHE) += cache.o ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o +ceph-$(CONFIG_FS_ENCRYPTION) += crypto.o diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c new file mode 100644 index 000000000000..dbe8b60fd1b0 --- /dev/null +++ b/fs/ceph/crypto.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include "super.h" +#include "crypto.h" + +static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len) +{ + return __ceph_getxattr(inode, CEPH_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len); +} + +static int ceph_crypt_set_context(struct inode *inode, const void *ctx, size_t len, void *fs_data) +{ + int ret; + + WARN_ON_ONCE(fs_data); + ret = __ceph_setxattr(inode, CEPH_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len, XATTR_CREATE); + if (ret == 0) + inode_set_flags(inode, S_ENCRYPTED, S_ENCRYPTED); + return ret; +} + +static bool ceph_crypt_empty_dir(struct inode *inode) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + + return ci->i_rsubdirs + ci->i_rfiles == 1; +} + +static struct fscrypt_operations ceph_fscrypt_ops = { + .get_context = ceph_crypt_get_context, + .set_context = ceph_crypt_set_context, + .empty_dir = ceph_crypt_empty_dir, + .max_namelen = NAME_MAX, +}; + +void ceph_fscrypt_set_ops(struct super_block *sb) +{ + fscrypt_set_ops(sb, &ceph_fscrypt_ops); +} diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h new file mode 100644 index 000000000000..189bd8424284 --- /dev/null +++ b/fs/ceph/crypto.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Ceph fscrypt functionality + */ + +#ifndef _CEPH_CRYPTO_H +#define _CEPH_CRYPTO_H + +#include + +#define CEPH_XATTR_NAME_ENCRYPTION_CONTEXT "encryption.ctx" + +#ifdef CONFIG_FS_ENCRYPTION +void ceph_fscrypt_set_ops(struct super_block *sb); + +#else /* CONFIG_FS_ENCRYPTION */ + +static inline void ceph_fscrypt_set_ops(struct super_block *sb) +{ +} + +#endif /* CONFIG_FS_ENCRYPTION */ + +#endif diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 2c512475c170..33dda23c99e0 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -14,10 +14,12 @@ #include #include #include +#include #include "super.h" #include "mds_client.h" #include "cache.h" +#include "crypto.h" #include /* @@ -566,6 +568,7 @@ void ceph_evict_inode(struct inode *inode) clear_inode(inode); ceph_fscache_unregister_inode_cookie(ci); + fscrypt_put_encryption_info(inode); __ceph_remove_caps(ci); @@ -944,6 +947,18 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, ceph_forget_all_cached_acls(inode); ceph_security_invalidate_secctx(inode); xattr_blob = NULL; + + /* + * Most inodes inherit the encrypted flag from their parent, + * but empty directories can end up being encrypted later via + * ioctl. Only check for encryption if it's not already encrypted, + * and it's a new inode, or a directory. + */ + if (!IS_ENCRYPTED(inode) && + ((inode->i_state & I_NEW) || S_ISDIR(inode->i_mode))) { + if (ceph_inode_has_xattr(ci, CEPH_XATTR_NAME_ENCRYPTION_CONTEXT)) + inode_set_flags(inode, S_ENCRYPTED, S_ENCRYPTED); + } } /* finally update i_version */ diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 9b1b7f4cfdd4..cdac6ff675e2 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -20,6 +20,7 @@ #include "super.h" #include "mds_client.h" #include "cache.h" +#include "crypto.h" #include #include @@ -988,6 +989,8 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc) s->s_time_min = 0; s->s_time_max = U32_MAX; + ceph_fscrypt_set_ops(s); + ret = set_anon_super_fc(s, fc); if (ret != 0) fsc->sb = NULL; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 5e0e1aeee1b5..36b12e33b2bc 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -1016,6 +1016,7 @@ extern ssize_t ceph_listxattr(struct dentry *, char *, size_t); extern struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci); extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci); extern const struct xattr_handler *ceph_xattr_handlers[]; +bool ceph_inode_has_xattr(struct ceph_inode_info *ci, const char *name); struct ceph_acl_sec_ctx { #ifdef CONFIG_CEPH_FS_POSIX_ACL diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 02f59bcb4f27..38ac2968e4a1 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -1360,6 +1360,38 @@ void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx) ceph_pagelist_release(as_ctx->pagelist); } +/* Return true if inode's xattr blob has an xattr named "name" */ +bool ceph_inode_has_xattr(struct ceph_inode_info *ci, const char *name) +{ + void *p, *end; + u32 numattr; + size_t namelen; + + lockdep_assert_held(&ci->i_ceph_lock); + + if (!ci->i_xattrs.blob || ci->i_xattrs.blob->vec.iov_len <= 4) + return false; + + namelen = strlen(name); + p = ci->i_xattrs.blob->vec.iov_base; + end = p + ci->i_xattrs.blob->vec.iov_len; + ceph_decode_32_safe(&p, end, numattr, bad); + + while (numattr--) { + u32 len; + + ceph_decode_32_safe(&p, end, len, bad); + ceph_decode_need(&p, end, len, bad); + if (len == namelen && !memcmp(p, name, len)) + return true; + p += len; + ceph_decode_32_safe(&p, end, len, bad); + ceph_decode_skip_n(&p, end, len, bad); + } +bad: + return false; +} + /* * List of handlers for synthetic system.* attributes. Other * attributes are handled directly. From patchwork Fri Mar 26 17:32:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409586 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E5A8AC433F4 for ; Fri, 26 Mar 2021 17:33:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B7F4E61999 for ; Fri, 26 Mar 2021 17:33:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230288AbhCZRcq (ORCPT ); Fri, 26 Mar 2021 13:32:46 -0400 Received: from mail.kernel.org ([198.145.29.99]:48318 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230223AbhCZRcg (ORCPT ); Fri, 26 Mar 2021 13:32:36 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 64A7461A2B; Fri, 26 Mar 2021 17:32:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779954; bh=3gRPAvJ9pyfsVKUPJKz1HZd4M+bMwwUijVds6ndHDYQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q4ch4bcSi8KOyYjrwifXaWaUNjUD6fOutZyp7te4fdElM4H7aC86Rd0kRljgNNuXc ne3x7XZGkTS9RbE0TjgevA/QDClKErQtpsPoS4R/aYGkmgURpTbd+HQUZckCt1/jdq rKvXdV1bjFr/qklzA88y46OuFwxMxLmyDSOsic6NEvkGHnPQ2FD9t7oAeIzHvnPyVY ogayQMNHWmTDSlftSrnkO+LmtGDNsPAyG8f4dsHG+XfUx2jUTT9QEU61dKdGU8Xwdn 1sDip+BSzfmRp5poetxIUTYfAIG/EJG2/95kuluf7PZjGmykLZwqxT4At9e6vIL9Kx pW3WTVvp/tBvg== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 08/19] ceph: add routine to create fscrypt context prior to RPC Date: Fri, 26 Mar 2021 13:32:16 -0400 Message-Id: <20210326173227.96363-9-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org After pre-creating a new inode, do an fscrypt prepare on it, fetch a new encryption context and then marshal that into the security context to be sent along with the RPC. Call the new function from ceph_new_inode. Signed-off-by: Jeff Layton --- fs/ceph/crypto.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/ceph/crypto.h | 12 ++++++++++ fs/ceph/inode.c | 9 +++++-- fs/ceph/super.h | 3 +++ 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index 879d9a0d3751..f037a4939026 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -46,3 +46,64 @@ void ceph_fscrypt_set_ops(struct super_block *sb) { fscrypt_set_ops(sb, &ceph_fscrypt_ops); } + +int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, + struct ceph_acl_sec_ctx *as) +{ + int ret, ctxsize; + size_t name_len; + char *name; + struct ceph_pagelist *pagelist = as->pagelist; + bool encrypted = false; + + ret = fscrypt_prepare_new_inode(dir, inode, &encrypted); + if (ret) + return ret; + if (!encrypted) + return 0; + + inode->i_flags |= S_ENCRYPTED; + + ctxsize = fscrypt_context_for_new_inode(&as->fscrypt, inode); + if (ctxsize < 0) + return ctxsize; + + /* marshal it in page array */ + if (!pagelist) { + pagelist = ceph_pagelist_alloc(GFP_KERNEL); + if (!pagelist) + return -ENOMEM; + ret = ceph_pagelist_reserve(pagelist, PAGE_SIZE); + if (ret) + goto out; + ceph_pagelist_encode_32(pagelist, 1); + } + + name = CEPH_XATTR_NAME_ENCRYPTION_CONTEXT; + name_len = strlen(name); + ret = ceph_pagelist_reserve(pagelist, 4 * 2 + name_len + ctxsize); + if (ret) + goto out; + + if (as->pagelist) { + BUG_ON(pagelist->length <= sizeof(__le32)); + if (list_is_singular(&pagelist->head)) { + le32_add_cpu((__le32*)pagelist->mapped_tail, 1); + } else { + struct page *page = list_first_entry(&pagelist->head, + struct page, lru); + void *addr = kmap_atomic(page); + le32_add_cpu((__le32*)addr, 1); + kunmap_atomic(addr); + } + } + + ceph_pagelist_encode_32(pagelist, name_len); + ceph_pagelist_append(pagelist, name, name_len); + ceph_pagelist_encode_32(pagelist, ctxsize); + ceph_pagelist_append(pagelist, as->fscrypt, ctxsize); +out: + if (pagelist && !as->pagelist) + ceph_pagelist_release(pagelist); + return ret; +} diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h index 0dd043b56096..cc4e481bf13a 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h @@ -18,6 +18,9 @@ static inline void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc) fscrypt_free_dummy_policy(&fsc->dummy_enc_policy); } +int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, + struct ceph_acl_sec_ctx *as); + #else /* CONFIG_FS_ENCRYPTION */ static inline void ceph_fscrypt_set_ops(struct super_block *sb) @@ -27,6 +30,15 @@ static inline void ceph_fscrypt_set_ops(struct super_block *sb) static inline void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc) { } + +static inline int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, + struct ceph_acl_sec_ctx *as) +{ + if (IS_ENCRYPTED(dir)) + return -EOPNOTSUPP; + return 0; +} + #endif /* CONFIG_FS_ENCRYPTION */ #endif diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 7b70187cc564..64cdc4513c8a 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -83,12 +83,17 @@ struct inode *ceph_new_inode(struct inode *dir, struct dentry *dentry, goto out_err; } + inode->i_state = 0; + inode->i_mode = *mode; + err = ceph_security_init_secctx(dentry, *mode, as_ctx); if (err < 0) goto out_err; - inode->i_state = 0; - inode->i_mode = *mode; + err = ceph_fscrypt_prepare_context(dir, inode, as_ctx); + if (err) + goto out_err; + return inode; out_err: iput(inode); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 8a40374f9154..3b85a5154b49 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -1034,6 +1034,9 @@ struct ceph_acl_sec_ctx { #ifdef CONFIG_CEPH_FS_SECURITY_LABEL void *sec_ctx; u32 sec_ctxlen; +#endif +#ifdef CONFIG_FS_ENCRYPTION + u8 fscrypt[FSCRYPT_SET_CONTEXT_MAX_SIZE]; #endif struct ceph_pagelist *pagelist; }; From patchwork Fri Mar 26 17:32:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409583 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0CD98C4345D for ; Fri, 26 Mar 2021 17:33:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CEF0D61A2B for ; Fri, 26 Mar 2021 17:33:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230343AbhCZRcx (ORCPT ); Fri, 26 Mar 2021 13:32:53 -0400 Received: from mail.kernel.org ([198.145.29.99]:48322 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230198AbhCZRcg (ORCPT ); Fri, 26 Mar 2021 13:32:36 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id B47DB61A28; Fri, 26 Mar 2021 17:32:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779956; bh=aSlpCmNDnJqfQyFLWTSlku6kb/FBLnS3j1023Kp/1bU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KYGrCBMJ//FJL0muk55fFpr6xqHW5epXBSkgtp1SDkJHNzNf45duulvnslQBb9Hbu uQnIKwcI5hWMRFa62XhAjkmp5ADLjYPu87tF+2zGeKmCnc2Up8yjhzgETPFPGkjose TYAFvm+9Jm6y4ql3gLS5CJQnI30WJ+asiW8XAoGkQQVLkqkeZ8T3LePFNn3cnokoqN apAnl11DHIJPmGxGLPYdxbDfUXTmDNVSObP6rKqiTCUJnYMfeRoV7pfQBt/Mh6Dj05 f99T3BkDvGiowI+8cmiWNYKew3DXmfEX+GfLI6vUKVTRnFlQMc4vwI1SBTiMUY5089 keS5hcGc8/5QQ== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 10/19] ceph: add encrypted fname handling to ceph_mdsc_build_path Date: Fri, 26 Mar 2021 13:32:18 -0400 Message-Id: <20210326173227.96363-11-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org Allow ceph_mdsc_build_path to encrypt and base64 encode the filename when the parent is encrypted and we're sending the path to the MDS. In most cases, we just encrypt the filenames and base64 encode them, but when the name is longer than CEPH_NOHASH_NAME_MAX, we use a similar scheme to fscrypt proper, and hash the remaning bits with sha256. When doing this, we then send along the full crypttext of the name in the new alternate_name field of the MClientRequest. The MDS can then send that along in readdir responses and traces. Signed-off-by: Jeff Layton --- fs/ceph/crypto.h | 16 +++++ fs/ceph/mds_client.c | 138 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 136 insertions(+), 18 deletions(-) diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h index cc4e481bf13a..331b9c8da7fb 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h @@ -6,11 +6,27 @@ #ifndef _CEPH_CRYPTO_H #define _CEPH_CRYPTO_H +#include #include #define CEPH_XATTR_NAME_ENCRYPTION_CONTEXT "encryption.ctx" #ifdef CONFIG_FS_ENCRYPTION + +/* + * We want to encrypt filenames when creating them, but the encrypted + * versions of those names may have illegal characters in them. To mitigate + * that, we base64 encode them, but that gives us a result that can exceed + * NAME_MAX. + * + * Follow a similar scheme to fscrypt itself, and cap the filename to a + * smaller size. If the cleartext name is longer than the value below, then + * sha256 hash the remaining bytes. + * + * 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) + */ +#define CEPH_NOHASH_NAME_MAX (189 - SHA256_DIGEST_SIZE) + void ceph_fscrypt_set_ops(struct super_block *sb); static inline void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d7a40e83f12f..814f74d88748 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -13,6 +13,7 @@ #include #include "super.h" +#include "crypto.h" #include "mds_client.h" #include @@ -2310,18 +2311,85 @@ static inline u64 __get_oldest_tid(struct ceph_mds_client *mdsc) return mdsc->oldest_tid; } -/* - * Build a dentry's path. Allocate on heap; caller must kfree. Based - * on build_path_from_dentry in fs/cifs/dir.c. +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) +static int encode_encrypted_fname(const struct inode *parent, struct dentry *dentry, char *buf) +{ + u32 len; + int elen; + int ret; + u8 *cryptbuf; + + WARN_ON_ONCE(!fscrypt_has_encryption_key(parent)); + + /* + * convert cleartext dentry name to ciphertext + * if result is longer than CEPH_NOKEY_NAME_MAX, + * sha256 the remaining bytes + * + * See: fscrypt_setup_filename + */ + if (!fscrypt_fname_encrypted_size(parent, dentry->d_name.len, NAME_MAX, &len)) + return -ENAMETOOLONG; + + /* If we have to hash the end, then we need a full-length buffer */ + if (len > CEPH_NOHASH_NAME_MAX) + len = NAME_MAX; + + cryptbuf = kmalloc(len, GFP_KERNEL); + if (!cryptbuf) + return -ENOMEM; + + ret = fscrypt_fname_encrypt(parent, &dentry->d_name, cryptbuf, len); + if (ret) { + kfree(cryptbuf); + return ret; + } + + /* hash the end if the name is long enough */ + if (len > CEPH_NOHASH_NAME_MAX) { + u8 hash[SHA256_DIGEST_SIZE]; + u8 *extra = cryptbuf + CEPH_NOHASH_NAME_MAX; + + /* hash the extra bytes and overwrite crypttext beyond that point with it */ + sha256(extra, len - CEPH_NOHASH_NAME_MAX, hash); + memcpy(extra, hash, SHA256_DIGEST_SIZE); + len = CEPH_NOHASH_NAME_MAX + SHA256_DIGEST_SIZE; + } + + /* base64 encode the encrypted name */ + elen = fscrypt_base64_encode(cryptbuf, len, buf); + kfree(cryptbuf); + dout("base64-encoded ciphertext name = %.*s\n", len, buf); + return elen; +} +#else +static int encode_encrypted_fname(const struct inode *parent, struct dentry *dentry, char *buf) +{ + return -EOPNOTSUPP; +} +#endif + +/** + * ceph_mdsc_build_path - build a path string to a given dentry + * @dentry: dentry to which path should be built + * @plen: returned length of string + * @pbase: returned base inode number + * @for_wire: is this path going to be sent to the MDS? + * + * Build a string that represents the path to the dentry. This is mostly called + * for two different purposes: * - * If @stop_on_nosnap, generate path relative to the first non-snapped - * inode. + * 1) we need to build a path string to send to the MDS (for_wire == true) + * 2) we need a path string for local presentation (e.g. debugfs) (for_wire == false) + * + * The path is built in reverse, starting with the dentry. Walk back up toward + * the root, building the path until the first non-snapped inode is reached (for_wire) + * or the root inode is reached (!for_wire). * * Encode hidden .snap dirs as a double /, i.e. * foo/.snap/bar -> foo//bar */ -char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase, - int stop_on_nosnap) +char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase, int for_wire) { struct dentry *cur; struct inode *inode; @@ -2343,30 +2411,65 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase, seq = read_seqbegin(&rename_lock); cur = dget(dentry); for (;;) { - struct dentry *temp; + struct dentry *parent; spin_lock(&cur->d_lock); inode = d_inode(cur); if (inode && ceph_snap(inode) == CEPH_SNAPDIR) { dout("build_path path+%d: %p SNAPDIR\n", pos, cur); - } else if (stop_on_nosnap && inode && dentry != cur && - ceph_snap(inode) == CEPH_NOSNAP) { + spin_unlock(&cur->d_lock); + parent = dget_parent(cur); + } else if (for_wire && inode && dentry != cur && ceph_snap(inode) == CEPH_NOSNAP) { spin_unlock(&cur->d_lock); pos++; /* get rid of any prepended '/' */ break; - } else { + } else if (!for_wire || !IS_ENCRYPTED(d_inode(cur->d_parent))) { pos -= cur->d_name.len; if (pos < 0) { spin_unlock(&cur->d_lock); break; } memcpy(path + pos, cur->d_name.name, cur->d_name.len); + spin_unlock(&cur->d_lock); + parent = dget_parent(cur); + } else { + int len, ret; + char buf[FSCRYPT_BASE64_CHARS(NAME_MAX)]; + + /* + * Proactively copy name into buf, in case we need to present + * it as-is. + */ + memcpy(buf, cur->d_name.name, cur->d_name.len); + len = cur->d_name.len; + spin_unlock(&cur->d_lock); + parent = dget_parent(cur); + + ret = __fscrypt_prepare_readdir(d_inode(parent)); + if (ret < 0) { + dput(parent); + dput(cur); + return ERR_PTR(ret); + } + + if (fscrypt_has_encryption_key(d_inode(parent))) { + len = encode_encrypted_fname(d_inode(parent), cur, buf); + if (len < 0) { + dput(parent); + dput(cur); + return ERR_PTR(len); + } + } + pos -= len; + if (pos < 0) { + dput(parent); + break; + } + memcpy(path + pos, buf, len); } - temp = cur; - spin_unlock(&temp->d_lock); - cur = dget_parent(temp); - dput(temp); + dput(cur); + cur = parent; /* Are we at the root? */ if (IS_ROOT(cur)) @@ -2390,8 +2493,7 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase, * A rename didn't occur, but somehow we didn't end up where * we thought we would. Throw a warning and try again. */ - pr_warn("build_path did not end path lookup where " - "expected, pos is %d\n", pos); + pr_warn("build_path did not end path lookup where expected (pos = %d)\n", pos); goto retry; } @@ -2411,7 +2513,7 @@ static int build_dentry_path(struct dentry *dentry, struct inode *dir, rcu_read_lock(); if (!dir) dir = d_inode_rcu(dentry->d_parent); - if (dir && parent_locked && ceph_snap(dir) == CEPH_NOSNAP) { + if (dir && parent_locked && ceph_snap(dir) == CEPH_NOSNAP && !IS_ENCRYPTED(dir)) { *pino = ceph_ino(dir); rcu_read_unlock(); *ppath = dentry->d_name.name; From patchwork Fri Mar 26 17:32:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409584 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B7CB5C433DB for ; Fri, 26 Mar 2021 17:33:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8D0E661A3F for ; Fri, 26 Mar 2021 17:33:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230334AbhCZRcw (ORCPT ); Fri, 26 Mar 2021 13:32:52 -0400 Received: from mail.kernel.org ([198.145.29.99]:48318 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230229AbhCZRch (ORCPT ); Fri, 26 Mar 2021 13:32:37 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 681DD61A13; Fri, 26 Mar 2021 17:32:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779956; bh=MOB3lUzex0arW8xhnrg0Tjc0j91jO80EJ3WeS+U1vVg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=n7L5D4RdZs+VhR2kjO1Co2pHXRzJyBc/Y8T/c7n1XfOh9jv+ULSUcpPAB140m++CT 0OjFSXT1eSuwjsNzz9iDF3HUrR71T+QfDAcmx1kULl/x0M+QiiZuesnR+2wLRL+PFD aslQ8AfzCncj0TLd/0wIMiLutmgHP0TJrQ4fIH0V4kJ+tuYmQUE6ubYhft1c2Ik3/7 zvBsdrfDils1JKTdiikAOOOPTHxYQPXlNpT8JvyUpioLUSXKcKqEdofn5OQQS3Unx4 80uvOeQsCOJDRtuIYi5vLYYO39oUXQ5LocoU5BEmMS18czQ17lTthRJL1jKs01YK5a PVU9mMk9Z3xEg== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 11/19] ceph: decode alternate_name in lease info Date: Fri, 26 Mar 2021 13:32:19 -0400 Message-Id: <20210326173227.96363-12-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org Ceph is a bit different from local filesystems, in that we don't want to store filenames as raw binary data, since we may also be dealing with clients that don't support fscrypt. We could just base64-encode the encrypted filenames, but that could leave us with filenames longer than NAME_MAX. It turns out that the MDS doesn't care much about filename length, but the clients do. To manage this, we've added a new "alternate name" field that can be optionally added to any dentry that we'll use to store the binary crypttext of the filename if its base64-encoded value will be longer than NAME_MAX. When a dentry has one of these names attached, the MDS will send it along in the lease info, which we can then store for later usage. Signed-off-by: Jeff Layton --- fs/ceph/mds_client.c | 40 ++++++++++++++++++++++++++++++---------- fs/ceph/mds_client.h | 11 +++++++---- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 814f74d88748..31a4c9674681 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -256,27 +256,44 @@ static int parse_reply_info_dir(void **p, void *end, static int parse_reply_info_lease(void **p, void *end, struct ceph_mds_reply_lease **lease, - u64 features) + u64 features, u32 *altname_len, u8 **altname) { + u8 struct_v; + u32 struct_len; + if (features == (u64)-1) { - u8 struct_v, struct_compat; - u32 struct_len; + u8 struct_compat; + ceph_decode_8_safe(p, end, struct_v, bad); ceph_decode_8_safe(p, end, struct_compat, bad); + /* struct_v is expected to be >= 1. we only understand * encoding whose struct_compat == 1. */ if (!struct_v || struct_compat != 1) goto bad; + ceph_decode_32_safe(p, end, struct_len, bad); - ceph_decode_need(p, end, struct_len, bad); - end = *p + struct_len; + } else { + struct_len = sizeof(**lease); + *altname_len = 0; + *altname = NULL; } - ceph_decode_need(p, end, sizeof(**lease), bad); + ceph_decode_need(p, end, struct_len, bad); *lease = *p; *p += sizeof(**lease); - if (features == (u64)-1) - *p = end; + + if (features == (u64)-1) { + if (struct_v >= 2) { + ceph_decode_32_safe(p, end, *altname_len, bad); + ceph_decode_need(p, end, *altname_len, bad); + *altname = *p; + *p += *altname_len; + } else { + *altname = NULL; + *altname_len = 0; + } + } return 0; bad: return -EIO; @@ -306,7 +323,8 @@ static int parse_reply_info_trace(void **p, void *end, info->dname = *p; *p += info->dname_len; - err = parse_reply_info_lease(p, end, &info->dlease, features); + err = parse_reply_info_lease(p, end, &info->dlease, features, + &info->altname_len, &info->altname); if (err < 0) goto out_bad; } @@ -373,9 +391,11 @@ static int parse_reply_info_readdir(void **p, void *end, dout("parsed dir dname '%.*s'\n", rde->name_len, rde->name); /* dentry lease */ - err = parse_reply_info_lease(p, end, &rde->lease, features); + err = parse_reply_info_lease(p, end, &rde->lease, features, + &rde->altname_len, &rde->altname); if (err) goto out_bad; + /* inode */ err = parse_reply_info_in(p, end, &rde->inode, features); if (err < 0) diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 2b18ea24c650..b6aeca9b241b 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -29,8 +29,8 @@ enum ceph_feature_type { CEPHFS_FEATURE_MULTI_RECONNECT, CEPHFS_FEATURE_DELEG_INO, CEPHFS_FEATURE_METRIC_COLLECT, - - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_ALTERNATE_NAME, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_ALTERNATE_NAME, }; /* @@ -45,8 +45,7 @@ enum ceph_feature_type { CEPHFS_FEATURE_MULTI_RECONNECT, \ CEPHFS_FEATURE_DELEG_INO, \ CEPHFS_FEATURE_METRIC_COLLECT, \ - \ - CEPHFS_FEATURE_MAX, \ + CEPHFS_FEATURE_ALTERNATE_NAME, \ } #define CEPHFS_FEATURES_CLIENT_REQUIRED {} @@ -93,7 +92,9 @@ struct ceph_mds_reply_info_in { struct ceph_mds_reply_dir_entry { char *name; + u8 *altname; u32 name_len; + u32 altname_len; struct ceph_mds_reply_lease *lease; struct ceph_mds_reply_info_in inode; loff_t offset; @@ -112,7 +113,9 @@ struct ceph_mds_reply_info_parsed { struct ceph_mds_reply_info_in diri, targeti; struct ceph_mds_reply_dirfrag *dirfrag; char *dname; + u8 *altname; u32 dname_len; + u32 altname_len; struct ceph_mds_reply_lease *dlease; /* extra */ From patchwork Fri Mar 26 17:32:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409581 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1EBFAC4332E for ; Fri, 26 Mar 2021 17:33:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E950B61A13 for ; Fri, 26 Mar 2021 17:33:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230376AbhCZRc6 (ORCPT ); Fri, 26 Mar 2021 13:32:58 -0400 Received: from mail.kernel.org ([198.145.29.99]:48324 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230231AbhCZRci (ORCPT ); Fri, 26 Mar 2021 13:32:38 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 1AEA461A2B; Fri, 26 Mar 2021 17:32:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779957; bh=C77FPiXyQYcU/8fTelD3ZMx6YlBkXH7rNgFoqNr1Vt8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZvGFkspZyvovaebnf4vnqRKLiXDd3Qhg0kr1JA9rVHFtFye+ruvVam3InvLyATDnc 9HsUq+DsmkEWR4d5HrkH81rEnJz38h1OnEjJ6nT9aDTTW+10GGQO7Fko1EskO21fxa 0Kjz9eSh2zSqTfpVJJjW6oGNGa5jRNL1DblSNC1UCZHr5zFpT4+LeoRLae8kJJ2gfS TdAUOxKMJlmFz4/CM+LDkd5RUUaZnLi8lFJdjaCrbyL95SxHFy6tZ2KjyxvDEDDzhy K3dIKFUu7eqms2xWh0Idj6k9+/bc5eO0D1DcMT0PLFwBBoHvXVgrME8G81tC9LkLH4 uaS4g4qXJdNlA== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 12/19] ceph: send altname in MClientRequest Date: Fri, 26 Mar 2021 13:32:20 -0400 Message-Id: <20210326173227.96363-13-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org In the event that we have a filename longer than CEPH_NOHASH_NAME_MAX, we'll need to hash the tail of the filename. The client however will still need to know the full name of the file if it has a key. To support this, the MClientRequest field has grown a new alternate_name field that we populate with the full (binary) crypttext of the filename. This is then transmitted to the clients in readdir or traces as part of the dentry lease. Add support for populating this field when the filenames are very long. Signed-off-by: Jeff Layton --- fs/ceph/mds_client.c | 79 +++++++++++++++++++++++++++++++++++++++++--- fs/ceph/mds_client.h | 2 ++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 31a4c9674681..a2c25292c4b1 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -858,6 +858,7 @@ void ceph_mdsc_release_request(struct kref *kref) put_cred(req->r_cred); if (req->r_pagelist) ceph_pagelist_release(req->r_pagelist); + kfree(req->r_altname); put_request_session(req); ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation); WARN_ON_ONCE(!list_empty(&req->r_wait)); @@ -2382,11 +2383,66 @@ static int encode_encrypted_fname(const struct inode *parent, struct dentry *den dout("base64-encoded ciphertext name = %.*s\n", len, buf); return elen; } + +static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen) +{ + struct inode *dir = req->r_parent; + struct dentry *dentry = req->r_dentry; + u8 *cryptbuf = NULL; + u32 len = 0; + int ret = 0; + + /* only encode if we have parent and dentry */ + if (!dir || !dentry) + goto success; + + /* No-op unless this is encrypted */ + if (!IS_ENCRYPTED(dir)) + goto success; + + ret = __fscrypt_prepare_readdir(dir); + if (ret) + return ERR_PTR(ret); + + /* No key? Just ignore it. */ + if (!fscrypt_has_encryption_key(dir)) + goto success; + + if (!fscrypt_fname_encrypted_size(dir, dentry->d_name.len, NAME_MAX, &len)) { + WARN_ON_ONCE(1); + return ERR_PTR(-ENAMETOOLONG); + } + + /* No need to append altname if name is short enough */ + if (len <= CEPH_NOHASH_NAME_MAX) { + len = 0; + goto success; + } + + cryptbuf = kmalloc(len, GFP_KERNEL); + if (!cryptbuf) + return ERR_PTR(-ENOMEM); + + ret = fscrypt_fname_encrypt(dir, &dentry->d_name, cryptbuf, len); + if (ret) { + kfree(cryptbuf); + return ERR_PTR(ret); + } +success: + *plen = len; + return cryptbuf; +} #else static int encode_encrypted_fname(const struct inode *parent, struct dentry *dentry, char *buf) { return -EOPNOTSUPP; } + +static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen) +{ + *plen = 0; + return NULL; +} #endif /** @@ -2601,7 +2657,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, return r; } -static void encode_timestamp_and_gids(void **p, +static void encode_mclientrequest_tail(void **p, const struct ceph_mds_request *req) { struct ceph_timespec ts; @@ -2610,11 +2666,16 @@ static void encode_timestamp_and_gids(void **p, ceph_encode_timespec64(&ts, &req->r_stamp); ceph_encode_copy(p, &ts, sizeof(ts)); - /* gid_list */ + /* v4: gid_list */ ceph_encode_32(p, req->r_cred->group_info->ngroups); for (i = 0; i < req->r_cred->group_info->ngroups; i++) ceph_encode_64(p, from_kgid(&init_user_ns, req->r_cred->group_info->gid[i])); + + /* v5: altname */ + ceph_encode_32(p, req->r_altname_len); + if (req->r_altname_len) + ceph_encode_copy(p, req->r_altname, req->r_altname_len); } /* @@ -2659,10 +2720,18 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, goto out_free1; } + req->r_altname = get_fscrypt_altname(req, &req->r_altname_len); + if (IS_ERR(req->r_altname)) { + msg = ERR_CAST(req->r_altname); + req->r_altname = NULL; + goto out_free2; + } + len = legacy ? sizeof(*head) : sizeof(struct ceph_mds_request_head); len += pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) + sizeof(struct ceph_timespec); len += sizeof(u32) + (sizeof(u64) * req->r_cred->group_info->ngroups); + len += sizeof(u32) + req->r_altname_len; /* calculate (max) length for cap releases */ len += sizeof(struct ceph_mds_request_release) * @@ -2693,7 +2762,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, } else { struct ceph_mds_request_head *new_head = msg->front.iov_base; - msg->hdr.version = cpu_to_le16(4); + msg->hdr.version = cpu_to_le16(5); new_head->version = cpu_to_le16(CEPH_MDS_REQUEST_HEAD_VERSION); head = (struct ceph_mds_request_head_old *)&new_head->oldest_client_tid; p = msg->front.iov_base + sizeof(*new_head); @@ -2744,7 +2813,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, head->num_releases = cpu_to_le16(releases); - encode_timestamp_and_gids(&p, req); + encode_mclientrequest_tail(&p, req); if (WARN_ON_ONCE(p > end)) { ceph_msg_put(msg); @@ -2853,7 +2922,7 @@ static int __prepare_send_request(struct ceph_mds_session *session, rhead->num_releases = 0; p = msg->front.iov_base + req->r_request_release_offset; - encode_timestamp_and_gids(&p, req); + encode_mclientrequest_tail(&p, req); msg->front.iov_len = p - msg->front.iov_base; msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index b6aeca9b241b..33b8dba7a44e 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -278,6 +278,8 @@ struct ceph_mds_request { struct mutex r_fill_mutex; union ceph_mds_request_args r_args; + u8 *r_altname; /* fscrypt binary crypttext for long filenames */ + u32 r_altname_len; /* length of r_altname */ int r_fmode; /* file mode, if expecting cap */ const struct cred *r_cred; int r_request_release_offset; From patchwork Fri Mar 26 17:32:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409580 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5761CC43332 for ; Fri, 26 Mar 2021 17:33:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 32C6D61999 for ; Fri, 26 Mar 2021 17:33:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230378AbhCZRc6 (ORCPT ); Fri, 26 Mar 2021 13:32:58 -0400 Received: from mail.kernel.org ([198.145.29.99]:48328 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230237AbhCZRcj (ORCPT ); Fri, 26 Mar 2021 13:32:39 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 7159361999; Fri, 26 Mar 2021 17:32:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779958; bh=txA1YUye09KqfbmVs0VBQwSMiAzyb4sJGcW6VErNpVY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Czf42N8K79+5yxRALW8S1lhTrxKdhtpxJ9l+tenDLa8Sl4Z1Xf+yRthp9Tttvbyi2 w7gdM6BB/2JZ7TAsyuXqSOXvPncbLvUWPncLR1j0HSzBZl/Klx9bzSFSeZRK16OVof KFuv9bwkl1ghIXHc3EZmqTSbQ2BsiEGNz6ihHLAPnytZPPoF0VFmXsueDX9Aj6os8r rBsOuEvZbXP4cj8qrzDfagxxUia1JbvyWED6HkMJwCqfWp9ZnUv/tREuJAtLoDbsyu w57zt1IOi+mR7V3mj4aPgJJd2UNgIeTFxB7NBqc3SYUCGrTNCXfX3bbMG0+zdaz7X2 /YnJTsno2CDDw== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 14/19] ceph: make d_revalidate call fscrypt revalidator for encrypted dentries Date: Fri, 26 Mar 2021 13:32:22 -0400 Message-Id: <20210326173227.96363-15-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org If we have a dentry which represents a no-key name, then we need to test whether the parent directory's encryption key has since been added. Do that before we test anything else about the dentry. Signed-off-by: Jeff Layton --- fs/ceph/dir.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 72728850e96c..867e396f44f1 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1697,6 +1697,10 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) struct inode *dir, *inode; struct ceph_mds_client *mdsc; + valid = fscrypt_d_revalidate(dentry, flags); + if (valid <= 0) + return valid; + if (flags & LOOKUP_RCU) { parent = READ_ONCE(dentry->d_parent); dir = d_inode_rcu(parent); @@ -1709,8 +1713,8 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) inode = d_inode(dentry); } - dout("d_revalidate %p '%pd' inode %p offset 0x%llx\n", dentry, - dentry, inode, ceph_dentry(dentry)->offset); + dout("d_revalidate %p '%pd' inode %p offset 0x%llx nokey %d\n", dentry, + dentry, inode, ceph_dentry(dentry)->offset, !!(dentry->d_flags & DCACHE_NOKEY_NAME)); mdsc = ceph_sb_to_client(dir->i_sb)->mdsc; From patchwork Fri Mar 26 17:32:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409579 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6D239C433E9 for ; Fri, 26 Mar 2021 17:33:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 367E8619B8 for ; Fri, 26 Mar 2021 17:33:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230407AbhCZRdO (ORCPT ); Fri, 26 Mar 2021 13:33:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:48336 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230247AbhCZRck (ORCPT ); Fri, 26 Mar 2021 13:32:40 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C976061999; Fri, 26 Mar 2021 17:32:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779960; bh=6xZpBiTnoHtIJkNEIvaZxzupy5U2KaTOn2huDHMP6ag=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oZ4VgQe18k+LrEELidgorJk3IkMRImwz+4Db6O05AGqr1A32VpMQDQFfFyVuSHtqR OaSwWGI+opoi4IbmV8f0o7EPJ+V4f3+spCodVKAJBQEzWNv5u/BgHbI57csDHdYcEs /7a4kd4sp9XQNauRcWXQ7pTsiX6Iq2daXRCXwamvpJCv2tuLJIkOLjxpYGLuImLXLC 1syJjFOqGHK1RJ1CvvAFaq2wkJmiiK5uGZyb2d0aN+lwHug+WmvUCfGsgwqLi68ehC gPR2JwXvt6pHNn1CJyK41zOnCbwzc2iwkwa0PADbaMVUib2scqCZWWYhEvJlbBgtv2 7d/b/sTjVQG9A== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 16/19] ceph: add fscrypt support to ceph_fill_trace Date: Fri, 26 Mar 2021 13:32:24 -0400 Message-Id: <20210326173227.96363-17-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org When we get a dentry in a trace, decrypt the name so we can properly instantiate the dentry. Signed-off-by: Jeff Layton --- fs/ceph/inode.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 64cdc4513c8a..39f4c0dfa071 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1381,8 +1381,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) if (dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME && test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) && !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) { + bool is_nokey = false; struct qstr dname; struct dentry *dn, *parent; + struct fscrypt_str oname = FSTR_INIT(NULL, 0); + struct ceph_fname fname = { .dir = dir, + .name = rinfo->dname, + .ctext = rinfo->altname, + .name_len = rinfo->dname_len, + .ctext_len = rinfo->altname_len }; BUG_ON(!rinfo->head->is_target); BUG_ON(req->r_dentry); @@ -1390,8 +1397,20 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) parent = d_find_any_alias(dir); BUG_ON(!parent); - dname.name = rinfo->dname; - dname.len = rinfo->dname_len; + err = ceph_fname_alloc_buffer(dir, &oname); + if (err < 0) { + dput(parent); + goto done; + } + + err = ceph_fname_to_usr(&fname, NULL, &oname, &is_nokey); + if (err < 0) { + dput(parent); + ceph_fname_free_buffer(dir, &oname); + goto done; + } + dname.name = oname.name; + dname.len = oname.len; dname.hash = full_name_hash(parent, dname.name, dname.len); tvino.ino = le64_to_cpu(rinfo->targeti.in->ino); tvino.snap = le64_to_cpu(rinfo->targeti.in->snapid); @@ -1406,9 +1425,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) dname.len, dname.name, dn); if (!dn) { dput(parent); + ceph_fname_free_buffer(dir, &oname); err = -ENOMEM; goto done; } + if (is_nokey) { + spin_lock(&dn->d_lock); + dn->d_flags |= DCACHE_NOKEY_NAME; + spin_unlock(&dn->d_lock); + } err = 0; } else if (d_really_is_positive(dn) && (ceph_ino(d_inode(dn)) != tvino.ino || @@ -1420,6 +1445,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) dput(dn); goto retry_lookup; } + ceph_fname_free_buffer(dir, &oname); req->r_dentry = dn; dput(parent); From patchwork Fri Mar 26 17:32:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 409578 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 07B1CC433F1 for ; Fri, 26 Mar 2021 17:33:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D389F61A32 for ; Fri, 26 Mar 2021 17:33:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230454AbhCZRdR (ORCPT ); Fri, 26 Mar 2021 13:33:17 -0400 Received: from mail.kernel.org ([198.145.29.99]:48346 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230252AbhCZRcn (ORCPT ); Fri, 26 Mar 2021 13:32:43 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id CCEFC61A28; Fri, 26 Mar 2021 17:32:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1616779962; bh=OK2KGWFptjTIN1OXjEChJKuyV3fd0j4GvVod8RQV4Kk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KtkXBn9ItWo8N68h8CWZRXbKHxgxgwiMkBuu7RmK9NDAQc71iT8t2vX0ucRZ5/HCQ wsPlurc++bKJ6ckHKTWiTGl7NavTLyNA7eMPRuiiYUqidglaS5jEvi+eBhCM+ZMRIS CcjGrvOMl0tFvk+Rg1sMLdDRvT//6xQmSUG+Zxpp5XmJo6kyDh7BilQ6BHlHS9tSQq NXWc52APLZRIy5c7+J49QAQ3cWVLOPk9Eu7Xg5DRj+BwAFQrMydzxvIGYrssLM48bt btMvMh31P8ZG55HwFPbJln0i0C8lfnTt6GNgf6usyfnck7L05FmTl6WHCCIlinVeVf dMxk27nemf3oA== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 19/19] ceph: add fscrypt ioctls Date: Fri, 26 Mar 2021 13:32:27 -0400 Message-Id: <20210326173227.96363-20-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org We gate most of the ioctls on MDS feature support. The exception is the key removal and status functions that we still want to work if the MDS's were to (inexplicably) lose the feature. For the set_policy ioctl, we take Fcx caps to ensure that nothing can create files in the directory while the ioctl is running. That should be enough to ensure that the "empty_dir" check is reliable. Signed-off-by: Jeff Layton --- fs/ceph/ioctl.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c index 6e061bf62ad4..34b85bcfcfc7 100644 --- a/fs/ceph/ioctl.c +++ b/fs/ceph/ioctl.c @@ -6,6 +6,7 @@ #include "mds_client.h" #include "ioctl.h" #include +#include /* * ioctls @@ -268,8 +269,56 @@ static long ceph_ioctl_syncio(struct file *file) return 0; } +static int vet_mds_for_fscrypt(struct file *file) +{ + int i, ret = -EOPNOTSUPP; + struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(file_inode(file)->i_sb); + + mutex_lock(&mdsc->mutex); + for (i = 0; i < mdsc->max_sessions; i++) { + struct ceph_mds_session *s = mdsc->sessions[i]; + + if (!s) + continue; + if (test_bit(CEPHFS_FEATURE_ALTERNATE_NAME, &s->s_features)) + ret = 0; + break; + } + mutex_unlock(&mdsc->mutex); + return ret; +} + +static long ceph_set_encryption_policy(struct file *file, unsigned long arg) +{ + int ret, got = 0; + struct page *page = NULL; + struct inode *inode = file_inode(file); + struct ceph_inode_info *ci = ceph_inode(inode); + + ret = vet_mds_for_fscrypt(file); + if (ret) + return ret; + + /* + * Ensure we hold these caps so that we _know_ that the rstats check + * in the empty_dir check is reliable. + */ + ret = ceph_get_caps(file, CEPH_CAP_FILE_SHARED, 0, -1, &got, &page); + if (ret) + return ret; + if (page) + put_page(page); + ret = fscrypt_ioctl_set_policy(file, (const void __user *)arg); + if (got) + ceph_put_cap_refs(ci, got); + return ret; +} + long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + int ret; + struct ceph_inode_info *ci = ceph_inode(file_inode(file)); + dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg); switch (cmd) { case CEPH_IOC_GET_LAYOUT: @@ -289,6 +338,51 @@ long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case CEPH_IOC_SYNCIO: return ceph_ioctl_syncio(file); + + case FS_IOC_SET_ENCRYPTION_POLICY: + return ceph_set_encryption_policy(file, arg); + + case FS_IOC_GET_ENCRYPTION_POLICY: + ret = vet_mds_for_fscrypt(file); + if (ret) + return ret; + return fscrypt_ioctl_get_policy(file, (void __user *)arg); + + case FS_IOC_GET_ENCRYPTION_POLICY_EX: + ret = vet_mds_for_fscrypt(file); + if (ret) + return ret; + return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg); + + case FS_IOC_ADD_ENCRYPTION_KEY: + ret = vet_mds_for_fscrypt(file); + if (ret) + return ret; + atomic_inc(&ci->i_shared_gen); + ceph_dir_clear_ordered(file_inode(file)); + ceph_dir_clear_complete(file_inode(file)); + return fscrypt_ioctl_add_key(file, (void __user *)arg); + + case FS_IOC_REMOVE_ENCRYPTION_KEY: + atomic_inc(&ci->i_shared_gen); + ceph_dir_clear_ordered(file_inode(file)); + ceph_dir_clear_complete(file_inode(file)); + return fscrypt_ioctl_remove_key(file, (void __user *)arg); + + case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: + atomic_inc(&ci->i_shared_gen); + ceph_dir_clear_ordered(file_inode(file)); + ceph_dir_clear_complete(file_inode(file)); + return fscrypt_ioctl_remove_key_all_users(file, (void __user *)arg); + + case FS_IOC_GET_ENCRYPTION_KEY_STATUS: + return fscrypt_ioctl_get_key_status(file, (void __user *)arg); + + case FS_IOC_GET_ENCRYPTION_NONCE: + ret = vet_mds_for_fscrypt(file); + if (ret) + return ret; + return fscrypt_ioctl_get_nonce(file, (void __user *)arg); } return -ENOTTY; From patchwork Wed Mar 31 20:35:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 412919 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1873C43460 for ; Wed, 31 Mar 2021 20:36:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AF2B961057 for ; Wed, 31 Mar 2021 20:36:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236639AbhCaUfy (ORCPT ); Wed, 31 Mar 2021 16:35:54 -0400 Received: from mail.kernel.org ([198.145.29.99]:45336 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236613AbhCaUfX (ORCPT ); Wed, 31 Mar 2021 16:35:23 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 4276861075; Wed, 31 Mar 2021 20:35:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1617222922; bh=BgCOE323QK2JeVx28rknXxKqdm/ImMAtgrDBpemL8no=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WF9CCTP8J+73gVrlFLHMitELvkY3yVfYU9mBXUzK+WTZGz78JJuJCcGZTzU3QCfDY 2EaDBEoA61zPwD6KI8rup0RpAa7WhrmgnVqRTe62jdBdamVVydzHyvKito21TI9nPb I6JJVNVmUdv5yjfUXya0h+9iZyOvZE1HcUdgFca88DrmcWlu9de70TKQN24g4dsrrS 4aNirMuOcLzeXU+rVvzRsV7v2Aa3fy+/Zk888az1zxM9dxHA1NVyuk1mIYupqrusXz 5vwyhHfXebmiIRu/RNt5mQvjP9g8w2+htlrK8tKMhFpsgeciV5Vj4gIv51WhLh9Gq/ p7E7q2Fo+YmKA== From: Jeff Layton To: ceph-devel@vger.kernel.org Cc: linux-fscrypt@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v5 20/19] ceph: make ceph_get_name decrypt filenames Date: Wed, 31 Mar 2021 16:35:20 -0400 Message-Id: <20210331203520.65916-1-jlayton@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210326173227.96363-1-jlayton@kernel.org> References: <20210326173227.96363-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org When we do a lookupino to the MDS, we get a filename in the trace. ceph_get_name uses that name directly, so we must properly decrypt it before copying it to the name buffer. Signed-off-by: Jeff Layton --- fs/ceph/export.c | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) This patch is what's needed to fix the "busy inodes after umount" issue I was seeing with xfstest generic/477, and also makes that test pass reliably with mounts using -o test_dummy_encryption. diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 17d8c8f4ec89..f4e3a17ffc01 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -7,6 +7,7 @@ #include "super.h" #include "mds_client.h" +#include "crypto.h" /* * Basic fh @@ -516,7 +517,9 @@ static int ceph_get_name(struct dentry *parent, char *name, { struct ceph_mds_client *mdsc; struct ceph_mds_request *req; + struct inode *dir = d_inode(parent); struct inode *inode = d_inode(child); + struct ceph_mds_reply_info_parsed *rinfo; int err; if (ceph_snap(inode) != CEPH_NOSNAP) @@ -528,29 +531,46 @@ static int ceph_get_name(struct dentry *parent, char *name, if (IS_ERR(req)) return PTR_ERR(req); - inode_lock(d_inode(parent)); - + inode_lock(dir); req->r_inode = inode; ihold(inode); req->r_ino2 = ceph_vino(d_inode(parent)); - req->r_parent = d_inode(parent); + req->r_parent = dir; set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); + inode_unlock(dir); - inode_unlock(d_inode(parent)); + if (err) + goto out; - if (!err) { - struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info; + rinfo = &req->r_reply_info; + if (!IS_ENCRYPTED(dir)) { memcpy(name, rinfo->dname, rinfo->dname_len); name[rinfo->dname_len] = 0; - dout("get_name %p ino %llx.%llx name %s\n", - child, ceph_vinop(inode), name); } else { - dout("get_name %p ino %llx.%llx err %d\n", - child, ceph_vinop(inode), err); - } + struct fscrypt_str oname = FSTR_INIT(NULL, 0); + struct ceph_fname fname = { .dir = dir, + .name = rinfo->dname, + .ctext = rinfo->altname, + .name_len = rinfo->dname_len, + .ctext_len = rinfo->altname_len }; + + err = ceph_fname_alloc_buffer(dir, &oname); + if (err < 0) + goto out; + err = ceph_fname_to_usr(&fname, NULL, &oname, NULL); + if (!err) { + memcpy(name, oname.name, oname.len); + name[oname.len] = 0; + } + ceph_fname_free_buffer(dir, &oname); + } +out: + dout("get_name %p ino %llx.%llx err %d %s%s\n", + child, ceph_vinop(inode), err, + err ? "" : "name ", err ? "" : name); ceph_mdsc_put_request(req); return err; }