Commit dfe70581 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-4.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs

Pull f2fs/fscrypto fixes from Jaegeuk Kim:
 "In addition to f2fs/fscrypto fixes, I've added one patch which
  prevents RCU mode lookup in d_revalidate, as Al mentioned.

  These patches fix f2fs and fscrypto based on -rc3 bug fixes in ext4
  crypto, which have not yet been fully propagated as follows.

   - use of dget_parent and file_dentry to avoid crashes
   - disallow RCU-mode lookup in d_invalidate
   - disallow -ENOMEM in the core data encryption path"

* tag 'for-linus-4.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  ext4/fscrypto: avoid RCU lookup in d_revalidate
  fscrypto: don't let data integrity writebacks fail with ENOMEM
  f2fs: use dget_parent and file_dentry in f2fs_file_open
  fscrypto: use dget_parent() in fscrypt_d_revalidate()
parents 16382ed9 03a8bb0e
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/fscrypto.h> #include <linux/fscrypto.h>
#include <linux/ecryptfs.h> #include <linux/ecryptfs.h>
...@@ -81,13 +82,14 @@ EXPORT_SYMBOL(fscrypt_release_ctx); ...@@ -81,13 +82,14 @@ EXPORT_SYMBOL(fscrypt_release_ctx);
/** /**
* fscrypt_get_ctx() - Gets an encryption context * fscrypt_get_ctx() - Gets an encryption context
* @inode: The inode for which we are doing the crypto * @inode: The inode for which we are doing the crypto
* @gfp_flags: The gfp flag for memory allocation
* *
* Allocates and initializes an encryption context. * Allocates and initializes an encryption context.
* *
* Return: An allocated and initialized encryption context on success; error * Return: An allocated and initialized encryption context on success; error
* value or NULL otherwise. * 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_ctx *ctx = NULL;
struct fscrypt_info *ci = inode->i_crypt_info; struct fscrypt_info *ci = inode->i_crypt_info;
...@@ -113,7 +115,7 @@ struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode) ...@@ -113,7 +115,7 @@ struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode)
list_del(&ctx->free_list); list_del(&ctx->free_list);
spin_unlock_irqrestore(&fscrypt_ctx_lock, flags); spin_unlock_irqrestore(&fscrypt_ctx_lock, flags);
if (!ctx) { if (!ctx) {
ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, GFP_NOFS); ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, gfp_flags);
if (!ctx) if (!ctx)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ctx->flags |= FS_CTX_REQUIRES_FREE_ENCRYPT_FL; ctx->flags |= FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
...@@ -147,7 +149,8 @@ typedef enum { ...@@ -147,7 +149,8 @@ typedef enum {
static int do_page_crypto(struct inode *inode, static int do_page_crypto(struct inode *inode,
fscrypt_direction_t rw, pgoff_t index, 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]; u8 xts_tweak[FS_XTS_TWEAK_SIZE];
struct skcipher_request *req = NULL; struct skcipher_request *req = NULL;
...@@ -157,7 +160,7 @@ static int do_page_crypto(struct inode *inode, ...@@ -157,7 +160,7 @@ static int do_page_crypto(struct inode *inode,
struct crypto_skcipher *tfm = ci->ci_ctfm; struct crypto_skcipher *tfm = ci->ci_ctfm;
int res = 0; int res = 0;
req = skcipher_request_alloc(tfm, GFP_NOFS); req = skcipher_request_alloc(tfm, gfp_flags);
if (!req) { if (!req) {
printk_ratelimited(KERN_ERR printk_ratelimited(KERN_ERR
"%s: crypto_request_alloc() failed\n", "%s: crypto_request_alloc() failed\n",
...@@ -199,10 +202,9 @@ static int do_page_crypto(struct inode *inode, ...@@ -199,10 +202,9 @@ static int do_page_crypto(struct inode *inode,
return 0; 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, ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
GFP_NOWAIT);
if (ctx->w.bounce_page == NULL) if (ctx->w.bounce_page == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ctx->flags |= FS_WRITE_PATH_FL; ctx->flags |= FS_WRITE_PATH_FL;
...@@ -213,6 +215,7 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx) ...@@ -213,6 +215,7 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx)
* fscypt_encrypt_page() - Encrypts a page * fscypt_encrypt_page() - Encrypts a page
* @inode: The inode for which the encryption should take place * @inode: The inode for which the encryption should take place
* @plaintext_page: The page to encrypt. Must be locked. * @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 * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx
* encryption context. * encryption context.
...@@ -225,7 +228,7 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx) ...@@ -225,7 +228,7 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx)
* error value or NULL. * error value or NULL.
*/ */
struct page *fscrypt_encrypt_page(struct inode *inode, 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 fscrypt_ctx *ctx;
struct page *ciphertext_page = NULL; struct page *ciphertext_page = NULL;
...@@ -233,18 +236,19 @@ struct page *fscrypt_encrypt_page(struct inode *inode, ...@@ -233,18 +236,19 @@ struct page *fscrypt_encrypt_page(struct inode *inode,
BUG_ON(!PageLocked(plaintext_page)); BUG_ON(!PageLocked(plaintext_page));
ctx = fscrypt_get_ctx(inode); ctx = fscrypt_get_ctx(inode, gfp_flags);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return (struct page *)ctx; return (struct page *)ctx;
/* The encryption operation will require a bounce page. */ /* 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)) if (IS_ERR(ciphertext_page))
goto errout; goto errout;
ctx->w.control_page = plaintext_page; ctx->w.control_page = plaintext_page;
err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index, err = do_page_crypto(inode, FS_ENCRYPT, plaintext_page->index,
plaintext_page, ciphertext_page); plaintext_page, ciphertext_page,
gfp_flags);
if (err) { if (err) {
ciphertext_page = ERR_PTR(err); ciphertext_page = ERR_PTR(err);
goto errout; goto errout;
...@@ -275,7 +279,7 @@ int fscrypt_decrypt_page(struct page *page) ...@@ -275,7 +279,7 @@ int fscrypt_decrypt_page(struct page *page)
BUG_ON(!PageLocked(page)); BUG_ON(!PageLocked(page));
return do_page_crypto(page->mapping->host, 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); EXPORT_SYMBOL(fscrypt_decrypt_page);
...@@ -289,11 +293,11 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, ...@@ -289,11 +293,11 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk,
BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); 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)) if (IS_ERR(ctx))
return PTR_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)) { if (IS_ERR(ciphertext_page)) {
err = PTR_ERR(ciphertext_page); err = PTR_ERR(ciphertext_page);
goto errout; goto errout;
...@@ -301,11 +305,12 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, ...@@ -301,11 +305,12 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk,
while (len--) { while (len--) {
err = do_page_crypto(inode, FS_ENCRYPT, lblk, err = do_page_crypto(inode, FS_ENCRYPT, lblk,
ZERO_PAGE(0), ciphertext_page); ZERO_PAGE(0), ciphertext_page,
GFP_NOFS);
if (err) if (err)
goto errout; goto errout;
bio = bio_alloc(GFP_KERNEL, 1); bio = bio_alloc(GFP_NOWAIT, 1);
if (!bio) { if (!bio) {
err = -ENOMEM; err = -ENOMEM;
goto errout; goto errout;
...@@ -345,13 +350,20 @@ EXPORT_SYMBOL(fscrypt_zeroout_range); ...@@ -345,13 +350,20 @@ EXPORT_SYMBOL(fscrypt_zeroout_range);
*/ */
static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
{ {
struct inode *dir = d_inode(dentry->d_parent); struct dentry *dir;
struct fscrypt_info *ci = dir->i_crypt_info; struct fscrypt_info *ci;
int dir_has_key, cached_with_key; int dir_has_key, cached_with_key;
if (!dir->i_sb->s_cop->is_encrypted(dir)) 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);
return 0; return 0;
}
ci = d_inode(dir)->i_crypt_info;
if (ci && ci->ci_keyring_key && if (ci && ci->ci_keyring_key &&
(ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
(1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_REVOKED) |
...@@ -363,6 +375,7 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -363,6 +375,7 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY; cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
dir_has_key = (ci != NULL); dir_has_key = (ci != NULL);
dput(dir);
/* /*
* If the dentry was cached without the key, and it is a * If the dentry was cached without the key, and it is a
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/spinlock_types.h> #include <linux/spinlock_types.h>
#include <linux/namei.h>
#include "ext4_extents.h" #include "ext4_extents.h"
#include "xattr.h" #include "xattr.h"
...@@ -482,6 +483,9 @@ static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -482,6 +483,9 @@ static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags)
struct ext4_crypt_info *ci; struct ext4_crypt_info *ci;
int dir_has_key, cached_with_key; int dir_has_key, cached_with_key;
if (flags & LOOKUP_RCU)
return -ECHILD;
dir = dget_parent(dentry); dir = dget_parent(dentry);
if (!ext4_encrypted_inode(d_inode(dir))) { if (!ext4_encrypted_inode(d_inode(dir))) {
dput(dir); dput(dir);
......
...@@ -992,7 +992,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping, ...@@ -992,7 +992,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
if (f2fs_encrypted_inode(inode) && if (f2fs_encrypted_inode(inode) &&
S_ISREG(inode->i_mode)) { S_ISREG(inode->i_mode)) {
ctx = fscrypt_get_ctx(inode); ctx = fscrypt_get_ctx(inode, GFP_NOFS);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
goto set_error_page; goto set_error_page;
...@@ -1092,14 +1092,24 @@ int do_write_data_page(struct f2fs_io_info *fio) ...@@ -1092,14 +1092,24 @@ int do_write_data_page(struct f2fs_io_info *fio)
} }
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
gfp_t gfp_flags = GFP_NOFS;
/* wait for GCed encrypted page writeback */ /* wait for GCed encrypted page writeback */
f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode), f2fs_wait_on_encrypted_page_writeback(F2FS_I_SB(inode),
fio->old_blkaddr); fio->old_blkaddr);
retry_encrypt:
fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page); fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
gfp_flags);
if (IS_ERR(fio->encrypted_page)) { if (IS_ERR(fio->encrypted_page)) {
err = PTR_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; goto out_writepage;
} }
} }
......
...@@ -441,7 +441,7 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -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) static int f2fs_file_open(struct inode *inode, struct file *filp)
{ {
int ret = generic_file_open(inode, 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)) { if (!ret && f2fs_encrypted_inode(inode)) {
ret = fscrypt_get_encryption_info(inode); ret = fscrypt_get_encryption_info(inode);
...@@ -450,9 +450,13 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) ...@@ -450,9 +450,13 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)
if (!fscrypt_has_encryption_key(inode)) if (!fscrypt_has_encryption_key(inode))
return -ENOKEY; return -ENOKEY;
} }
if (f2fs_encrypted_inode(dir) && dir = dget_parent(file_dentry(filp));
!fscrypt_has_permitted_context(dir, inode)) if (f2fs_encrypted_inode(d_inode(dir)) &&
!fscrypt_has_permitted_context(d_inode(dir), inode)) {
dput(dir);
return -EPERM; return -EPERM;
}
dput(dir);
return ret; return ret;
} }
......
...@@ -263,9 +263,9 @@ static inline void fscrypt_set_d_op(struct dentry *dentry) ...@@ -263,9 +263,9 @@ static inline void fscrypt_set_d_op(struct dentry *dentry)
extern struct kmem_cache *fscrypt_info_cachep; extern struct kmem_cache *fscrypt_info_cachep;
int fscrypt_initialize(void); 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 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 int fscrypt_decrypt_page(struct page *);
extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
extern void fscrypt_pullback_bio_page(struct page **, bool); 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 *, ...@@ -299,7 +299,8 @@ extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
#endif #endif
/* crypto.c */ /* 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); return ERR_PTR(-EOPNOTSUPP);
} }
...@@ -310,7 +311,7 @@ static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c) ...@@ -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, static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i,
struct page *p) struct page *p, gfp_t f)
{ {
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment