Message ID | 20200914191707.380444-11-jlayton@kernel.org (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Series | ceph+fscrypt: context, filename and symlink support | expand |
On Mon, Sep 14, 2020 at 03:17:01PM -0400, Jeff Layton wrote: > diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h > index b5f38ee80553..c1b6ec4b2961 100644 > --- a/fs/ceph/crypto.h > +++ b/fs/ceph/crypto.h > @@ -11,6 +11,8 @@ > #define CEPH_XATTR_NAME_ENCRYPTION_CONTEXT "encryption.ctx" > > void ceph_fscrypt_set_ops(struct super_block *sb); > +int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, > + struct ceph_acl_sec_ctx *as); > > #else /* CONFIG_FS_ENCRYPTION */ > > @@ -19,6 +21,12 @@ static inline int ceph_fscrypt_set_ops(struct super_block *sb) > return 0; > } > > +static inline int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, > + struct ceph_acl_sec_ctx *as) > +{ > + return 0; > +} > + > #endif /* CONFIG_FS_ENCRYPTION */ Seems there should at least be something that prevents you from creating a file in an encrypted directory when !CONFIG_FS_ENCRYPTION. The other filesystems use fscrypt_prepare_new_inode() for this; it returns EOPNOTSUPP when IS_ENCRYPTED(dir). - Eric
On Mon, 2020-09-14 at 18:37 -0700, Eric Biggers wrote: > On Mon, Sep 14, 2020 at 03:17:01PM -0400, Jeff Layton wrote: > > diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h > > index b5f38ee80553..c1b6ec4b2961 100644 > > --- a/fs/ceph/crypto.h > > +++ b/fs/ceph/crypto.h > > @@ -11,6 +11,8 @@ > > #define CEPH_XATTR_NAME_ENCRYPTION_CONTEXT "encryption.ctx" > > > > void ceph_fscrypt_set_ops(struct super_block *sb); > > +int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, > > + struct ceph_acl_sec_ctx *as); > > > > #else /* CONFIG_FS_ENCRYPTION */ > > > > @@ -19,6 +21,12 @@ static inline int ceph_fscrypt_set_ops(struct super_block *sb) > > return 0; > > } > > > > +static inline int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, > > + struct ceph_acl_sec_ctx *as) > > +{ > > + return 0; > > +} > > + > > #endif /* CONFIG_FS_ENCRYPTION */ > > Seems there should at least be something that prevents you from creating a file > in an encrypted directory when !CONFIG_FS_ENCRYPTION. > > The other filesystems use fscrypt_prepare_new_inode() for this; it returns > EOPNOTSUPP when IS_ENCRYPTED(dir). > Once we have the MDS support done, we should be able to make it reject create requests from clients that don't support the new feature flag, but denying it on the client is more efficient. Fixed in my tree. Thanks!
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 b5f38ee80553..c1b6ec4b2961 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h @@ -11,6 +11,8 @@ #define CEPH_XATTR_NAME_ENCRYPTION_CONTEXT "encryption.ctx" void ceph_fscrypt_set_ops(struct super_block *sb); +int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, + struct ceph_acl_sec_ctx *as); #else /* CONFIG_FS_ENCRYPTION */ @@ -19,6 +21,12 @@ static inline int ceph_fscrypt_set_ops(struct super_block *sb) return 0; } +static inline int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, + struct ceph_acl_sec_ctx *as) +{ + return 0; +} + #endif /* CONFIG_FS_ENCRYPTION */ #endif diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index f50e7873bf6e..2fda08518312 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -18,6 +18,7 @@ #include "super.h" #include "mds_client.h" #include "cache.h" +#include "crypto.h" #include <linux/ceph/decode.h> /* @@ -73,12 +74,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 c05ed00035ec..5d5283552c03 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -1003,6 +1003,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; };
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. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/crypto.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/ceph/crypto.h | 8 +++++++ fs/ceph/inode.c | 10 ++++++-- fs/ceph/super.h | 3 +++ 4 files changed, 80 insertions(+), 2 deletions(-)