* [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate()
@ 2016-04-12 17:27 Jaegeuk Kim
2016-04-12 17:27 ` [PATCH 2/3] f2fs: use dget_parent and file_dentry in f2fs_file_open Jaegeuk Kim
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Jaegeuk Kim @ 2016-04-12 17:27 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel
Cc: Jaegeuk Kim, Theodore Ts'o
This patch updates fscrypto along with the below ext4 crypto change.
Fixes: 3d43bcfef5f0 ("ext4 crypto: use dget_parent() in ext4_d_revalidate()")
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/crypto/crypto.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 7f58045..58ae0ba 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -345,13 +345,17 @@ EXPORT_SYMBOL(fscrypt_zeroout_range);
*/
static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
{
- struct inode *dir = d_inode(dentry->d_parent);
- struct fscrypt_info *ci = dir->i_crypt_info;
+ struct dentry *dir;
+ struct fscrypt_info *ci;
int dir_has_key, cached_with_key;
- if (!dir->i_sb->s_cop->is_encrypted(dir))
+ dir = dget_parent(dentry);
+ if (!d_inode(dir)->i_sb->s_cop->is_encrypted(d_inode(dir))) {
+ dput(dir);
return 0;
+ }
+ ci = d_inode(dir)->i_crypt_info;
if (ci && ci->ci_keyring_key &&
(ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
(1 << KEY_FLAG_REVOKED) |
@@ -363,6 +367,7 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
spin_unlock(&dentry->d_lock);
dir_has_key = (ci != NULL);
+ dput(dir);
/*
* If the dentry was cached without the key, and it is a
--
2.6.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/3] f2fs: use dget_parent and file_dentry in f2fs_file_open 2016-04-12 17:27 [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Jaegeuk Kim @ 2016-04-12 17:27 ` Jaegeuk Kim 2016-04-12 17:27 ` [PATCH 3/3] fscrypto: don't let data integrity writebacks fail with ENOMEM Jaegeuk Kim 2016-04-12 22:33 ` [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Al Viro 2 siblings, 0 replies; 5+ messages in thread From: Jaegeuk Kim @ 2016-04-12 17:27 UTC (permalink / raw) To: linux-kernel, linux-fsdevel, linux-f2fs-devel Cc: Jaegeuk Kim, Miklos Szeredi, Theodore Ts'o This patch synced with the below two ext4 crypto fixes together. In 4.6-rc1, f2fs newly introduced accessing f_path.dentry which crashes overlayfs. To fix, now we need to use file_dentry() to access that field. Fixes: c0a37d487884 ("ext4: use file_dentry()") Fixes: 9dd78d8c9a7b ("ext4: use dget_parent() in ext4_file_open()") Cc: Miklos Szeredi <mszeredi@redhat.com> Cc: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> --- fs/f2fs/file.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 443e077..90d1157 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -441,7 +441,7 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) static int f2fs_file_open(struct inode *inode, struct file *filp) { int ret = generic_file_open(inode, filp); - struct inode *dir = filp->f_path.dentry->d_parent->d_inode; + struct dentry *dir; if (!ret && f2fs_encrypted_inode(inode)) { ret = fscrypt_get_encryption_info(inode); @@ -450,9 +450,13 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) if (!fscrypt_has_encryption_key(inode)) return -ENOKEY; } - if (f2fs_encrypted_inode(dir) && - !fscrypt_has_permitted_context(dir, inode)) + dir = dget_parent(file_dentry(filp)); + if (f2fs_encrypted_inode(d_inode(dir)) && + !fscrypt_has_permitted_context(d_inode(dir), inode)) { + dput(dir); return -EPERM; + } + dput(dir); return ret; } -- 2.6.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] fscrypto: don't let data integrity writebacks fail with ENOMEM 2016-04-12 17:27 [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Jaegeuk Kim 2016-04-12 17:27 ` [PATCH 2/3] f2fs: use dget_parent and file_dentry in f2fs_file_open Jaegeuk Kim @ 2016-04-12 17:27 ` Jaegeuk Kim 2016-04-12 22:33 ` [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Al Viro 2 siblings, 0 replies; 5+ messages in thread From: Jaegeuk Kim @ 2016-04-12 17:27 UTC (permalink / raw) To: linux-kernel, linux-fsdevel, linux-f2fs-devel Cc: Jaegeuk Kim, Theodore Ts'o This patch fixes the issue introduced by the ext4 crypto fix in a same manner. For F2FS, however, we flush the pending IOs and wait for a while to acquire free memory. Fixes: c9af28fdd4492 ("ext4 crypto: don't let data integrity writebacks fail with ENOMEM") Cc: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> --- fs/crypto/crypto.c | 36 ++++++++++++++++++++---------------- fs/f2fs/data.c | 16 +++++++++++++--- include/linux/fscrypto.h | 9 +++++---- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 58ae0ba..da70520 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -81,13 +81,14 @@ EXPORT_SYMBOL(fscrypt_release_ctx); /** * fscrypt_get_ctx() - Gets an encryption context * @inode: The inode for which we are doing the crypto + * @gfp_flags: The gfp flag for memory allocation * * Allocates and initializes an encryption context. * * Return: An allocated and initialized encryption context on success; error * value or NULL otherwise. */ -struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode) +struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags) { struct fscrypt_ctx *ctx = NULL; struct fscrypt_info *ci = inode->i_crypt_info; @@ -113,7 +114,7 @@ struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode) list_del(&ctx->free_list); spin_unlock_irqrestore(&fscrypt_ctx_lock, flags); if (!ctx) { - ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, GFP_NOFS); + ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, gfp_flags); if (!ctx) return ERR_PTR(-ENOMEM); ctx->flags |= FS_CTX_REQUIRES_FREE_ENCRYPT_FL; @@ -147,7 +148,8 @@ typedef enum { static int do_page_crypto(struct inode *inode, fscrypt_direction_t rw, pgoff_t index, - struct page *src_page, struct page *dest_page) + struct page *src_page, struct page *dest_page, + gfp_t gfp_flags) { u8 xts_tweak[FS_XTS_TWEAK_SIZE]; struct skcipher_request *req = NULL; @@ -157,7 +159,7 @@ static int do_page_crypto(struct inode *inode, struct crypto_skcipher *tfm = ci->ci_ctfm; int res = 0; - req = skcipher_request_alloc(tfm, GFP_NOFS); + req = skcipher_request_alloc(tfm, gfp_flags); if (!req) { printk_ratelimited(KERN_ERR "%s: crypto_request_alloc() failed\n", @@ -199,10 +201,9 @@ static int do_page_crypto(struct inode *inode, return 0; } -static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx) +static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags) { - ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, - GFP_NOWAIT); + ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags); if (ctx->w.bounce_page == NULL) return ERR_PTR(-ENOMEM); ctx->flags |= FS_WRITE_PATH_FL; @@ -213,6 +214,7 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx) * fscypt_encrypt_page() - Encrypts a page * @inode: The inode for which the encryption should take place * @plaintext_page: The page to encrypt. Must be locked. + * @gfp_flags: The gfp flag for memory allocation * * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx * encryption context. @@ -225,7 +227,7 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx) * error value or NULL. */ struct page *fscrypt_encrypt_page(struct inode *inode, - struct page *plaintext_page) + struct page *plaintext_page, gfp_t gfp_flags) { struct fscrypt_ctx *ctx; struct page *ciphertext_page = NULL; @@ -233,18 +235,19 @@ struct page *fscrypt_encrypt_page(struct inode *inode, BUG_ON(!PageLocked(plaintext_page)); - ctx = fscrypt_get_ctx(inode); + ctx = fscrypt_get_ctx(inode, gfp_flags); if (IS_ERR(ctx)) return (struct page *)ctx; /* The encryption operation will require a bounce page. */ - ciphertext_page = alloc_bounce_page(ctx); + ciphertext_page = alloc_bounce_page(ctx, gfp_flags); if (IS_ERR(ciphertext_page)) goto errout; ctx->w.control_page = plaintext_page; err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index, - plaintext_page, ciphertext_page); + plaintext_page, ciphertext_page, + gfp_flags); if (err) { ciphertext_page = ERR_PTR(err); goto errout; @@ -275,7 +278,7 @@ int fscrypt_decrypt_page(struct page *page) BUG_ON(!PageLocked(page)); return do_page_crypto(page->mapping->host, - FS_DECRYPT, page->index, page, page); + FS_DECRYPT, page->index, page, page, GFP_NOFS); } EXPORT_SYMBOL(fscrypt_decrypt_page); @@ -289,11 +292,11 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); - ctx = fscrypt_get_ctx(inode); + ctx = fscrypt_get_ctx(inode, GFP_NOFS); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ciphertext_page = alloc_bounce_page(ctx); + ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT); if (IS_ERR(ciphertext_page)) { err = PTR_ERR(ciphertext_page); goto errout; @@ -301,11 +304,12 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, while (len--) { err = do_page_crypto(inode, FS_ENCRYPT, lblk, - ZERO_PAGE(0), ciphertext_page); + ZERO_PAGE(0), ciphertext_page, + GFP_NOFS); if (err) goto errout; - bio = bio_alloc(GFP_KERNEL, 1); + bio = bio_alloc(GFP_NOWAIT, 1); if (!bio) { err = -ENOMEM; goto errout; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 53fec08..5dafb9c 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -992,7 +992,7 @@ submit_and_realloc: if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { - ctx = fscrypt_get_ctx(inode); + ctx = fscrypt_get_ctx(inode, GFP_NOFS); if (IS_ERR(ctx)) goto set_error_page; @@ -1092,14 +1092,24 @@ int do_write_data_page(struct f2fs_io_info *fio) } if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { + gfp_t gfp_flags = GFP_NOFS; /* wait for GCed encrypted page writeback */ f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode), fio->old_blkaddr); - - fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page); +retry_encrypt: + fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, + gfp_flags); if (IS_ERR(fio->encrypted_page)) { err = PTR_ERR(fio->encrypted_page); + if (err == -ENOMEM) { + /* flush pending ios and wait for a while */ + f2fs_flush_merged_bios(F2FS_I_SB(inode)); + congestion_wait(BLK_RW_ASYNC, HZ/50); + gfp_flags |= __GFP_NOFAIL; + err = 0; + goto retry_encrypt; + } goto out_writepage; } } diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index cd91f75..6027f6b 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h @@ -263,9 +263,9 @@ static inline void fscrypt_set_d_op(struct dentry *dentry) extern struct kmem_cache *fscrypt_info_cachep; int fscrypt_initialize(void); -extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *); +extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); -extern struct page *fscrypt_encrypt_page(struct inode *, struct page *); +extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, gfp_t); extern int fscrypt_decrypt_page(struct page *); extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); extern void fscrypt_pullback_bio_page(struct page **, bool); @@ -299,7 +299,8 @@ extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, #endif /* crypto.c */ -static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(struct inode *i) +static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(struct inode *i, + gfp_t f) { return ERR_PTR(-EOPNOTSUPP); } @@ -310,7 +311,7 @@ static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c) } static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i, - struct page *p) + struct page *p, gfp_t f) { return ERR_PTR(-EOPNOTSUPP); } -- 2.6.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() 2016-04-12 17:27 [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Jaegeuk Kim 2016-04-12 17:27 ` [PATCH 2/3] f2fs: use dget_parent and file_dentry in f2fs_file_open Jaegeuk Kim 2016-04-12 17:27 ` [PATCH 3/3] fscrypto: don't let data integrity writebacks fail with ENOMEM Jaegeuk Kim @ 2016-04-12 22:33 ` Al Viro 2016-04-12 23:31 ` Jaegeuk Kim 2 siblings, 1 reply; 5+ messages in thread From: Al Viro @ 2016-04-12 22:33 UTC (permalink / raw) To: Jaegeuk Kim Cc: linux-kernel, linux-fsdevel, linux-f2fs-devel, Theodore Ts'o On Tue, Apr 12, 2016 at 10:27:20AM -0700, Jaegeuk Kim wrote: > This patch updates fscrypto along with the below ext4 crypto change. > > Fixes: 3d43bcfef5f0 ("ext4 crypto: use dget_parent() in ext4_d_revalidate()") > static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) > { > - struct inode *dir = d_inode(dentry->d_parent); > - struct fscrypt_info *ci = dir->i_crypt_info; > + struct dentry *dir; > + struct fscrypt_info *ci; > int dir_has_key, cached_with_key; > > - if (!dir->i_sb->s_cop->is_encrypted(dir)) > + dir = dget_parent(dentry); > + if (!d_inode(dir)->i_sb->s_cop->is_encrypted(d_inode(dir))) { > + dput(dir); ... and as soon as you call it from RCU mode, you are screwed. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() 2016-04-12 22:33 ` [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Al Viro @ 2016-04-12 23:31 ` Jaegeuk Kim 0 siblings, 0 replies; 5+ messages in thread From: Jaegeuk Kim @ 2016-04-12 23:31 UTC (permalink / raw) To: Al Viro; +Cc: linux-kernel, linux-fsdevel, linux-f2fs-devel, Theodore Ts'o On Tue, Apr 12, 2016 at 11:33:03PM +0100, Al Viro wrote: > On Tue, Apr 12, 2016 at 10:27:20AM -0700, Jaegeuk Kim wrote: > > This patch updates fscrypto along with the below ext4 crypto change. > > > > Fixes: 3d43bcfef5f0 ("ext4 crypto: use dget_parent() in ext4_d_revalidate()") > > > static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) > > { > > - struct inode *dir = d_inode(dentry->d_parent); > > - struct fscrypt_info *ci = dir->i_crypt_info; > > + struct dentry *dir; > > + struct fscrypt_info *ci; > > int dir_has_key, cached_with_key; > > > > - if (!dir->i_sb->s_cop->is_encrypted(dir)) > > + dir = dget_parent(dentry); > > + if (!d_inode(dir)->i_sb->s_cop->is_encrypted(d_inode(dir))) { > > + dput(dir); > > ... and as soon as you call it from RCU mode, you are screwed. Thank you for pointing this out. IIUC, did you mean this? Thanks, >From a0ac7972189b7c366720a0b456e39516d622a6d4 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim <jaegeuk@kernel.org> Date: Tue, 12 Apr 2016 16:05:36 -0700 Subject: [PATCH] ext4/fscrypto: avoid RCU lookup in d_revalidate As Al pointed, d_revalidate should return RCU lookup before using d_inode. This was originally introduced by: commit 34286d666230 ("fs: rcu-walk aware d_revalidate method"). Reported-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Cc: Theodore Ts'o <tytso@mit.edu> Cc: stable <stable@vger.kernel.org> --- fs/crypto/crypto.c | 4 ++++ fs/ext4/crypto.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index da70520..2fc8c43 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -26,6 +26,7 @@ #include <linux/ratelimit.h> #include <linux/bio.h> #include <linux/dcache.h> +#include <linux/namei.h> #include <linux/fscrypto.h> #include <linux/ecryptfs.h> @@ -353,6 +354,9 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) struct fscrypt_info *ci; int dir_has_key, cached_with_key; + if (flags & LOOKUP_RCU) + return -ECHILD; + dir = dget_parent(dentry); if (!d_inode(dir)->i_sb->s_cop->is_encrypted(d_inode(dir))) { dput(dir); diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index db9ae6e..6a6c273 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -32,6 +32,7 @@ #include <linux/random.h> #include <linux/scatterlist.h> #include <linux/spinlock_types.h> +#include <linux/namei.h> #include "ext4_extents.h" #include "xattr.h" @@ -482,6 +483,9 @@ static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags) struct ext4_crypt_info *ci; int dir_has_key, cached_with_key; + if (flags & LOOKUP_RCU) + return -ECHILD; + dir = dget_parent(dentry); if (!ext4_encrypted_inode(d_inode(dir))) { dput(dir); -- 2.6.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2016-04-12 23:31 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-04-12 17:27 [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Jaegeuk Kim 2016-04-12 17:27 ` [PATCH 2/3] f2fs: use dget_parent and file_dentry in f2fs_file_open Jaegeuk Kim 2016-04-12 17:27 ` [PATCH 3/3] fscrypto: don't let data integrity writebacks fail with ENOMEM Jaegeuk Kim 2016-04-12 22:33 ` [PATCH 1/3] fscrypto: use dget_parent() in fscrypt_d_revalidate() Al Viro 2016-04-12 23:31 ` Jaegeuk Kim
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox