forked from mirrors/linux
		
	ext4 crypto: migrate into vfs's crypto engine
This patch removes the most parts of internal crypto codes. And then, it modifies and adds some ext4-specific crypt codes to use the generic facility. Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
		
							parent
							
								
									ff0031d848
								
							
						
					
					
						commit
						a7550b30ab
					
				
					 19 changed files with 303 additions and 2003 deletions
				
			
		| 
						 | 
					@ -99,17 +99,9 @@ config EXT4_FS_SECURITY
 | 
				
			||||||
	  extended attributes for file security labels, say N.
 | 
						  extended attributes for file security labels, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config EXT4_ENCRYPTION
 | 
					config EXT4_ENCRYPTION
 | 
				
			||||||
	tristate "Ext4 Encryption"
 | 
						bool "Ext4 Encryption"
 | 
				
			||||||
	depends on EXT4_FS
 | 
						depends on EXT4_FS
 | 
				
			||||||
	select CRYPTO_AES
 | 
						select FS_ENCRYPTION
 | 
				
			||||||
	select CRYPTO_CBC
 | 
					 | 
				
			||||||
	select CRYPTO_ECB
 | 
					 | 
				
			||||||
	select CRYPTO_XTS
 | 
					 | 
				
			||||||
	select CRYPTO_CTS
 | 
					 | 
				
			||||||
	select CRYPTO_CTR
 | 
					 | 
				
			||||||
	select CRYPTO_SHA256
 | 
					 | 
				
			||||||
	select KEYS
 | 
					 | 
				
			||||||
	select ENCRYPTED_KEYS
 | 
					 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Enable encryption of ext4 files and directories.  This
 | 
						  Enable encryption of ext4 files and directories.  This
 | 
				
			||||||
	  feature is similar to ecryptfs, but it is more memory
 | 
						  feature is similar to ecryptfs, but it is more memory
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,5 +12,3 @@ ext4-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ext4-$(CONFIG_EXT4_FS_POSIX_ACL)	+= acl.o
 | 
					ext4-$(CONFIG_EXT4_FS_POSIX_ACL)	+= acl.o
 | 
				
			||||||
ext4-$(CONFIG_EXT4_FS_SECURITY)		+= xattr_security.o
 | 
					ext4-$(CONFIG_EXT4_FS_SECURITY)		+= xattr_security.o
 | 
				
			||||||
ext4-$(CONFIG_EXT4_FS_ENCRYPTION)	+= crypto_policy.o crypto.o \
 | 
					 | 
				
			||||||
		crypto_key.o crypto_fname.o
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										536
									
								
								fs/ext4/crypto.c
									
									
									
									
									
								
							
							
						
						
									
										536
									
								
								fs/ext4/crypto.c
									
									
									
									
									
								
							| 
						 | 
					@ -1,536 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * linux/fs/ext4/crypto.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2015, Google, Inc.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This contains encryption functions for ext4
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Written by Michael Halcrow, 2014.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Filename encryption additions
 | 
					 | 
				
			||||||
 *	Uday Savagaonkar, 2014
 | 
					 | 
				
			||||||
 * Encryption policy handling additions
 | 
					 | 
				
			||||||
 *	Ildar Muslukhov, 2014
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This has not yet undergone a rigorous security audit.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The usage of AES-XTS should conform to recommendations in NIST
 | 
					 | 
				
			||||||
 * Special Publication 800-38E and IEEE P1619/D16.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <crypto/skcipher.h>
 | 
					 | 
				
			||||||
#include <keys/user-type.h>
 | 
					 | 
				
			||||||
#include <keys/encrypted-type.h>
 | 
					 | 
				
			||||||
#include <linux/ecryptfs.h>
 | 
					 | 
				
			||||||
#include <linux/gfp.h>
 | 
					 | 
				
			||||||
#include <linux/kernel.h>
 | 
					 | 
				
			||||||
#include <linux/key.h>
 | 
					 | 
				
			||||||
#include <linux/list.h>
 | 
					 | 
				
			||||||
#include <linux/mempool.h>
 | 
					 | 
				
			||||||
#include <linux/module.h>
 | 
					 | 
				
			||||||
#include <linux/mutex.h>
 | 
					 | 
				
			||||||
#include <linux/random.h>
 | 
					 | 
				
			||||||
#include <linux/scatterlist.h>
 | 
					 | 
				
			||||||
#include <linux/spinlock_types.h>
 | 
					 | 
				
			||||||
#include <linux/namei.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ext4_extents.h"
 | 
					 | 
				
			||||||
#include "xattr.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Encryption added and removed here! (L: */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned int num_prealloc_crypto_pages = 32;
 | 
					 | 
				
			||||||
static unsigned int num_prealloc_crypto_ctxs = 128;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module_param(num_prealloc_crypto_pages, uint, 0444);
 | 
					 | 
				
			||||||
MODULE_PARM_DESC(num_prealloc_crypto_pages,
 | 
					 | 
				
			||||||
		 "Number of crypto pages to preallocate");
 | 
					 | 
				
			||||||
module_param(num_prealloc_crypto_ctxs, uint, 0444);
 | 
					 | 
				
			||||||
MODULE_PARM_DESC(num_prealloc_crypto_ctxs,
 | 
					 | 
				
			||||||
		 "Number of crypto contexts to preallocate");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static mempool_t *ext4_bounce_page_pool;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static LIST_HEAD(ext4_free_crypto_ctxs);
 | 
					 | 
				
			||||||
static DEFINE_SPINLOCK(ext4_crypto_ctx_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct kmem_cache *ext4_crypto_ctx_cachep;
 | 
					 | 
				
			||||||
struct kmem_cache *ext4_crypt_info_cachep;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_release_crypto_ctx() - Releases an encryption context
 | 
					 | 
				
			||||||
 * @ctx: The encryption context to release.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * If the encryption context was allocated from the pre-allocated pool, returns
 | 
					 | 
				
			||||||
 * it to that pool. Else, frees it.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * If there's a bounce page in the context, this frees that.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long flags;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ctx->flags & EXT4_WRITE_PATH_FL && ctx->w.bounce_page)
 | 
					 | 
				
			||||||
		mempool_free(ctx->w.bounce_page, ext4_bounce_page_pool);
 | 
					 | 
				
			||||||
	ctx->w.bounce_page = NULL;
 | 
					 | 
				
			||||||
	ctx->w.control_page = NULL;
 | 
					 | 
				
			||||||
	if (ctx->flags & EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL) {
 | 
					 | 
				
			||||||
		kmem_cache_free(ext4_crypto_ctx_cachep, ctx);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		spin_lock_irqsave(&ext4_crypto_ctx_lock, flags);
 | 
					 | 
				
			||||||
		list_add(&ctx->free_list, &ext4_free_crypto_ctxs);
 | 
					 | 
				
			||||||
		spin_unlock_irqrestore(&ext4_crypto_ctx_lock, flags);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_get_crypto_ctx() - Gets an encryption context
 | 
					 | 
				
			||||||
 * @inode:       The inode for which we are doing the crypto
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Allocates and initializes an encryption context.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: An allocated and initialized encryption context on success; error
 | 
					 | 
				
			||||||
 * value or NULL otherwise.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
 | 
					 | 
				
			||||||
					    gfp_t gfp_flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypto_ctx *ctx = NULL;
 | 
					 | 
				
			||||||
	int res = 0;
 | 
					 | 
				
			||||||
	unsigned long flags;
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ci == NULL)
 | 
					 | 
				
			||||||
		return ERR_PTR(-ENOKEY);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * We first try getting the ctx from a free list because in
 | 
					 | 
				
			||||||
	 * the common case the ctx will have an allocated and
 | 
					 | 
				
			||||||
	 * initialized crypto tfm, so it's probably a worthwhile
 | 
					 | 
				
			||||||
	 * optimization. For the bounce page, we first try getting it
 | 
					 | 
				
			||||||
	 * from the kernel allocator because that's just about as fast
 | 
					 | 
				
			||||||
	 * as getting it from a list and because a cache of free pages
 | 
					 | 
				
			||||||
	 * should generally be a "last resort" option for a filesystem
 | 
					 | 
				
			||||||
	 * to be able to do its job.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	spin_lock_irqsave(&ext4_crypto_ctx_lock, flags);
 | 
					 | 
				
			||||||
	ctx = list_first_entry_or_null(&ext4_free_crypto_ctxs,
 | 
					 | 
				
			||||||
				       struct ext4_crypto_ctx, free_list);
 | 
					 | 
				
			||||||
	if (ctx)
 | 
					 | 
				
			||||||
		list_del(&ctx->free_list);
 | 
					 | 
				
			||||||
	spin_unlock_irqrestore(&ext4_crypto_ctx_lock, flags);
 | 
					 | 
				
			||||||
	if (!ctx) {
 | 
					 | 
				
			||||||
		ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, gfp_flags);
 | 
					 | 
				
			||||||
		if (!ctx) {
 | 
					 | 
				
			||||||
			res = -ENOMEM;
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ctx->flags |= EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ctx->flags &= ~EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx->flags &= ~EXT4_WRITE_PATH_FL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	if (res) {
 | 
					 | 
				
			||||||
		if (!IS_ERR_OR_NULL(ctx))
 | 
					 | 
				
			||||||
			ext4_release_crypto_ctx(ctx);
 | 
					 | 
				
			||||||
		ctx = ERR_PTR(res);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ctx;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct workqueue_struct *ext4_read_workqueue;
 | 
					 | 
				
			||||||
static DEFINE_MUTEX(crypto_init);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_exit_crypto() - Shutdown the ext4 encryption system
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void ext4_exit_crypto(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypto_ctx *pos, *n;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	list_for_each_entry_safe(pos, n, &ext4_free_crypto_ctxs, free_list)
 | 
					 | 
				
			||||||
		kmem_cache_free(ext4_crypto_ctx_cachep, pos);
 | 
					 | 
				
			||||||
	INIT_LIST_HEAD(&ext4_free_crypto_ctxs);
 | 
					 | 
				
			||||||
	if (ext4_bounce_page_pool)
 | 
					 | 
				
			||||||
		mempool_destroy(ext4_bounce_page_pool);
 | 
					 | 
				
			||||||
	ext4_bounce_page_pool = NULL;
 | 
					 | 
				
			||||||
	if (ext4_read_workqueue)
 | 
					 | 
				
			||||||
		destroy_workqueue(ext4_read_workqueue);
 | 
					 | 
				
			||||||
	ext4_read_workqueue = NULL;
 | 
					 | 
				
			||||||
	if (ext4_crypto_ctx_cachep)
 | 
					 | 
				
			||||||
		kmem_cache_destroy(ext4_crypto_ctx_cachep);
 | 
					 | 
				
			||||||
	ext4_crypto_ctx_cachep = NULL;
 | 
					 | 
				
			||||||
	if (ext4_crypt_info_cachep)
 | 
					 | 
				
			||||||
		kmem_cache_destroy(ext4_crypt_info_cachep);
 | 
					 | 
				
			||||||
	ext4_crypt_info_cachep = NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_init_crypto() - Set up for ext4 encryption.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * We only call this when we start accessing encrypted files, since it
 | 
					 | 
				
			||||||
 * results in memory getting allocated that wouldn't otherwise be used.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: Zero on success, non-zero otherwise.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int ext4_init_crypto(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i, res = -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&crypto_init);
 | 
					 | 
				
			||||||
	if (ext4_read_workqueue)
 | 
					 | 
				
			||||||
		goto already_initialized;
 | 
					 | 
				
			||||||
	ext4_read_workqueue = alloc_workqueue("ext4_crypto", WQ_HIGHPRI, 0);
 | 
					 | 
				
			||||||
	if (!ext4_read_workqueue)
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ext4_crypto_ctx_cachep = KMEM_CACHE(ext4_crypto_ctx,
 | 
					 | 
				
			||||||
					    SLAB_RECLAIM_ACCOUNT);
 | 
					 | 
				
			||||||
	if (!ext4_crypto_ctx_cachep)
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ext4_crypt_info_cachep = KMEM_CACHE(ext4_crypt_info,
 | 
					 | 
				
			||||||
					    SLAB_RECLAIM_ACCOUNT);
 | 
					 | 
				
			||||||
	if (!ext4_crypt_info_cachep)
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < num_prealloc_crypto_ctxs; i++) {
 | 
					 | 
				
			||||||
		struct ext4_crypto_ctx *ctx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, GFP_NOFS);
 | 
					 | 
				
			||||||
		if (!ctx) {
 | 
					 | 
				
			||||||
			res = -ENOMEM;
 | 
					 | 
				
			||||||
			goto fail;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		list_add(&ctx->free_list, &ext4_free_crypto_ctxs);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ext4_bounce_page_pool =
 | 
					 | 
				
			||||||
		mempool_create_page_pool(num_prealloc_crypto_pages, 0);
 | 
					 | 
				
			||||||
	if (!ext4_bounce_page_pool) {
 | 
					 | 
				
			||||||
		res = -ENOMEM;
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
already_initialized:
 | 
					 | 
				
			||||||
	mutex_unlock(&crypto_init);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
fail:
 | 
					 | 
				
			||||||
	ext4_exit_crypto();
 | 
					 | 
				
			||||||
	mutex_unlock(&crypto_init);
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ext4_restore_control_page(struct page *data_page)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypto_ctx *ctx =
 | 
					 | 
				
			||||||
		(struct ext4_crypto_ctx *)page_private(data_page);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set_page_private(data_page, (unsigned long)NULL);
 | 
					 | 
				
			||||||
	ClearPagePrivate(data_page);
 | 
					 | 
				
			||||||
	unlock_page(data_page);
 | 
					 | 
				
			||||||
	ext4_release_crypto_ctx(ctx);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_crypt_complete() - The completion callback for page encryption
 | 
					 | 
				
			||||||
 * @req: The asynchronous encryption request context
 | 
					 | 
				
			||||||
 * @res: The result of the encryption operation
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void ext4_crypt_complete(struct crypto_async_request *req, int res)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_completion_result *ecr = req->data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (res == -EINPROGRESS)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	ecr->res = res;
 | 
					 | 
				
			||||||
	complete(&ecr->completion);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum {
 | 
					 | 
				
			||||||
	EXT4_DECRYPT = 0,
 | 
					 | 
				
			||||||
	EXT4_ENCRYPT,
 | 
					 | 
				
			||||||
} ext4_direction_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ext4_page_crypto(struct inode *inode,
 | 
					 | 
				
			||||||
			    ext4_direction_t rw,
 | 
					 | 
				
			||||||
			    pgoff_t index,
 | 
					 | 
				
			||||||
			    struct page *src_page,
 | 
					 | 
				
			||||||
			    struct page *dest_page,
 | 
					 | 
				
			||||||
			    gfp_t gfp_flags)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u8 xts_tweak[EXT4_XTS_TWEAK_SIZE];
 | 
					 | 
				
			||||||
	struct skcipher_request *req = NULL;
 | 
					 | 
				
			||||||
	DECLARE_EXT4_COMPLETION_RESULT(ecr);
 | 
					 | 
				
			||||||
	struct scatterlist dst, src;
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
	struct crypto_skcipher *tfm = ci->ci_ctfm;
 | 
					 | 
				
			||||||
	int res = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req = skcipher_request_alloc(tfm, gfp_flags);
 | 
					 | 
				
			||||||
	if (!req) {
 | 
					 | 
				
			||||||
		printk_ratelimited(KERN_ERR
 | 
					 | 
				
			||||||
				   "%s: crypto_request_alloc() failed\n",
 | 
					 | 
				
			||||||
				   __func__);
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	skcipher_request_set_callback(
 | 
					 | 
				
			||||||
		req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
 | 
					 | 
				
			||||||
		ext4_crypt_complete, &ecr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BUILD_BUG_ON(EXT4_XTS_TWEAK_SIZE < sizeof(index));
 | 
					 | 
				
			||||||
	memcpy(xts_tweak, &index, sizeof(index));
 | 
					 | 
				
			||||||
	memset(&xts_tweak[sizeof(index)], 0,
 | 
					 | 
				
			||||||
	       EXT4_XTS_TWEAK_SIZE - sizeof(index));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sg_init_table(&dst, 1);
 | 
					 | 
				
			||||||
	sg_set_page(&dst, dest_page, PAGE_SIZE, 0);
 | 
					 | 
				
			||||||
	sg_init_table(&src, 1);
 | 
					 | 
				
			||||||
	sg_set_page(&src, src_page, PAGE_SIZE, 0);
 | 
					 | 
				
			||||||
	skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE,
 | 
					 | 
				
			||||||
				   xts_tweak);
 | 
					 | 
				
			||||||
	if (rw == EXT4_DECRYPT)
 | 
					 | 
				
			||||||
		res = crypto_skcipher_decrypt(req);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		res = crypto_skcipher_encrypt(req);
 | 
					 | 
				
			||||||
	if (res == -EINPROGRESS || res == -EBUSY) {
 | 
					 | 
				
			||||||
		wait_for_completion(&ecr.completion);
 | 
					 | 
				
			||||||
		res = ecr.res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	skcipher_request_free(req);
 | 
					 | 
				
			||||||
	if (res) {
 | 
					 | 
				
			||||||
		printk_ratelimited(
 | 
					 | 
				
			||||||
			KERN_ERR
 | 
					 | 
				
			||||||
			"%s: crypto_skcipher_encrypt() returned %d\n",
 | 
					 | 
				
			||||||
			__func__, res);
 | 
					 | 
				
			||||||
		return res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct page *alloc_bounce_page(struct ext4_crypto_ctx *ctx,
 | 
					 | 
				
			||||||
				      gfp_t gfp_flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	ctx->w.bounce_page = mempool_alloc(ext4_bounce_page_pool, gfp_flags);
 | 
					 | 
				
			||||||
	if (ctx->w.bounce_page == NULL)
 | 
					 | 
				
			||||||
		return ERR_PTR(-ENOMEM);
 | 
					 | 
				
			||||||
	ctx->flags |= EXT4_WRITE_PATH_FL;
 | 
					 | 
				
			||||||
	return ctx->w.bounce_page;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_encrypt() - Encrypts a page
 | 
					 | 
				
			||||||
 * @inode:          The inode for which the encryption should take place
 | 
					 | 
				
			||||||
 * @plaintext_page: The page to encrypt. Must be locked.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx
 | 
					 | 
				
			||||||
 * encryption context.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Called on the page write path.  The caller must call
 | 
					 | 
				
			||||||
 * ext4_restore_control_page() on the returned ciphertext page to
 | 
					 | 
				
			||||||
 * release the bounce buffer and the encryption context.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: An allocated page with the encrypted content on success. Else, an
 | 
					 | 
				
			||||||
 * error value or NULL.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct page *ext4_encrypt(struct inode *inode,
 | 
					 | 
				
			||||||
			  struct page *plaintext_page,
 | 
					 | 
				
			||||||
			  gfp_t gfp_flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypto_ctx *ctx;
 | 
					 | 
				
			||||||
	struct page *ciphertext_page = NULL;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BUG_ON(!PageLocked(plaintext_page));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx = ext4_get_crypto_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, gfp_flags);
 | 
					 | 
				
			||||||
	if (IS_ERR(ciphertext_page))
 | 
					 | 
				
			||||||
		goto errout;
 | 
					 | 
				
			||||||
	ctx->w.control_page = plaintext_page;
 | 
					 | 
				
			||||||
	err = ext4_page_crypto(inode, EXT4_ENCRYPT, plaintext_page->index,
 | 
					 | 
				
			||||||
			       plaintext_page, ciphertext_page, gfp_flags);
 | 
					 | 
				
			||||||
	if (err) {
 | 
					 | 
				
			||||||
		ciphertext_page = ERR_PTR(err);
 | 
					 | 
				
			||||||
	errout:
 | 
					 | 
				
			||||||
		ext4_release_crypto_ctx(ctx);
 | 
					 | 
				
			||||||
		return ciphertext_page;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	SetPagePrivate(ciphertext_page);
 | 
					 | 
				
			||||||
	set_page_private(ciphertext_page, (unsigned long)ctx);
 | 
					 | 
				
			||||||
	lock_page(ciphertext_page);
 | 
					 | 
				
			||||||
	return ciphertext_page;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_decrypt() - Decrypts a page in-place
 | 
					 | 
				
			||||||
 * @ctx:  The encryption context.
 | 
					 | 
				
			||||||
 * @page: The page to decrypt. Must be locked.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Decrypts page in-place using the ctx encryption context.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Called from the read completion callback.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: Zero on success, non-zero otherwise.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int ext4_decrypt(struct page *page)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	BUG_ON(!PageLocked(page));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ext4_page_crypto(page->mapping->host, EXT4_DECRYPT,
 | 
					 | 
				
			||||||
				page->index, page, page, GFP_NOFS);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk,
 | 
					 | 
				
			||||||
			   ext4_fsblk_t pblk, ext4_lblk_t len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypto_ctx	*ctx;
 | 
					 | 
				
			||||||
	struct page		*ciphertext_page = NULL;
 | 
					 | 
				
			||||||
	struct bio		*bio;
 | 
					 | 
				
			||||||
	int			ret, err = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	ext4_msg(inode->i_sb, KERN_CRIT,
 | 
					 | 
				
			||||||
		 "ext4_encrypted_zeroout ino %lu lblk %u len %u",
 | 
					 | 
				
			||||||
		 (unsigned long) inode->i_ino, lblk, len);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx = ext4_get_crypto_ctx(inode, GFP_NOFS);
 | 
					 | 
				
			||||||
	if (IS_ERR(ctx))
 | 
					 | 
				
			||||||
		return PTR_ERR(ctx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT);
 | 
					 | 
				
			||||||
	if (IS_ERR(ciphertext_page)) {
 | 
					 | 
				
			||||||
		err = PTR_ERR(ciphertext_page);
 | 
					 | 
				
			||||||
		goto errout;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (len--) {
 | 
					 | 
				
			||||||
		err = ext4_page_crypto(inode, EXT4_ENCRYPT, lblk,
 | 
					 | 
				
			||||||
				       ZERO_PAGE(0), ciphertext_page,
 | 
					 | 
				
			||||||
				       GFP_NOFS);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto errout;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bio = bio_alloc(GFP_NOWAIT, 1);
 | 
					 | 
				
			||||||
		if (!bio) {
 | 
					 | 
				
			||||||
			err = -ENOMEM;
 | 
					 | 
				
			||||||
			goto errout;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		bio->bi_bdev = inode->i_sb->s_bdev;
 | 
					 | 
				
			||||||
		bio->bi_iter.bi_sector =
 | 
					 | 
				
			||||||
			pblk << (inode->i_sb->s_blocksize_bits - 9);
 | 
					 | 
				
			||||||
		ret = bio_add_page(bio, ciphertext_page,
 | 
					 | 
				
			||||||
				   inode->i_sb->s_blocksize, 0);
 | 
					 | 
				
			||||||
		if (ret != inode->i_sb->s_blocksize) {
 | 
					 | 
				
			||||||
			/* should never happen! */
 | 
					 | 
				
			||||||
			ext4_msg(inode->i_sb, KERN_ERR,
 | 
					 | 
				
			||||||
				 "bio_add_page failed: %d", ret);
 | 
					 | 
				
			||||||
			WARN_ON(1);
 | 
					 | 
				
			||||||
			bio_put(bio);
 | 
					 | 
				
			||||||
			err = -EIO;
 | 
					 | 
				
			||||||
			goto errout;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = submit_bio_wait(WRITE, bio);
 | 
					 | 
				
			||||||
		if ((err == 0) && bio->bi_error)
 | 
					 | 
				
			||||||
			err = -EIO;
 | 
					 | 
				
			||||||
		bio_put(bio);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto errout;
 | 
					 | 
				
			||||||
		lblk++; pblk++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = 0;
 | 
					 | 
				
			||||||
errout:
 | 
					 | 
				
			||||||
	ext4_release_crypto_ctx(ctx);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool ext4_valid_contents_enc_mode(uint32_t mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return (mode == EXT4_ENCRYPTION_MODE_AES_256_XTS);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_validate_encryption_key_size() - Validate the encryption key size
 | 
					 | 
				
			||||||
 * @mode: The key mode.
 | 
					 | 
				
			||||||
 * @size: The key size to validate.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: The validated key size for @mode. Zero if invalid.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (size == ext4_encryption_key_size(mode))
 | 
					 | 
				
			||||||
		return size;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Validate dentries for encrypted directories to make sure we aren't
 | 
					 | 
				
			||||||
 * potentially caching stale data after a key has been added or
 | 
					 | 
				
			||||||
 * removed.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dentry *dir;
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ci = EXT4_I(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) |
 | 
					 | 
				
			||||||
					  (1 << KEY_FLAG_DEAD))))
 | 
					 | 
				
			||||||
		ci = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* this should eventually be an flag in d_flags */
 | 
					 | 
				
			||||||
	cached_with_key = dentry->d_fsdata != NULL;
 | 
					 | 
				
			||||||
	dir_has_key = (ci != NULL);
 | 
					 | 
				
			||||||
	dput(dir);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * If the dentry was cached without the key, and it is a
 | 
					 | 
				
			||||||
	 * negative dentry, it might be a valid name.  We can't check
 | 
					 | 
				
			||||||
	 * if the key has since been made available due to locking
 | 
					 | 
				
			||||||
	 * reasons, so we fail the validation so ext4_lookup() can do
 | 
					 | 
				
			||||||
	 * this check.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * We also fail the validation if the dentry was created with
 | 
					 | 
				
			||||||
	 * the key present, but we no longer have the key, or vice versa.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if ((!cached_with_key && d_is_negative(dentry)) ||
 | 
					 | 
				
			||||||
	    (!cached_with_key && dir_has_key) ||
 | 
					 | 
				
			||||||
	    (cached_with_key && !dir_has_key)) {
 | 
					 | 
				
			||||||
#if 0				/* Revalidation debug */
 | 
					 | 
				
			||||||
		char buf[80];
 | 
					 | 
				
			||||||
		char *cp = simple_dname(dentry, buf, sizeof(buf));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (IS_ERR(cp))
 | 
					 | 
				
			||||||
			cp = (char *) "???";
 | 
					 | 
				
			||||||
		pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata,
 | 
					 | 
				
			||||||
		       cached_with_key, d_is_negative(dentry),
 | 
					 | 
				
			||||||
		       dir_has_key);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const struct dentry_operations ext4_encrypted_d_ops = {
 | 
					 | 
				
			||||||
	.d_revalidate = ext4_d_revalidate,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,468 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * linux/fs/ext4/crypto_fname.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2015, Google, Inc.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This contains functions for filename crypto management in ext4
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Written by Uday Savagaonkar, 2014.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This has not yet undergone a rigorous security audit.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <crypto/skcipher.h>
 | 
					 | 
				
			||||||
#include <keys/encrypted-type.h>
 | 
					 | 
				
			||||||
#include <keys/user-type.h>
 | 
					 | 
				
			||||||
#include <linux/gfp.h>
 | 
					 | 
				
			||||||
#include <linux/kernel.h>
 | 
					 | 
				
			||||||
#include <linux/key.h>
 | 
					 | 
				
			||||||
#include <linux/list.h>
 | 
					 | 
				
			||||||
#include <linux/mempool.h>
 | 
					 | 
				
			||||||
#include <linux/random.h>
 | 
					 | 
				
			||||||
#include <linux/scatterlist.h>
 | 
					 | 
				
			||||||
#include <linux/spinlock_types.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ext4.h"
 | 
					 | 
				
			||||||
#include "ext4_crypto.h"
 | 
					 | 
				
			||||||
#include "xattr.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_dir_crypt_complete() -
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void ext4_dir_crypt_complete(struct crypto_async_request *req, int res)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_completion_result *ecr = req->data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (res == -EINPROGRESS)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	ecr->res = res;
 | 
					 | 
				
			||||||
	complete(&ecr->completion);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool ext4_valid_filenames_enc_mode(uint32_t mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return (mode == EXT4_ENCRYPTION_MODE_AES_256_CTS);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned max_name_len(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize :
 | 
					 | 
				
			||||||
		EXT4_NAME_LEN;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_fname_encrypt() -
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This function encrypts the input filename, and returns the length of the
 | 
					 | 
				
			||||||
 * ciphertext. Errors are returned as negative numbers.  We trust the caller to
 | 
					 | 
				
			||||||
 * allocate sufficient memory to oname string.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int ext4_fname_encrypt(struct inode *inode,
 | 
					 | 
				
			||||||
			      const struct qstr *iname,
 | 
					 | 
				
			||||||
			      struct ext4_str *oname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u32 ciphertext_len;
 | 
					 | 
				
			||||||
	struct skcipher_request *req = NULL;
 | 
					 | 
				
			||||||
	DECLARE_EXT4_COMPLETION_RESULT(ecr);
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
	struct crypto_skcipher *tfm = ci->ci_ctfm;
 | 
					 | 
				
			||||||
	int res = 0;
 | 
					 | 
				
			||||||
	char iv[EXT4_CRYPTO_BLOCK_SIZE];
 | 
					 | 
				
			||||||
	struct scatterlist src_sg, dst_sg;
 | 
					 | 
				
			||||||
	int padding = 4 << (ci->ci_flags & EXT4_POLICY_FLAGS_PAD_MASK);
 | 
					 | 
				
			||||||
	char *workbuf, buf[32], *alloc_buf = NULL;
 | 
					 | 
				
			||||||
	unsigned lim = max_name_len(inode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (iname->len <= 0 || iname->len > lim)
 | 
					 | 
				
			||||||
		return -EIO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ciphertext_len = (iname->len < EXT4_CRYPTO_BLOCK_SIZE) ?
 | 
					 | 
				
			||||||
		EXT4_CRYPTO_BLOCK_SIZE : iname->len;
 | 
					 | 
				
			||||||
	ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding);
 | 
					 | 
				
			||||||
	ciphertext_len = (ciphertext_len > lim)
 | 
					 | 
				
			||||||
			? lim : ciphertext_len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ciphertext_len <= sizeof(buf)) {
 | 
					 | 
				
			||||||
		workbuf = buf;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
 | 
					 | 
				
			||||||
		if (!alloc_buf)
 | 
					 | 
				
			||||||
			return -ENOMEM;
 | 
					 | 
				
			||||||
		workbuf = alloc_buf;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Allocate request */
 | 
					 | 
				
			||||||
	req = skcipher_request_alloc(tfm, GFP_NOFS);
 | 
					 | 
				
			||||||
	if (!req) {
 | 
					 | 
				
			||||||
		printk_ratelimited(
 | 
					 | 
				
			||||||
		    KERN_ERR "%s: crypto_request_alloc() failed\n", __func__);
 | 
					 | 
				
			||||||
		kfree(alloc_buf);
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	skcipher_request_set_callback(req,
 | 
					 | 
				
			||||||
		CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
 | 
					 | 
				
			||||||
		ext4_dir_crypt_complete, &ecr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Copy the input */
 | 
					 | 
				
			||||||
	memcpy(workbuf, iname->name, iname->len);
 | 
					 | 
				
			||||||
	if (iname->len < ciphertext_len)
 | 
					 | 
				
			||||||
		memset(workbuf + iname->len, 0, ciphertext_len - iname->len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Initialize IV */
 | 
					 | 
				
			||||||
	memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create encryption request */
 | 
					 | 
				
			||||||
	sg_init_one(&src_sg, workbuf, ciphertext_len);
 | 
					 | 
				
			||||||
	sg_init_one(&dst_sg, oname->name, ciphertext_len);
 | 
					 | 
				
			||||||
	skcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
 | 
					 | 
				
			||||||
	res = crypto_skcipher_encrypt(req);
 | 
					 | 
				
			||||||
	if (res == -EINPROGRESS || res == -EBUSY) {
 | 
					 | 
				
			||||||
		wait_for_completion(&ecr.completion);
 | 
					 | 
				
			||||||
		res = ecr.res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	kfree(alloc_buf);
 | 
					 | 
				
			||||||
	skcipher_request_free(req);
 | 
					 | 
				
			||||||
	if (res < 0) {
 | 
					 | 
				
			||||||
		printk_ratelimited(
 | 
					 | 
				
			||||||
		    KERN_ERR "%s: Error (error code %d)\n", __func__, res);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	oname->len = ciphertext_len;
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * ext4_fname_decrypt()
 | 
					 | 
				
			||||||
 *	This function decrypts the input filename, and returns
 | 
					 | 
				
			||||||
 *	the length of the plaintext.
 | 
					 | 
				
			||||||
 *	Errors are returned as negative numbers.
 | 
					 | 
				
			||||||
 *	We trust the caller to allocate sufficient memory to oname string.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int ext4_fname_decrypt(struct inode *inode,
 | 
					 | 
				
			||||||
			      const struct ext4_str *iname,
 | 
					 | 
				
			||||||
			      struct ext4_str *oname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_str tmp_in[2], tmp_out[1];
 | 
					 | 
				
			||||||
	struct skcipher_request *req = NULL;
 | 
					 | 
				
			||||||
	DECLARE_EXT4_COMPLETION_RESULT(ecr);
 | 
					 | 
				
			||||||
	struct scatterlist src_sg, dst_sg;
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
	struct crypto_skcipher *tfm = ci->ci_ctfm;
 | 
					 | 
				
			||||||
	int res = 0;
 | 
					 | 
				
			||||||
	char iv[EXT4_CRYPTO_BLOCK_SIZE];
 | 
					 | 
				
			||||||
	unsigned lim = max_name_len(inode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (iname->len <= 0 || iname->len > lim)
 | 
					 | 
				
			||||||
		return -EIO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tmp_in[0].name = iname->name;
 | 
					 | 
				
			||||||
	tmp_in[0].len = iname->len;
 | 
					 | 
				
			||||||
	tmp_out[0].name = oname->name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Allocate request */
 | 
					 | 
				
			||||||
	req = skcipher_request_alloc(tfm, GFP_NOFS);
 | 
					 | 
				
			||||||
	if (!req) {
 | 
					 | 
				
			||||||
		printk_ratelimited(
 | 
					 | 
				
			||||||
		    KERN_ERR "%s: crypto_request_alloc() failed\n",  __func__);
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	skcipher_request_set_callback(req,
 | 
					 | 
				
			||||||
		CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
 | 
					 | 
				
			||||||
		ext4_dir_crypt_complete, &ecr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Initialize IV */
 | 
					 | 
				
			||||||
	memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create encryption request */
 | 
					 | 
				
			||||||
	sg_init_one(&src_sg, iname->name, iname->len);
 | 
					 | 
				
			||||||
	sg_init_one(&dst_sg, oname->name, oname->len);
 | 
					 | 
				
			||||||
	skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
 | 
					 | 
				
			||||||
	res = crypto_skcipher_decrypt(req);
 | 
					 | 
				
			||||||
	if (res == -EINPROGRESS || res == -EBUSY) {
 | 
					 | 
				
			||||||
		wait_for_completion(&ecr.completion);
 | 
					 | 
				
			||||||
		res = ecr.res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	skcipher_request_free(req);
 | 
					 | 
				
			||||||
	if (res < 0) {
 | 
					 | 
				
			||||||
		printk_ratelimited(
 | 
					 | 
				
			||||||
		    KERN_ERR "%s: Error in ext4_fname_encrypt (error code %d)\n",
 | 
					 | 
				
			||||||
		    __func__, res);
 | 
					 | 
				
			||||||
		return res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	oname->len = strnlen(oname->name, iname->len);
 | 
					 | 
				
			||||||
	return oname->len;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const char *lookup_table =
 | 
					 | 
				
			||||||
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_fname_encode_digest() -
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Encodes the input digest using characters from the set [a-zA-Z0-9_+].
 | 
					 | 
				
			||||||
 * The encoded string is roughly 4/3 times the size of the input string.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int digest_encode(const char *src, int len, char *dst)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i = 0, bits = 0, ac = 0;
 | 
					 | 
				
			||||||
	char *cp = dst;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (i < len) {
 | 
					 | 
				
			||||||
		ac += (((unsigned char) src[i]) << bits);
 | 
					 | 
				
			||||||
		bits += 8;
 | 
					 | 
				
			||||||
		do {
 | 
					 | 
				
			||||||
			*cp++ = lookup_table[ac & 0x3f];
 | 
					 | 
				
			||||||
			ac >>= 6;
 | 
					 | 
				
			||||||
			bits -= 6;
 | 
					 | 
				
			||||||
		} while (bits >= 6);
 | 
					 | 
				
			||||||
		i++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (bits)
 | 
					 | 
				
			||||||
		*cp++ = lookup_table[ac & 0x3f];
 | 
					 | 
				
			||||||
	return cp - dst;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int digest_decode(const char *src, int len, char *dst)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i = 0, bits = 0, ac = 0;
 | 
					 | 
				
			||||||
	const char *p;
 | 
					 | 
				
			||||||
	char *cp = dst;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (i < len) {
 | 
					 | 
				
			||||||
		p = strchr(lookup_table, src[i]);
 | 
					 | 
				
			||||||
		if (p == NULL || src[i] == 0)
 | 
					 | 
				
			||||||
			return -2;
 | 
					 | 
				
			||||||
		ac += (p - lookup_table) << bits;
 | 
					 | 
				
			||||||
		bits += 6;
 | 
					 | 
				
			||||||
		if (bits >= 8) {
 | 
					 | 
				
			||||||
			*cp++ = ac & 0xff;
 | 
					 | 
				
			||||||
			ac >>= 8;
 | 
					 | 
				
			||||||
			bits -= 8;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		i++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (ac)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	return cp - dst;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_fname_crypto_round_up() -
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: The next multiple of block size
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
u32 ext4_fname_crypto_round_up(u32 size, u32 blksize)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ((size+blksize-1)/blksize)*blksize;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
unsigned ext4_fname_encrypted_size(struct inode *inode, u32 ilen)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
	int padding = 32;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ci)
 | 
					 | 
				
			||||||
		padding = 4 << (ci->ci_flags & EXT4_POLICY_FLAGS_PAD_MASK);
 | 
					 | 
				
			||||||
	if (ilen < EXT4_CRYPTO_BLOCK_SIZE)
 | 
					 | 
				
			||||||
		ilen = EXT4_CRYPTO_BLOCK_SIZE;
 | 
					 | 
				
			||||||
	return ext4_fname_crypto_round_up(ilen, padding);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * ext4_fname_crypto_alloc_buffer() -
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Allocates an output buffer that is sufficient for the crypto operation
 | 
					 | 
				
			||||||
 * specified by the context and the direction.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int ext4_fname_crypto_alloc_buffer(struct inode *inode,
 | 
					 | 
				
			||||||
				   u32 ilen, struct ext4_str *crypto_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned int olen = ext4_fname_encrypted_size(inode, ilen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	crypto_str->len = olen;
 | 
					 | 
				
			||||||
	if (olen < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2)
 | 
					 | 
				
			||||||
		olen = EXT4_FNAME_CRYPTO_DIGEST_SIZE*2;
 | 
					 | 
				
			||||||
	/* Allocated buffer can hold one more character to null-terminate the
 | 
					 | 
				
			||||||
	 * string */
 | 
					 | 
				
			||||||
	crypto_str->name = kmalloc(olen+1, GFP_NOFS);
 | 
					 | 
				
			||||||
	if (!(crypto_str->name))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_fname_crypto_free_buffer() -
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Frees the buffer allocated for crypto operation.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (!crypto_str)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	kfree(crypto_str->name);
 | 
					 | 
				
			||||||
	crypto_str->name = NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_fname_disk_to_usr() - converts a filename from disk space to user space
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int _ext4_fname_disk_to_usr(struct inode *inode,
 | 
					 | 
				
			||||||
			    struct dx_hash_info *hinfo,
 | 
					 | 
				
			||||||
			    const struct ext4_str *iname,
 | 
					 | 
				
			||||||
			    struct ext4_str *oname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char buf[24];
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (iname->len < 3) {
 | 
					 | 
				
			||||||
		/*Check for . and .. */
 | 
					 | 
				
			||||||
		if (iname->name[0] == '.' && iname->name[iname->len-1] == '.') {
 | 
					 | 
				
			||||||
			oname->name[0] = '.';
 | 
					 | 
				
			||||||
			oname->name[iname->len-1] = '.';
 | 
					 | 
				
			||||||
			oname->len = iname->len;
 | 
					 | 
				
			||||||
			return oname->len;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (iname->len < EXT4_CRYPTO_BLOCK_SIZE) {
 | 
					 | 
				
			||||||
		EXT4_ERROR_INODE(inode, "encrypted inode too small");
 | 
					 | 
				
			||||||
		return -EUCLEAN;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (EXT4_I(inode)->i_crypt_info)
 | 
					 | 
				
			||||||
		return ext4_fname_decrypt(inode, iname, oname);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) {
 | 
					 | 
				
			||||||
		ret = digest_encode(iname->name, iname->len, oname->name);
 | 
					 | 
				
			||||||
		oname->len = ret;
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (hinfo) {
 | 
					 | 
				
			||||||
		memcpy(buf, &hinfo->hash, 4);
 | 
					 | 
				
			||||||
		memcpy(buf+4, &hinfo->minor_hash, 4);
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		memset(buf, 0, 8);
 | 
					 | 
				
			||||||
	memcpy(buf + 8, iname->name + iname->len - 16, 16);
 | 
					 | 
				
			||||||
	oname->name[0] = '_';
 | 
					 | 
				
			||||||
	ret = digest_encode(buf, 24, oname->name+1);
 | 
					 | 
				
			||||||
	oname->len = ret + 1;
 | 
					 | 
				
			||||||
	return ret + 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ext4_fname_disk_to_usr(struct inode *inode,
 | 
					 | 
				
			||||||
			   struct dx_hash_info *hinfo,
 | 
					 | 
				
			||||||
			   const struct ext4_dir_entry_2 *de,
 | 
					 | 
				
			||||||
			   struct ext4_str *oname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_str iname = {.name = (unsigned char *) de->name,
 | 
					 | 
				
			||||||
				 .len = de->name_len };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return _ext4_fname_disk_to_usr(inode, hinfo, &iname, oname);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_fname_usr_to_disk() - converts a filename from user space to disk space
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int ext4_fname_usr_to_disk(struct inode *inode,
 | 
					 | 
				
			||||||
			   const struct qstr *iname,
 | 
					 | 
				
			||||||
			   struct ext4_str *oname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (iname->len < 3) {
 | 
					 | 
				
			||||||
		/*Check for . and .. */
 | 
					 | 
				
			||||||
		if (iname->name[0] == '.' &&
 | 
					 | 
				
			||||||
				iname->name[iname->len-1] == '.') {
 | 
					 | 
				
			||||||
			oname->name[0] = '.';
 | 
					 | 
				
			||||||
			oname->name[iname->len-1] = '.';
 | 
					 | 
				
			||||||
			oname->len = iname->len;
 | 
					 | 
				
			||||||
			return oname->len;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (ci) {
 | 
					 | 
				
			||||||
		res = ext4_fname_encrypt(inode, iname, oname);
 | 
					 | 
				
			||||||
		return res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Without a proper key, a user is not allowed to modify the filenames
 | 
					 | 
				
			||||||
	 * in a directory. Consequently, a user space name cannot be mapped to
 | 
					 | 
				
			||||||
	 * a disk-space name */
 | 
					 | 
				
			||||||
	return -EACCES;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ext4_fname_setup_filename(struct inode *dir, const struct qstr *iname,
 | 
					 | 
				
			||||||
			      int lookup, struct ext4_filename *fname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci;
 | 
					 | 
				
			||||||
	int ret = 0, bigname = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(fname, 0, sizeof(struct ext4_filename));
 | 
					 | 
				
			||||||
	fname->usr_fname = iname;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!ext4_encrypted_inode(dir) ||
 | 
					 | 
				
			||||||
	    ((iname->name[0] == '.') &&
 | 
					 | 
				
			||||||
	     ((iname->len == 1) ||
 | 
					 | 
				
			||||||
	      ((iname->name[1] == '.') && (iname->len == 2))))) {
 | 
					 | 
				
			||||||
		fname->disk_name.name = (unsigned char *) iname->name;
 | 
					 | 
				
			||||||
		fname->disk_name.len = iname->len;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ret = ext4_get_encryption_info(dir);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	ci = EXT4_I(dir)->i_crypt_info;
 | 
					 | 
				
			||||||
	if (ci) {
 | 
					 | 
				
			||||||
		ret = ext4_fname_crypto_alloc_buffer(dir, iname->len,
 | 
					 | 
				
			||||||
						     &fname->crypto_buf);
 | 
					 | 
				
			||||||
		if (ret < 0)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
		ret = ext4_fname_encrypt(dir, iname, &fname->crypto_buf);
 | 
					 | 
				
			||||||
		if (ret < 0)
 | 
					 | 
				
			||||||
			goto errout;
 | 
					 | 
				
			||||||
		fname->disk_name.name = fname->crypto_buf.name;
 | 
					 | 
				
			||||||
		fname->disk_name.len = fname->crypto_buf.len;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!lookup)
 | 
					 | 
				
			||||||
		return -EACCES;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* We don't have the key and we are doing a lookup; decode the
 | 
					 | 
				
			||||||
	 * user-supplied name
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (iname->name[0] == '_')
 | 
					 | 
				
			||||||
		bigname = 1;
 | 
					 | 
				
			||||||
	if ((bigname && (iname->len != 33)) ||
 | 
					 | 
				
			||||||
	    (!bigname && (iname->len > 43)))
 | 
					 | 
				
			||||||
		return -ENOENT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fname->crypto_buf.name = kmalloc(32, GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (fname->crypto_buf.name == NULL)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	ret = digest_decode(iname->name + bigname, iname->len - bigname,
 | 
					 | 
				
			||||||
			    fname->crypto_buf.name);
 | 
					 | 
				
			||||||
	if (ret < 0) {
 | 
					 | 
				
			||||||
		ret = -ENOENT;
 | 
					 | 
				
			||||||
		goto errout;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fname->crypto_buf.len = ret;
 | 
					 | 
				
			||||||
	if (bigname) {
 | 
					 | 
				
			||||||
		memcpy(&fname->hinfo.hash, fname->crypto_buf.name, 4);
 | 
					 | 
				
			||||||
		memcpy(&fname->hinfo.minor_hash, fname->crypto_buf.name + 4, 4);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		fname->disk_name.name = fname->crypto_buf.name;
 | 
					 | 
				
			||||||
		fname->disk_name.len = fname->crypto_buf.len;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
errout:
 | 
					 | 
				
			||||||
	kfree(fname->crypto_buf.name);
 | 
					 | 
				
			||||||
	fname->crypto_buf.name = NULL;
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ext4_fname_free_filename(struct ext4_filename *fname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	kfree(fname->crypto_buf.name);
 | 
					 | 
				
			||||||
	fname->crypto_buf.name = NULL;
 | 
					 | 
				
			||||||
	fname->usr_fname = NULL;
 | 
					 | 
				
			||||||
	fname->disk_name.name = NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,274 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * linux/fs/ext4/crypto_key.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2015, Google, Inc.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This contains encryption key functions for ext4
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <crypto/skcipher.h>
 | 
					 | 
				
			||||||
#include <keys/encrypted-type.h>
 | 
					 | 
				
			||||||
#include <keys/user-type.h>
 | 
					 | 
				
			||||||
#include <linux/random.h>
 | 
					 | 
				
			||||||
#include <linux/scatterlist.h>
 | 
					 | 
				
			||||||
#include <uapi/linux/keyctl.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ext4.h"
 | 
					 | 
				
			||||||
#include "xattr.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void derive_crypt_complete(struct crypto_async_request *req, int rc)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_completion_result *ecr = req->data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rc == -EINPROGRESS)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ecr->res = rc;
 | 
					 | 
				
			||||||
	complete(&ecr->completion);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_derive_key_aes() - Derive a key using AES-128-ECB
 | 
					 | 
				
			||||||
 * @deriving_key: Encryption key used for derivation.
 | 
					 | 
				
			||||||
 * @source_key:   Source key to which to apply derivation.
 | 
					 | 
				
			||||||
 * @derived_key:  Derived key.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: Zero on success; non-zero otherwise.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int ext4_derive_key_aes(char deriving_key[EXT4_AES_128_ECB_KEY_SIZE],
 | 
					 | 
				
			||||||
			       char source_key[EXT4_AES_256_XTS_KEY_SIZE],
 | 
					 | 
				
			||||||
			       char derived_key[EXT4_AES_256_XTS_KEY_SIZE])
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int res = 0;
 | 
					 | 
				
			||||||
	struct skcipher_request *req = NULL;
 | 
					 | 
				
			||||||
	DECLARE_EXT4_COMPLETION_RESULT(ecr);
 | 
					 | 
				
			||||||
	struct scatterlist src_sg, dst_sg;
 | 
					 | 
				
			||||||
	struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (IS_ERR(tfm)) {
 | 
					 | 
				
			||||||
		res = PTR_ERR(tfm);
 | 
					 | 
				
			||||||
		tfm = NULL;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
 | 
					 | 
				
			||||||
	req = skcipher_request_alloc(tfm, GFP_NOFS);
 | 
					 | 
				
			||||||
	if (!req) {
 | 
					 | 
				
			||||||
		res = -ENOMEM;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	skcipher_request_set_callback(req,
 | 
					 | 
				
			||||||
			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
 | 
					 | 
				
			||||||
			derive_crypt_complete, &ecr);
 | 
					 | 
				
			||||||
	res = crypto_skcipher_setkey(tfm, deriving_key,
 | 
					 | 
				
			||||||
				     EXT4_AES_128_ECB_KEY_SIZE);
 | 
					 | 
				
			||||||
	if (res < 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	sg_init_one(&src_sg, source_key, EXT4_AES_256_XTS_KEY_SIZE);
 | 
					 | 
				
			||||||
	sg_init_one(&dst_sg, derived_key, EXT4_AES_256_XTS_KEY_SIZE);
 | 
					 | 
				
			||||||
	skcipher_request_set_crypt(req, &src_sg, &dst_sg,
 | 
					 | 
				
			||||||
				   EXT4_AES_256_XTS_KEY_SIZE, NULL);
 | 
					 | 
				
			||||||
	res = crypto_skcipher_encrypt(req);
 | 
					 | 
				
			||||||
	if (res == -EINPROGRESS || res == -EBUSY) {
 | 
					 | 
				
			||||||
		wait_for_completion(&ecr.completion);
 | 
					 | 
				
			||||||
		res = ecr.res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	skcipher_request_free(req);
 | 
					 | 
				
			||||||
	crypto_free_skcipher(tfm);
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ext4_free_crypt_info(struct ext4_crypt_info *ci)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (!ci)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ci->ci_keyring_key)
 | 
					 | 
				
			||||||
		key_put(ci->ci_keyring_key);
 | 
					 | 
				
			||||||
	crypto_free_skcipher(ci->ci_ctfm);
 | 
					 | 
				
			||||||
	kmem_cache_free(ext4_crypt_info_cachep, ci);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ext4_free_encryption_info(struct inode *inode,
 | 
					 | 
				
			||||||
			       struct ext4_crypt_info *ci)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_inode_info *ei = EXT4_I(inode);
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *prev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ci == NULL)
 | 
					 | 
				
			||||||
		ci = ACCESS_ONCE(ei->i_crypt_info);
 | 
					 | 
				
			||||||
	if (ci == NULL)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	prev = cmpxchg(&ei->i_crypt_info, ci, NULL);
 | 
					 | 
				
			||||||
	if (prev != ci)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ext4_free_crypt_info(ci);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int _ext4_get_encryption_info(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_inode_info *ei = EXT4_I(inode);
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *crypt_info;
 | 
					 | 
				
			||||||
	char full_key_descriptor[EXT4_KEY_DESC_PREFIX_SIZE +
 | 
					 | 
				
			||||||
				 (EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1];
 | 
					 | 
				
			||||||
	struct key *keyring_key = NULL;
 | 
					 | 
				
			||||||
	struct ext4_encryption_key *master_key;
 | 
					 | 
				
			||||||
	struct ext4_encryption_context ctx;
 | 
					 | 
				
			||||||
	const struct user_key_payload *ukp;
 | 
					 | 
				
			||||||
	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 | 
					 | 
				
			||||||
	struct crypto_skcipher *ctfm;
 | 
					 | 
				
			||||||
	const char *cipher_str;
 | 
					 | 
				
			||||||
	char raw_key[EXT4_MAX_KEY_SIZE];
 | 
					 | 
				
			||||||
	char mode;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!ext4_read_workqueue) {
 | 
					 | 
				
			||||||
		res = ext4_init_crypto();
 | 
					 | 
				
			||||||
		if (res)
 | 
					 | 
				
			||||||
			return res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
retry:
 | 
					 | 
				
			||||||
	crypt_info = ACCESS_ONCE(ei->i_crypt_info);
 | 
					 | 
				
			||||||
	if (crypt_info) {
 | 
					 | 
				
			||||||
		if (!crypt_info->ci_keyring_key ||
 | 
					 | 
				
			||||||
		    key_validate(crypt_info->ci_keyring_key) == 0)
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		ext4_free_encryption_info(inode, crypt_info);
 | 
					 | 
				
			||||||
		goto retry;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
					 | 
				
			||||||
				 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
 | 
					 | 
				
			||||||
				 &ctx, sizeof(ctx));
 | 
					 | 
				
			||||||
	if (res < 0) {
 | 
					 | 
				
			||||||
		if (!DUMMY_ENCRYPTION_ENABLED(sbi))
 | 
					 | 
				
			||||||
			return res;
 | 
					 | 
				
			||||||
		ctx.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
 | 
					 | 
				
			||||||
		ctx.filenames_encryption_mode =
 | 
					 | 
				
			||||||
			EXT4_ENCRYPTION_MODE_AES_256_CTS;
 | 
					 | 
				
			||||||
		ctx.flags = 0;
 | 
					 | 
				
			||||||
	} else if (res != sizeof(ctx))
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	res = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	crypt_info = kmem_cache_alloc(ext4_crypt_info_cachep, GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!crypt_info)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	crypt_info->ci_flags = ctx.flags;
 | 
					 | 
				
			||||||
	crypt_info->ci_data_mode = ctx.contents_encryption_mode;
 | 
					 | 
				
			||||||
	crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
 | 
					 | 
				
			||||||
	crypt_info->ci_ctfm = NULL;
 | 
					 | 
				
			||||||
	crypt_info->ci_keyring_key = NULL;
 | 
					 | 
				
			||||||
	memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
 | 
					 | 
				
			||||||
	       sizeof(crypt_info->ci_master_key));
 | 
					 | 
				
			||||||
	if (S_ISREG(inode->i_mode))
 | 
					 | 
				
			||||||
		mode = crypt_info->ci_data_mode;
 | 
					 | 
				
			||||||
	else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
 | 
					 | 
				
			||||||
		mode = crypt_info->ci_filename_mode;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		BUG();
 | 
					 | 
				
			||||||
	switch (mode) {
 | 
					 | 
				
			||||||
	case EXT4_ENCRYPTION_MODE_AES_256_XTS:
 | 
					 | 
				
			||||||
		cipher_str = "xts(aes)";
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case EXT4_ENCRYPTION_MODE_AES_256_CTS:
 | 
					 | 
				
			||||||
		cipher_str = "cts(cbc(aes))";
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		printk_once(KERN_WARNING
 | 
					 | 
				
			||||||
			    "ext4: unsupported key mode %d (ino %u)\n",
 | 
					 | 
				
			||||||
			    mode, (unsigned) inode->i_ino);
 | 
					 | 
				
			||||||
		res = -ENOKEY;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (DUMMY_ENCRYPTION_ENABLED(sbi)) {
 | 
					 | 
				
			||||||
		memset(raw_key, 0x42, EXT4_AES_256_XTS_KEY_SIZE);
 | 
					 | 
				
			||||||
		goto got_key;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX,
 | 
					 | 
				
			||||||
	       EXT4_KEY_DESC_PREFIX_SIZE);
 | 
					 | 
				
			||||||
	sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE,
 | 
					 | 
				
			||||||
		"%*phN", EXT4_KEY_DESCRIPTOR_SIZE,
 | 
					 | 
				
			||||||
		ctx.master_key_descriptor);
 | 
					 | 
				
			||||||
	full_key_descriptor[EXT4_KEY_DESC_PREFIX_SIZE +
 | 
					 | 
				
			||||||
			    (2 * EXT4_KEY_DESCRIPTOR_SIZE)] = '\0';
 | 
					 | 
				
			||||||
	keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
 | 
					 | 
				
			||||||
	if (IS_ERR(keyring_key)) {
 | 
					 | 
				
			||||||
		res = PTR_ERR(keyring_key);
 | 
					 | 
				
			||||||
		keyring_key = NULL;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	crypt_info->ci_keyring_key = keyring_key;
 | 
					 | 
				
			||||||
	if (keyring_key->type != &key_type_logon) {
 | 
					 | 
				
			||||||
		printk_once(KERN_WARNING
 | 
					 | 
				
			||||||
			    "ext4: key type must be logon\n");
 | 
					 | 
				
			||||||
		res = -ENOKEY;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	down_read(&keyring_key->sem);
 | 
					 | 
				
			||||||
	ukp = user_key_payload(keyring_key);
 | 
					 | 
				
			||||||
	if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
 | 
					 | 
				
			||||||
		res = -EINVAL;
 | 
					 | 
				
			||||||
		up_read(&keyring_key->sem);
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	master_key = (struct ext4_encryption_key *)ukp->data;
 | 
					 | 
				
			||||||
	BUILD_BUG_ON(EXT4_AES_128_ECB_KEY_SIZE !=
 | 
					 | 
				
			||||||
		     EXT4_KEY_DERIVATION_NONCE_SIZE);
 | 
					 | 
				
			||||||
	if (master_key->size != EXT4_AES_256_XTS_KEY_SIZE) {
 | 
					 | 
				
			||||||
		printk_once(KERN_WARNING
 | 
					 | 
				
			||||||
			    "ext4: key size incorrect: %d\n",
 | 
					 | 
				
			||||||
			    master_key->size);
 | 
					 | 
				
			||||||
		res = -ENOKEY;
 | 
					 | 
				
			||||||
		up_read(&keyring_key->sem);
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	res = ext4_derive_key_aes(ctx.nonce, master_key->raw,
 | 
					 | 
				
			||||||
				  raw_key);
 | 
					 | 
				
			||||||
	up_read(&keyring_key->sem);
 | 
					 | 
				
			||||||
	if (res)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
got_key:
 | 
					 | 
				
			||||||
	ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
 | 
					 | 
				
			||||||
	if (!ctfm || IS_ERR(ctfm)) {
 | 
					 | 
				
			||||||
		res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
 | 
					 | 
				
			||||||
		printk(KERN_DEBUG
 | 
					 | 
				
			||||||
		       "%s: error %d (inode %u) allocating crypto tfm\n",
 | 
					 | 
				
			||||||
		       __func__, res, (unsigned) inode->i_ino);
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	crypt_info->ci_ctfm = ctfm;
 | 
					 | 
				
			||||||
	crypto_skcipher_clear_flags(ctfm, ~0);
 | 
					 | 
				
			||||||
	crypto_tfm_set_flags(crypto_skcipher_tfm(ctfm),
 | 
					 | 
				
			||||||
			     CRYPTO_TFM_REQ_WEAK_KEY);
 | 
					 | 
				
			||||||
	res = crypto_skcipher_setkey(ctfm, raw_key,
 | 
					 | 
				
			||||||
				     ext4_encryption_key_size(mode));
 | 
					 | 
				
			||||||
	if (res)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	memzero_explicit(raw_key, sizeof(raw_key));
 | 
					 | 
				
			||||||
	if (cmpxchg(&ei->i_crypt_info, NULL, crypt_info) != NULL) {
 | 
					 | 
				
			||||||
		ext4_free_crypt_info(crypt_info);
 | 
					 | 
				
			||||||
		goto retry;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	if (res == -ENOKEY)
 | 
					 | 
				
			||||||
		res = 0;
 | 
					 | 
				
			||||||
	ext4_free_crypt_info(crypt_info);
 | 
					 | 
				
			||||||
	memzero_explicit(raw_key, sizeof(raw_key));
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ext4_has_encryption_key(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_inode_info *ei = EXT4_I(inode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (ei->i_crypt_info != NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,229 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * linux/fs/ext4/crypto_policy.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2015, Google, Inc.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This contains encryption policy functions for ext4
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Written by Michael Halcrow, 2015.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/random.h>
 | 
					 | 
				
			||||||
#include <linux/string.h>
 | 
					 | 
				
			||||||
#include <linux/types.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ext4_jbd2.h"
 | 
					 | 
				
			||||||
#include "ext4.h"
 | 
					 | 
				
			||||||
#include "xattr.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ext4_inode_has_encryption_context(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
					 | 
				
			||||||
				 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0);
 | 
					 | 
				
			||||||
	return (res > 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * check whether the policy is consistent with the encryption context
 | 
					 | 
				
			||||||
 * for the inode
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int ext4_is_encryption_context_consistent_with_policy(
 | 
					 | 
				
			||||||
	struct inode *inode, const struct ext4_encryption_policy *policy)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_encryption_context ctx;
 | 
					 | 
				
			||||||
	int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
					 | 
				
			||||||
				 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
 | 
					 | 
				
			||||||
				 sizeof(ctx));
 | 
					 | 
				
			||||||
	if (res != sizeof(ctx))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
 | 
					 | 
				
			||||||
			EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
 | 
					 | 
				
			||||||
		(ctx.flags ==
 | 
					 | 
				
			||||||
		 policy->flags) &&
 | 
					 | 
				
			||||||
		(ctx.contents_encryption_mode ==
 | 
					 | 
				
			||||||
		 policy->contents_encryption_mode) &&
 | 
					 | 
				
			||||||
		(ctx.filenames_encryption_mode ==
 | 
					 | 
				
			||||||
		 policy->filenames_encryption_mode));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ext4_create_encryption_context_from_policy(
 | 
					 | 
				
			||||||
	struct inode *inode, const struct ext4_encryption_policy *policy)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_encryption_context ctx;
 | 
					 | 
				
			||||||
	handle_t *handle;
 | 
					 | 
				
			||||||
	int res, res2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	res = ext4_convert_inline_data(inode);
 | 
					 | 
				
			||||||
	if (res)
 | 
					 | 
				
			||||||
		return res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
 | 
					 | 
				
			||||||
	memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
 | 
					 | 
				
			||||||
	       EXT4_KEY_DESCRIPTOR_SIZE);
 | 
					 | 
				
			||||||
	if (!ext4_valid_contents_enc_mode(policy->contents_encryption_mode)) {
 | 
					 | 
				
			||||||
		printk(KERN_WARNING
 | 
					 | 
				
			||||||
		       "%s: Invalid contents encryption mode %d\n", __func__,
 | 
					 | 
				
			||||||
			policy->contents_encryption_mode);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!ext4_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
 | 
					 | 
				
			||||||
		printk(KERN_WARNING
 | 
					 | 
				
			||||||
		       "%s: Invalid filenames encryption mode %d\n", __func__,
 | 
					 | 
				
			||||||
			policy->filenames_encryption_mode);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (policy->flags & ~EXT4_POLICY_FLAGS_VALID)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	ctx.contents_encryption_mode = policy->contents_encryption_mode;
 | 
					 | 
				
			||||||
	ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
 | 
					 | 
				
			||||||
	ctx.flags = policy->flags;
 | 
					 | 
				
			||||||
	BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE);
 | 
					 | 
				
			||||||
	get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	handle = ext4_journal_start(inode, EXT4_HT_MISC,
 | 
					 | 
				
			||||||
				    ext4_jbd2_credits_xattr(inode));
 | 
					 | 
				
			||||||
	if (IS_ERR(handle))
 | 
					 | 
				
			||||||
		return PTR_ERR(handle);
 | 
					 | 
				
			||||||
	res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
					 | 
				
			||||||
			     EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
 | 
					 | 
				
			||||||
			     sizeof(ctx), 0);
 | 
					 | 
				
			||||||
	if (!res) {
 | 
					 | 
				
			||||||
		ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
 | 
					 | 
				
			||||||
		res = ext4_mark_inode_dirty(handle, inode);
 | 
					 | 
				
			||||||
		if (res)
 | 
					 | 
				
			||||||
			EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	res2 = ext4_journal_stop(handle);
 | 
					 | 
				
			||||||
	if (!res)
 | 
					 | 
				
			||||||
		res = res2;
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ext4_process_policy(const struct ext4_encryption_policy *policy,
 | 
					 | 
				
			||||||
			struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (policy->version != 0)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!ext4_inode_has_encryption_context(inode)) {
 | 
					 | 
				
			||||||
		if (!S_ISDIR(inode->i_mode))
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		if (!ext4_empty_dir(inode))
 | 
					 | 
				
			||||||
			return -ENOTEMPTY;
 | 
					 | 
				
			||||||
		return ext4_create_encryption_context_from_policy(inode,
 | 
					 | 
				
			||||||
								  policy);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ext4_is_encryption_context_consistent_with_policy(inode, policy))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n",
 | 
					 | 
				
			||||||
	       __func__);
 | 
					 | 
				
			||||||
	return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ext4_get_policy(struct inode *inode, struct ext4_encryption_policy *policy)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_encryption_context ctx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
					 | 
				
			||||||
				 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
 | 
					 | 
				
			||||||
				 &ctx, sizeof(ctx));
 | 
					 | 
				
			||||||
	if (res != sizeof(ctx))
 | 
					 | 
				
			||||||
		return -ENOENT;
 | 
					 | 
				
			||||||
	if (ctx.format != EXT4_ENCRYPTION_CONTEXT_FORMAT_V1)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	policy->version = 0;
 | 
					 | 
				
			||||||
	policy->contents_encryption_mode = ctx.contents_encryption_mode;
 | 
					 | 
				
			||||||
	policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
 | 
					 | 
				
			||||||
	policy->flags = ctx.flags;
 | 
					 | 
				
			||||||
	memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
 | 
					 | 
				
			||||||
	       EXT4_KEY_DESCRIPTOR_SIZE);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ext4_is_child_context_consistent_with_parent(struct inode *parent,
 | 
					 | 
				
			||||||
						 struct inode *child)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *parent_ci, *child_ci;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((parent == NULL) || (child == NULL)) {
 | 
					 | 
				
			||||||
		pr_err("parent %p child %p\n", parent, child);
 | 
					 | 
				
			||||||
		WARN_ON(1);	/* Should never happen */
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* no restrictions if the parent directory is not encrypted */
 | 
					 | 
				
			||||||
	if (!ext4_encrypted_inode(parent))
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	/* if the child directory is not encrypted, this is always a problem */
 | 
					 | 
				
			||||||
	if (!ext4_encrypted_inode(child))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	res = ext4_get_encryption_info(parent);
 | 
					 | 
				
			||||||
	if (res)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	res = ext4_get_encryption_info(child);
 | 
					 | 
				
			||||||
	if (res)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	parent_ci = EXT4_I(parent)->i_crypt_info;
 | 
					 | 
				
			||||||
	child_ci = EXT4_I(child)->i_crypt_info;
 | 
					 | 
				
			||||||
	if (!parent_ci && !child_ci)
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	if (!parent_ci || !child_ci)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (memcmp(parent_ci->ci_master_key,
 | 
					 | 
				
			||||||
		       child_ci->ci_master_key,
 | 
					 | 
				
			||||||
		       EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
 | 
					 | 
				
			||||||
		(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
 | 
					 | 
				
			||||||
		(parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
 | 
					 | 
				
			||||||
		(parent_ci->ci_flags == child_ci->ci_flags));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * ext4_inherit_context() - Sets a child context from its parent
 | 
					 | 
				
			||||||
 * @parent: Parent inode from which the context is inherited.
 | 
					 | 
				
			||||||
 * @child:  Child inode that inherits the context from @parent.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Return: Zero on success, non-zero otherwise
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int ext4_inherit_context(struct inode *parent, struct inode *child)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_encryption_context ctx;
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	res = ext4_get_encryption_info(parent);
 | 
					 | 
				
			||||||
	if (res < 0)
 | 
					 | 
				
			||||||
		return res;
 | 
					 | 
				
			||||||
	ci = EXT4_I(parent)->i_crypt_info;
 | 
					 | 
				
			||||||
	if (ci == NULL)
 | 
					 | 
				
			||||||
		return -ENOKEY;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
 | 
					 | 
				
			||||||
	if (DUMMY_ENCRYPTION_ENABLED(EXT4_SB(parent->i_sb))) {
 | 
					 | 
				
			||||||
		ctx.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
 | 
					 | 
				
			||||||
		ctx.filenames_encryption_mode =
 | 
					 | 
				
			||||||
			EXT4_ENCRYPTION_MODE_AES_256_CTS;
 | 
					 | 
				
			||||||
		ctx.flags = 0;
 | 
					 | 
				
			||||||
		memset(ctx.master_key_descriptor, 0x42,
 | 
					 | 
				
			||||||
		       EXT4_KEY_DESCRIPTOR_SIZE);
 | 
					 | 
				
			||||||
		res = 0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ctx.contents_encryption_mode = ci->ci_data_mode;
 | 
					 | 
				
			||||||
		ctx.filenames_encryption_mode = ci->ci_filename_mode;
 | 
					 | 
				
			||||||
		ctx.flags = ci->ci_flags;
 | 
					 | 
				
			||||||
		memcpy(ctx.master_key_descriptor, ci->ci_master_key,
 | 
					 | 
				
			||||||
		       EXT4_KEY_DESCRIPTOR_SIZE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
 | 
					 | 
				
			||||||
	res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
					 | 
				
			||||||
			     EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
 | 
					 | 
				
			||||||
			     sizeof(ctx), 0);
 | 
					 | 
				
			||||||
	if (!res) {
 | 
					 | 
				
			||||||
		ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT);
 | 
					 | 
				
			||||||
		ext4_clear_inode_state(child, EXT4_STATE_MAY_INLINE_DATA);
 | 
					 | 
				
			||||||
		res = ext4_get_encryption_info(child);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -109,10 +109,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
 | 
				
			||||||
	struct super_block *sb = inode->i_sb;
 | 
						struct super_block *sb = inode->i_sb;
 | 
				
			||||||
	struct buffer_head *bh = NULL;
 | 
						struct buffer_head *bh = NULL;
 | 
				
			||||||
	int dir_has_error = 0;
 | 
						int dir_has_error = 0;
 | 
				
			||||||
	struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
 | 
						struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ext4_encrypted_inode(inode)) {
 | 
						if (ext4_encrypted_inode(inode)) {
 | 
				
			||||||
		err = ext4_get_encryption_info(inode);
 | 
							err = fscrypt_get_encryption_info(inode);
 | 
				
			||||||
		if (err && err != -ENOKEY)
 | 
							if (err && err != -ENOKEY)
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -139,8 +139,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ext4_encrypted_inode(inode)) {
 | 
						if (ext4_encrypted_inode(inode)) {
 | 
				
			||||||
		err = ext4_fname_crypto_alloc_buffer(inode, EXT4_NAME_LEN,
 | 
							err = fscrypt_fname_alloc_buffer(inode, EXT4_NAME_LEN, &fstr);
 | 
				
			||||||
						     &fname_crypto_str);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -253,16 +252,19 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
 | 
				
			||||||
					    get_dtype(sb, de->file_type)))
 | 
										    get_dtype(sb, de->file_type)))
 | 
				
			||||||
						goto done;
 | 
											goto done;
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					int save_len = fname_crypto_str.len;
 | 
										int save_len = fstr.len;
 | 
				
			||||||
 | 
										struct fscrypt_str de_name =
 | 
				
			||||||
 | 
												FSTR_INIT(de->name,
 | 
				
			||||||
 | 
													de->name_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					/* Directory is encrypted */
 | 
										/* Directory is encrypted */
 | 
				
			||||||
					err = ext4_fname_disk_to_usr(inode,
 | 
										err = fscrypt_fname_disk_to_usr(inode,
 | 
				
			||||||
						NULL, de, &fname_crypto_str);
 | 
											0, 0, &de_name, &fstr);
 | 
				
			||||||
					fname_crypto_str.len = save_len;
 | 
										fstr.len = save_len;
 | 
				
			||||||
					if (err < 0)
 | 
										if (err < 0)
 | 
				
			||||||
						goto errout;
 | 
											goto errout;
 | 
				
			||||||
					if (!dir_emit(ctx,
 | 
										if (!dir_emit(ctx,
 | 
				
			||||||
					    fname_crypto_str.name, err,
 | 
										    fstr.name, err,
 | 
				
			||||||
					    le32_to_cpu(de->inode),
 | 
										    le32_to_cpu(de->inode),
 | 
				
			||||||
					    get_dtype(sb, de->file_type)))
 | 
										    get_dtype(sb, de->file_type)))
 | 
				
			||||||
						goto done;
 | 
											goto done;
 | 
				
			||||||
| 
						 | 
					@ -281,7 +283,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
 | 
				
			||||||
	err = 0;
 | 
						err = 0;
 | 
				
			||||||
errout:
 | 
					errout:
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
	ext4_fname_crypto_free_buffer(&fname_crypto_str);
 | 
						fscrypt_fname_free_buffer(&fstr);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	brelse(bh);
 | 
						brelse(bh);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -432,7 +434,7 @@ void ext4_htree_free_dir_info(struct dir_private_info *p)
 | 
				
			||||||
int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 | 
					int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 | 
				
			||||||
			     __u32 minor_hash,
 | 
								     __u32 minor_hash,
 | 
				
			||||||
			    struct ext4_dir_entry_2 *dirent,
 | 
								    struct ext4_dir_entry_2 *dirent,
 | 
				
			||||||
			    struct ext4_str *ent_name)
 | 
								    struct fscrypt_str *ent_name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rb_node **p, *parent = NULL;
 | 
						struct rb_node **p, *parent = NULL;
 | 
				
			||||||
	struct fname *fname, *new_fn;
 | 
						struct fname *fname, *new_fn;
 | 
				
			||||||
| 
						 | 
					@ -609,7 +611,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
 | 
				
			||||||
static int ext4_dir_open(struct inode * inode, struct file * filp)
 | 
					static int ext4_dir_open(struct inode * inode, struct file * filp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (ext4_encrypted_inode(inode))
 | 
						if (ext4_encrypted_inode(inode))
 | 
				
			||||||
		return ext4_get_encryption_info(inode) ? -EACCES : 0;
 | 
							return fscrypt_get_encryption_info(inode) ? -EACCES : 0;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										216
									
								
								fs/ext4/ext4.h
									
									
									
									
									
								
							
							
						
						
									
										216
									
								
								fs/ext4/ext4.h
									
									
									
									
									
								
							| 
						 | 
					@ -32,6 +32,7 @@
 | 
				
			||||||
#include <linux/percpu_counter.h>
 | 
					#include <linux/percpu_counter.h>
 | 
				
			||||||
#include <linux/ratelimit.h>
 | 
					#include <linux/ratelimit.h>
 | 
				
			||||||
#include <crypto/hash.h>
 | 
					#include <crypto/hash.h>
 | 
				
			||||||
 | 
					#include <linux/fscrypto.h>
 | 
				
			||||||
#include <linux/falloc.h>
 | 
					#include <linux/falloc.h>
 | 
				
			||||||
#include <linux/percpu-rwsem.h>
 | 
					#include <linux/percpu-rwsem.h>
 | 
				
			||||||
#ifdef __KERNEL__
 | 
					#ifdef __KERNEL__
 | 
				
			||||||
| 
						 | 
					@ -608,15 +609,6 @@ enum {
 | 
				
			||||||
#define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER	0x0010
 | 
					#define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER	0x0010
 | 
				
			||||||
#define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER	0x0020
 | 
					#define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER	0x0020
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Encryption algorithms */
 | 
					 | 
				
			||||||
#define EXT4_ENCRYPTION_MODE_INVALID		0
 | 
					 | 
				
			||||||
#define EXT4_ENCRYPTION_MODE_AES_256_XTS	1
 | 
					 | 
				
			||||||
#define EXT4_ENCRYPTION_MODE_AES_256_GCM	2
 | 
					 | 
				
			||||||
#define EXT4_ENCRYPTION_MODE_AES_256_CBC	3
 | 
					 | 
				
			||||||
#define EXT4_ENCRYPTION_MODE_AES_256_CTS	4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ext4_crypto.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * ioctl commands
 | 
					 * ioctl commands
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -638,9 +630,9 @@ enum {
 | 
				
			||||||
#define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
 | 
					#define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
 | 
				
			||||||
#define EXT4_IOC_SWAP_BOOT		_IO('f', 17)
 | 
					#define EXT4_IOC_SWAP_BOOT		_IO('f', 17)
 | 
				
			||||||
#define EXT4_IOC_PRECACHE_EXTENTS	_IO('f', 18)
 | 
					#define EXT4_IOC_PRECACHE_EXTENTS	_IO('f', 18)
 | 
				
			||||||
#define EXT4_IOC_SET_ENCRYPTION_POLICY	_IOR('f', 19, struct ext4_encryption_policy)
 | 
					#define EXT4_IOC_SET_ENCRYPTION_POLICY	FS_IOC_SET_ENCRYPTION_POLICY
 | 
				
			||||||
#define EXT4_IOC_GET_ENCRYPTION_PWSALT	_IOW('f', 20, __u8[16])
 | 
					#define EXT4_IOC_GET_ENCRYPTION_PWSALT	FS_IOC_GET_ENCRYPTION_PWSALT
 | 
				
			||||||
#define EXT4_IOC_GET_ENCRYPTION_POLICY	_IOW('f', 21, struct ext4_encryption_policy)
 | 
					#define EXT4_IOC_GET_ENCRYPTION_POLICY	FS_IOC_GET_ENCRYPTION_POLICY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef FS_IOC_FSGETXATTR
 | 
					#ifndef FS_IOC_FSGETXATTR
 | 
				
			||||||
/* Until the uapi changes get merged for project quota... */
 | 
					/* Until the uapi changes get merged for project quota... */
 | 
				
			||||||
| 
						 | 
					@ -1082,10 +1074,6 @@ struct ext4_inode_info {
 | 
				
			||||||
	/* Precomputed uuid+inum+igen checksum for seeding inode checksums */
 | 
						/* Precomputed uuid+inum+igen checksum for seeding inode checksums */
 | 
				
			||||||
	__u32 i_csum_seed;
 | 
						__u32 i_csum_seed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
	/* Encryption params */
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *i_crypt_info;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	kprojid_t i_projid;
 | 
						kprojid_t i_projid;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1344,6 +1332,11 @@ struct ext4_super_block {
 | 
				
			||||||
/* Number of quota types we support */
 | 
					/* Number of quota types we support */
 | 
				
			||||||
#define EXT4_MAXQUOTAS 3
 | 
					#define EXT4_MAXQUOTAS 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
 | 
					#define EXT4_KEY_DESC_PREFIX "ext4:"
 | 
				
			||||||
 | 
					#define EXT4_KEY_DESC_PREFIX_SIZE 5
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * fourth extended-fs super-block data in memory
 | 
					 * fourth extended-fs super-block data in memory
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -1513,6 +1506,12 @@ struct ext4_sb_info {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Barrier between changing inodes' journal flags and writepages ops. */
 | 
						/* Barrier between changing inodes' journal flags and writepages ops. */
 | 
				
			||||||
	struct percpu_rw_semaphore s_journal_flag_rwsem;
 | 
						struct percpu_rw_semaphore s_journal_flag_rwsem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Encryption support */
 | 
				
			||||||
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
 | 
						u8 key_prefix[EXT4_KEY_DESC_PREFIX_SIZE];
 | 
				
			||||||
 | 
						u8 key_prefix_size;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
 | 
					static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
 | 
				
			||||||
| 
						 | 
					@ -1611,15 +1610,6 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Returns true if the inode is inode is encrypted
 | 
					 * Returns true if the inode is inode is encrypted
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline int ext4_encrypted_inode(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
	return ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
 | 
					#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -2083,10 +2073,10 @@ struct dx_hash_info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ext4_filename {
 | 
					struct ext4_filename {
 | 
				
			||||||
	const struct qstr *usr_fname;
 | 
						const struct qstr *usr_fname;
 | 
				
			||||||
	struct ext4_str disk_name;
 | 
						struct fscrypt_str disk_name;
 | 
				
			||||||
	struct dx_hash_info hinfo;
 | 
						struct dx_hash_info hinfo;
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
	struct ext4_str crypto_buf;
 | 
						struct fscrypt_str crypto_buf;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2297,78 +2287,48 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
 | 
				
			||||||
					      struct ext4_group_desc *gdp);
 | 
										      struct ext4_group_desc *gdp);
 | 
				
			||||||
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
 | 
					ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* crypto_policy.c */
 | 
					 | 
				
			||||||
int ext4_is_child_context_consistent_with_parent(struct inode *parent,
 | 
					 | 
				
			||||||
						 struct inode *child);
 | 
					 | 
				
			||||||
int ext4_inherit_context(struct inode *parent, struct inode *child);
 | 
					 | 
				
			||||||
void ext4_to_hex(char *dst, char *src, size_t src_size);
 | 
					 | 
				
			||||||
int ext4_process_policy(const struct ext4_encryption_policy *policy,
 | 
					 | 
				
			||||||
			struct inode *inode);
 | 
					 | 
				
			||||||
int ext4_get_policy(struct inode *inode,
 | 
					 | 
				
			||||||
		    struct ext4_encryption_policy *policy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* crypto.c */
 | 
					 | 
				
			||||||
extern struct kmem_cache *ext4_crypt_info_cachep;
 | 
					 | 
				
			||||||
bool ext4_valid_contents_enc_mode(uint32_t mode);
 | 
					 | 
				
			||||||
uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size);
 | 
					 | 
				
			||||||
extern struct workqueue_struct *ext4_read_workqueue;
 | 
					 | 
				
			||||||
struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
 | 
					 | 
				
			||||||
					    gfp_t gfp_flags);
 | 
					 | 
				
			||||||
void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx);
 | 
					 | 
				
			||||||
void ext4_restore_control_page(struct page *data_page);
 | 
					 | 
				
			||||||
struct page *ext4_encrypt(struct inode *inode,
 | 
					 | 
				
			||||||
			  struct page *plaintext_page,
 | 
					 | 
				
			||||||
			  gfp_t gfp_flags);
 | 
					 | 
				
			||||||
int ext4_decrypt(struct page *page);
 | 
					 | 
				
			||||||
int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk,
 | 
					 | 
				
			||||||
			   ext4_fsblk_t pblk, ext4_lblk_t len);
 | 
					 | 
				
			||||||
extern const struct dentry_operations ext4_encrypted_d_ops;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
int ext4_init_crypto(void);
 | 
					 | 
				
			||||||
void ext4_exit_crypto(void);
 | 
					 | 
				
			||||||
static inline int ext4_sb_has_crypto(struct super_block *sb)
 | 
					static inline int ext4_sb_has_crypto(struct super_block *sb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return ext4_has_feature_encrypt(sb);
 | 
						return ext4_has_feature_encrypt(sb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static inline int ext4_init_crypto(void) { return 0; }
 | 
					 | 
				
			||||||
static inline void ext4_exit_crypto(void) { }
 | 
					 | 
				
			||||||
static inline int ext4_sb_has_crypto(struct super_block *sb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* crypto_fname.c */
 | 
					static inline bool ext4_encrypted_inode(struct inode *inode)
 | 
				
			||||||
bool ext4_valid_filenames_enc_mode(uint32_t mode);
 | 
					 | 
				
			||||||
u32 ext4_fname_crypto_round_up(u32 size, u32 blksize);
 | 
					 | 
				
			||||||
unsigned ext4_fname_encrypted_size(struct inode *inode, u32 ilen);
 | 
					 | 
				
			||||||
int ext4_fname_crypto_alloc_buffer(struct inode *inode,
 | 
					 | 
				
			||||||
				   u32 ilen, struct ext4_str *crypto_str);
 | 
					 | 
				
			||||||
int _ext4_fname_disk_to_usr(struct inode *inode,
 | 
					 | 
				
			||||||
			    struct dx_hash_info *hinfo,
 | 
					 | 
				
			||||||
			    const struct ext4_str *iname,
 | 
					 | 
				
			||||||
			    struct ext4_str *oname);
 | 
					 | 
				
			||||||
int ext4_fname_disk_to_usr(struct inode *inode,
 | 
					 | 
				
			||||||
			   struct dx_hash_info *hinfo,
 | 
					 | 
				
			||||||
			   const struct ext4_dir_entry_2 *de,
 | 
					 | 
				
			||||||
			   struct ext4_str *oname);
 | 
					 | 
				
			||||||
int ext4_fname_usr_to_disk(struct inode *inode,
 | 
					 | 
				
			||||||
			   const struct qstr *iname,
 | 
					 | 
				
			||||||
			   struct ext4_str *oname);
 | 
					 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str);
 | 
					 | 
				
			||||||
int ext4_fname_setup_filename(struct inode *dir, const struct qstr *iname,
 | 
					 | 
				
			||||||
			      int lookup, struct ext4_filename *fname);
 | 
					 | 
				
			||||||
void ext4_fname_free_filename(struct ext4_filename *fname);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static inline
 | 
					 | 
				
			||||||
int ext4_setup_fname_crypto(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline void ext4_fname_crypto_free_buffer(struct ext4_str *p) { }
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
 | 
					static inline int ext4_fname_setup_filename(struct inode *dir,
 | 
				
			||||||
 | 
								const struct qstr *iname,
 | 
				
			||||||
 | 
								int lookup, struct ext4_filename *fname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct fscrypt_name name;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(fname, 0, sizeof(struct ext4_filename));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = fscrypt_setup_filename(dir, iname, lookup, &name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fname->usr_fname = name.usr_fname;
 | 
				
			||||||
 | 
						fname->disk_name = name.disk_name;
 | 
				
			||||||
 | 
						fname->hinfo.hash = name.hash;
 | 
				
			||||||
 | 
						fname->hinfo.minor_hash = name.minor_hash;
 | 
				
			||||||
 | 
						fname->crypto_buf = name.crypto_buf;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void ext4_fname_free_filename(struct ext4_filename *fname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct fscrypt_name name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						name.crypto_buf = fname->crypto_buf;
 | 
				
			||||||
 | 
						fscrypt_free_filename(&name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fname->crypto_buf.name = NULL;
 | 
				
			||||||
 | 
						fname->usr_fname = NULL;
 | 
				
			||||||
 | 
						fname->disk_name.name = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
static inline int ext4_fname_setup_filename(struct inode *dir,
 | 
					static inline int ext4_fname_setup_filename(struct inode *dir,
 | 
				
			||||||
		const struct qstr *iname,
 | 
							const struct qstr *iname,
 | 
				
			||||||
		int lookup, struct ext4_filename *fname)
 | 
							int lookup, struct ext4_filename *fname)
 | 
				
			||||||
| 
						 | 
					@ -2379,51 +2339,31 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
 | 
					static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define fscrypt_set_d_op(i)
 | 
				
			||||||
 | 
					#define fscrypt_get_ctx			fscrypt_notsupp_get_ctx
 | 
				
			||||||
 | 
					#define fscrypt_release_ctx		fscrypt_notsupp_release_ctx
 | 
				
			||||||
 | 
					#define fscrypt_encrypt_page		fscrypt_notsupp_encrypt_page
 | 
				
			||||||
 | 
					#define fscrypt_decrypt_page		fscrypt_notsupp_decrypt_page
 | 
				
			||||||
 | 
					#define fscrypt_decrypt_bio_pages	fscrypt_notsupp_decrypt_bio_pages
 | 
				
			||||||
 | 
					#define fscrypt_pullback_bio_page	fscrypt_notsupp_pullback_bio_page
 | 
				
			||||||
 | 
					#define fscrypt_restore_control_page	fscrypt_notsupp_restore_control_page
 | 
				
			||||||
 | 
					#define fscrypt_zeroout_range		fscrypt_notsupp_zeroout_range
 | 
				
			||||||
 | 
					#define fscrypt_process_policy		fscrypt_notsupp_process_policy
 | 
				
			||||||
 | 
					#define fscrypt_get_policy		fscrypt_notsupp_get_policy
 | 
				
			||||||
 | 
					#define fscrypt_has_permitted_context	fscrypt_notsupp_has_permitted_context
 | 
				
			||||||
 | 
					#define fscrypt_inherit_context		fscrypt_notsupp_inherit_context
 | 
				
			||||||
 | 
					#define fscrypt_get_encryption_info	fscrypt_notsupp_get_encryption_info
 | 
				
			||||||
 | 
					#define fscrypt_put_encryption_info	fscrypt_notsupp_put_encryption_info
 | 
				
			||||||
 | 
					#define fscrypt_setup_filename		fscrypt_notsupp_setup_filename
 | 
				
			||||||
 | 
					#define fscrypt_free_filename		fscrypt_notsupp_free_filename
 | 
				
			||||||
 | 
					#define fscrypt_fname_encrypted_size	fscrypt_notsupp_fname_encrypted_size
 | 
				
			||||||
 | 
					#define fscrypt_fname_alloc_buffer	fscrypt_notsupp_fname_alloc_buffer
 | 
				
			||||||
 | 
					#define fscrypt_fname_free_buffer	fscrypt_notsupp_fname_free_buffer
 | 
				
			||||||
 | 
					#define fscrypt_fname_disk_to_usr	fscrypt_notsupp_fname_disk_to_usr
 | 
				
			||||||
 | 
					#define fscrypt_fname_usr_to_disk	fscrypt_notsupp_fname_usr_to_disk
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* crypto_key.c */
 | 
					 | 
				
			||||||
void ext4_free_crypt_info(struct ext4_crypt_info *ci);
 | 
					 | 
				
			||||||
void ext4_free_encryption_info(struct inode *inode, struct ext4_crypt_info *ci);
 | 
					 | 
				
			||||||
int _ext4_get_encryption_info(struct inode *inode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
int ext4_has_encryption_key(struct inode *inode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int ext4_get_encryption_info(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!ci ||
 | 
					 | 
				
			||||||
	    (ci->ci_keyring_key &&
 | 
					 | 
				
			||||||
	     (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
 | 
					 | 
				
			||||||
					   (1 << KEY_FLAG_REVOKED) |
 | 
					 | 
				
			||||||
					   (1 << KEY_FLAG_DEAD)))))
 | 
					 | 
				
			||||||
		return _ext4_get_encryption_info(inode);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline struct ext4_crypt_info *ext4_encryption_info(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return EXT4_I(inode)->i_crypt_info;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static inline int ext4_has_encryption_key(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static inline int ext4_get_encryption_info(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static inline struct ext4_crypt_info *ext4_encryption_info(struct inode *inode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* dir.c */
 | 
					/* dir.c */
 | 
				
			||||||
extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
 | 
					extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
 | 
				
			||||||
				  struct file *,
 | 
									  struct file *,
 | 
				
			||||||
| 
						 | 
					@ -2436,7 +2376,7 @@ extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
 | 
				
			||||||
extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 | 
					extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 | 
				
			||||||
				__u32 minor_hash,
 | 
									__u32 minor_hash,
 | 
				
			||||||
				struct ext4_dir_entry_2 *dirent,
 | 
									struct ext4_dir_entry_2 *dirent,
 | 
				
			||||||
				struct ext4_str *ent_name);
 | 
									struct fscrypt_str *ent_name);
 | 
				
			||||||
extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 | 
					extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 | 
				
			||||||
extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
 | 
					extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
 | 
				
			||||||
			     struct buffer_head *bh,
 | 
								     struct buffer_head *bh,
 | 
				
			||||||
| 
						 | 
					@ -2624,7 +2564,7 @@ extern int ext4_generic_delete_entry(handle_t *handle,
 | 
				
			||||||
				     void *entry_buf,
 | 
									     void *entry_buf,
 | 
				
			||||||
				     int buf_size,
 | 
									     int buf_size,
 | 
				
			||||||
				     int csum_size);
 | 
									     int csum_size);
 | 
				
			||||||
extern int ext4_empty_dir(struct inode *inode);
 | 
					extern bool ext4_empty_dir(struct inode *inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* resize.c */
 | 
					/* resize.c */
 | 
				
			||||||
extern int ext4_group_add(struct super_block *sb,
 | 
					extern int ext4_group_add(struct super_block *sb,
 | 
				
			||||||
| 
						 | 
					@ -3106,7 +3046,7 @@ extern int ext4_delete_inline_entry(handle_t *handle,
 | 
				
			||||||
				    struct ext4_dir_entry_2 *de_del,
 | 
									    struct ext4_dir_entry_2 *de_del,
 | 
				
			||||||
				    struct buffer_head *bh,
 | 
									    struct buffer_head *bh,
 | 
				
			||||||
				    int *has_inline_data);
 | 
									    int *has_inline_data);
 | 
				
			||||||
extern int empty_inline_dir(struct inode *dir, int *has_inline_data);
 | 
					extern bool empty_inline_dir(struct inode *dir, int *has_inline_data);
 | 
				
			||||||
extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode,
 | 
					extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode,
 | 
				
			||||||
					struct ext4_dir_entry_2 **parent_de,
 | 
										struct ext4_dir_entry_2 **parent_de,
 | 
				
			||||||
					int *retval);
 | 
										int *retval);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,159 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * linux/fs/ext4/ext4_crypto.h
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2015, Google, Inc.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This contains encryption header content for ext4
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Written by Michael Halcrow, 2015.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _EXT4_CRYPTO_H
 | 
					 | 
				
			||||||
#define _EXT4_CRYPTO_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/fs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define EXT4_KEY_DESCRIPTOR_SIZE 8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Policy provided via an ioctl on the topmost directory */
 | 
					 | 
				
			||||||
struct ext4_encryption_policy {
 | 
					 | 
				
			||||||
	char version;
 | 
					 | 
				
			||||||
	char contents_encryption_mode;
 | 
					 | 
				
			||||||
	char filenames_encryption_mode;
 | 
					 | 
				
			||||||
	char flags;
 | 
					 | 
				
			||||||
	char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
 | 
					 | 
				
			||||||
} __attribute__((__packed__));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define EXT4_ENCRYPTION_CONTEXT_FORMAT_V1 1
 | 
					 | 
				
			||||||
#define EXT4_KEY_DERIVATION_NONCE_SIZE 16
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define EXT4_POLICY_FLAGS_PAD_4		0x00
 | 
					 | 
				
			||||||
#define EXT4_POLICY_FLAGS_PAD_8		0x01
 | 
					 | 
				
			||||||
#define EXT4_POLICY_FLAGS_PAD_16	0x02
 | 
					 | 
				
			||||||
#define EXT4_POLICY_FLAGS_PAD_32	0x03
 | 
					 | 
				
			||||||
#define EXT4_POLICY_FLAGS_PAD_MASK	0x03
 | 
					 | 
				
			||||||
#define EXT4_POLICY_FLAGS_VALID		0x03
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Encryption context for inode
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Protector format:
 | 
					 | 
				
			||||||
 *  1 byte: Protector format (1 = this version)
 | 
					 | 
				
			||||||
 *  1 byte: File contents encryption mode
 | 
					 | 
				
			||||||
 *  1 byte: File names encryption mode
 | 
					 | 
				
			||||||
 *  1 byte: Reserved
 | 
					 | 
				
			||||||
 *  8 bytes: Master Key descriptor
 | 
					 | 
				
			||||||
 *  16 bytes: Encryption Key derivation nonce
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct ext4_encryption_context {
 | 
					 | 
				
			||||||
	char format;
 | 
					 | 
				
			||||||
	char contents_encryption_mode;
 | 
					 | 
				
			||||||
	char filenames_encryption_mode;
 | 
					 | 
				
			||||||
	char flags;
 | 
					 | 
				
			||||||
	char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
 | 
					 | 
				
			||||||
	char nonce[EXT4_KEY_DERIVATION_NONCE_SIZE];
 | 
					 | 
				
			||||||
} __attribute__((__packed__));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Encryption parameters */
 | 
					 | 
				
			||||||
#define EXT4_XTS_TWEAK_SIZE 16
 | 
					 | 
				
			||||||
#define EXT4_AES_128_ECB_KEY_SIZE 16
 | 
					 | 
				
			||||||
#define EXT4_AES_256_GCM_KEY_SIZE 32
 | 
					 | 
				
			||||||
#define EXT4_AES_256_CBC_KEY_SIZE 32
 | 
					 | 
				
			||||||
#define EXT4_AES_256_CTS_KEY_SIZE 32
 | 
					 | 
				
			||||||
#define EXT4_AES_256_XTS_KEY_SIZE 64
 | 
					 | 
				
			||||||
#define EXT4_MAX_KEY_SIZE 64
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define EXT4_KEY_DESC_PREFIX "ext4:"
 | 
					 | 
				
			||||||
#define EXT4_KEY_DESC_PREFIX_SIZE 5
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* This is passed in from userspace into the kernel keyring */
 | 
					 | 
				
			||||||
struct ext4_encryption_key {
 | 
					 | 
				
			||||||
        __u32 mode;
 | 
					 | 
				
			||||||
        char raw[EXT4_MAX_KEY_SIZE];
 | 
					 | 
				
			||||||
        __u32 size;
 | 
					 | 
				
			||||||
} __attribute__((__packed__));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ext4_crypt_info {
 | 
					 | 
				
			||||||
	char		ci_data_mode;
 | 
					 | 
				
			||||||
	char		ci_filename_mode;
 | 
					 | 
				
			||||||
	char		ci_flags;
 | 
					 | 
				
			||||||
	struct crypto_skcipher *ci_ctfm;
 | 
					 | 
				
			||||||
	struct key	*ci_keyring_key;
 | 
					 | 
				
			||||||
	char		ci_master_key[EXT4_KEY_DESCRIPTOR_SIZE];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL             0x00000001
 | 
					 | 
				
			||||||
#define EXT4_WRITE_PATH_FL			      0x00000002
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ext4_crypto_ctx {
 | 
					 | 
				
			||||||
	union {
 | 
					 | 
				
			||||||
		struct {
 | 
					 | 
				
			||||||
			struct page *bounce_page;       /* Ciphertext page */
 | 
					 | 
				
			||||||
			struct page *control_page;      /* Original page  */
 | 
					 | 
				
			||||||
		} w;
 | 
					 | 
				
			||||||
		struct {
 | 
					 | 
				
			||||||
			struct bio *bio;
 | 
					 | 
				
			||||||
			struct work_struct work;
 | 
					 | 
				
			||||||
		} r;
 | 
					 | 
				
			||||||
		struct list_head free_list;     /* Free list */
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	char flags;                      /* Flags */
 | 
					 | 
				
			||||||
	char mode;                       /* Encryption mode for tfm */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ext4_completion_result {
 | 
					 | 
				
			||||||
	struct completion completion;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define DECLARE_EXT4_COMPLETION_RESULT(ecr) \
 | 
					 | 
				
			||||||
	struct ext4_completion_result ecr = { \
 | 
					 | 
				
			||||||
		COMPLETION_INITIALIZER((ecr).completion), 0 }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int ext4_encryption_key_size(int mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	switch (mode) {
 | 
					 | 
				
			||||||
	case EXT4_ENCRYPTION_MODE_AES_256_XTS:
 | 
					 | 
				
			||||||
		return EXT4_AES_256_XTS_KEY_SIZE;
 | 
					 | 
				
			||||||
	case EXT4_ENCRYPTION_MODE_AES_256_GCM:
 | 
					 | 
				
			||||||
		return EXT4_AES_256_GCM_KEY_SIZE;
 | 
					 | 
				
			||||||
	case EXT4_ENCRYPTION_MODE_AES_256_CBC:
 | 
					 | 
				
			||||||
		return EXT4_AES_256_CBC_KEY_SIZE;
 | 
					 | 
				
			||||||
	case EXT4_ENCRYPTION_MODE_AES_256_CTS:
 | 
					 | 
				
			||||||
		return EXT4_AES_256_CTS_KEY_SIZE;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		BUG();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define EXT4_FNAME_NUM_SCATTER_ENTRIES	4
 | 
					 | 
				
			||||||
#define EXT4_CRYPTO_BLOCK_SIZE		16
 | 
					 | 
				
			||||||
#define EXT4_FNAME_CRYPTO_DIGEST_SIZE	32
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ext4_str {
 | 
					 | 
				
			||||||
	unsigned char *name;
 | 
					 | 
				
			||||||
	u32 len;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * For encrypted symlinks, the ciphertext length is stored at the beginning
 | 
					 | 
				
			||||||
 * of the string in little-endian format.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct ext4_encrypted_symlink_data {
 | 
					 | 
				
			||||||
	__le16 len;
 | 
					 | 
				
			||||||
	char encrypted_path[1];
 | 
					 | 
				
			||||||
} __attribute__((__packed__));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * This function is used to calculate the disk space required to
 | 
					 | 
				
			||||||
 * store a filename of length l in encrypted symlink format.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static inline u32 encrypted_symlink_data_len(u32 l)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (l < EXT4_CRYPTO_BLOCK_SIZE)
 | 
					 | 
				
			||||||
		l = EXT4_CRYPTO_BLOCK_SIZE;
 | 
					 | 
				
			||||||
	return (l + sizeof(struct ext4_encrypted_symlink_data) - 1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif	/* _EXT4_CRYPTO_H */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -303,10 +303,10 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
 | 
				
			||||||
	struct inode *inode = file->f_mapping->host;
 | 
						struct inode *inode = file->f_mapping->host;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ext4_encrypted_inode(inode)) {
 | 
						if (ext4_encrypted_inode(inode)) {
 | 
				
			||||||
		int err = ext4_get_encryption_info(inode);
 | 
							int err = fscrypt_get_encryption_info(inode);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		if (ext4_encryption_info(inode) == NULL)
 | 
							if (!fscrypt_has_encryption_key(inode))
 | 
				
			||||||
			return -ENOKEY;
 | 
								return -ENOKEY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	file_accessed(file);
 | 
						file_accessed(file);
 | 
				
			||||||
| 
						 | 
					@ -362,16 +362,16 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ext4_encrypted_inode(inode)) {
 | 
						if (ext4_encrypted_inode(inode)) {
 | 
				
			||||||
		ret = ext4_get_encryption_info(inode);
 | 
							ret = fscrypt_get_encryption_info(inode);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			return -EACCES;
 | 
								return -EACCES;
 | 
				
			||||||
		if (ext4_encryption_info(inode) == NULL)
 | 
							if (!fscrypt_has_encryption_key(inode))
 | 
				
			||||||
			return -ENOKEY;
 | 
								return -ENOKEY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dir = dget_parent(file_dentry(filp));
 | 
						dir = dget_parent(file_dentry(filp));
 | 
				
			||||||
	if (ext4_encrypted_inode(d_inode(dir)) &&
 | 
						if (ext4_encrypted_inode(d_inode(dir)) &&
 | 
				
			||||||
	    !ext4_is_child_context_consistent_with_parent(d_inode(dir), inode)) {
 | 
								!fscrypt_has_permitted_context(d_inode(dir), inode)) {
 | 
				
			||||||
		ext4_warning(inode->i_sb,
 | 
							ext4_warning(inode->i_sb,
 | 
				
			||||||
			     "Inconsistent encryption contexts: %lu/%lu",
 | 
								     "Inconsistent encryption contexts: %lu/%lu",
 | 
				
			||||||
			     (unsigned long) d_inode(dir)->i_ino,
 | 
								     (unsigned long) d_inode(dir)->i_ino,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -767,10 +767,10 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
 | 
				
			||||||
	if ((ext4_encrypted_inode(dir) ||
 | 
						if ((ext4_encrypted_inode(dir) ||
 | 
				
			||||||
	     DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) &&
 | 
						     DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) &&
 | 
				
			||||||
	    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
 | 
						    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
 | 
				
			||||||
		err = ext4_get_encryption_info(dir);
 | 
							err = fscrypt_get_encryption_info(dir);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			return ERR_PTR(err);
 | 
								return ERR_PTR(err);
 | 
				
			||||||
		if (ext4_encryption_info(dir) == NULL)
 | 
							if (!fscrypt_has_encryption_key(dir))
 | 
				
			||||||
			return ERR_PTR(-EPERM);
 | 
								return ERR_PTR(-EPERM);
 | 
				
			||||||
		if (!handle)
 | 
							if (!handle)
 | 
				
			||||||
			nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb);
 | 
								nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb);
 | 
				
			||||||
| 
						 | 
					@ -1115,7 +1115,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (encrypt) {
 | 
						if (encrypt) {
 | 
				
			||||||
		err = ext4_inherit_context(dir, inode);
 | 
							/* give pointer to avoid set_context with journal ops. */
 | 
				
			||||||
 | 
							err = fscrypt_inherit_context(dir, inode, &encrypt, true);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto fail_free_drop;
 | 
								goto fail_free_drop;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1326,7 +1326,7 @@ int htree_inlinedir_to_tree(struct file *dir_file,
 | 
				
			||||||
	struct ext4_iloc iloc;
 | 
						struct ext4_iloc iloc;
 | 
				
			||||||
	void *dir_buf = NULL;
 | 
						void *dir_buf = NULL;
 | 
				
			||||||
	struct ext4_dir_entry_2 fake;
 | 
						struct ext4_dir_entry_2 fake;
 | 
				
			||||||
	struct ext4_str tmp_str;
 | 
						struct fscrypt_str tmp_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ext4_get_inode_loc(inode, &iloc);
 | 
						ret = ext4_get_inode_loc(inode, &iloc);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
| 
						 | 
					@ -1739,20 +1739,20 @@ ext4_get_inline_entry(struct inode *inode,
 | 
				
			||||||
	return (struct ext4_dir_entry_2 *)(inline_pos + offset);
 | 
						return (struct ext4_dir_entry_2 *)(inline_pos + offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int empty_inline_dir(struct inode *dir, int *has_inline_data)
 | 
					bool empty_inline_dir(struct inode *dir, int *has_inline_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err, inline_size;
 | 
						int err, inline_size;
 | 
				
			||||||
	struct ext4_iloc iloc;
 | 
						struct ext4_iloc iloc;
 | 
				
			||||||
	void *inline_pos;
 | 
						void *inline_pos;
 | 
				
			||||||
	unsigned int offset;
 | 
						unsigned int offset;
 | 
				
			||||||
	struct ext4_dir_entry_2 *de;
 | 
						struct ext4_dir_entry_2 *de;
 | 
				
			||||||
	int ret = 1;
 | 
						bool ret = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = ext4_get_inode_loc(dir, &iloc);
 | 
						err = ext4_get_inode_loc(dir, &iloc);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		EXT4_ERROR_INODE(dir, "error %d getting inode %lu block",
 | 
							EXT4_ERROR_INODE(dir, "error %d getting inode %lu block",
 | 
				
			||||||
				 err, dir->i_ino);
 | 
									 err, dir->i_ino);
 | 
				
			||||||
		return 1;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	down_read(&EXT4_I(dir)->xattr_sem);
 | 
						down_read(&EXT4_I(dir)->xattr_sem);
 | 
				
			||||||
| 
						 | 
					@ -1766,7 +1766,7 @@ int empty_inline_dir(struct inode *dir, int *has_inline_data)
 | 
				
			||||||
		ext4_warning(dir->i_sb,
 | 
							ext4_warning(dir->i_sb,
 | 
				
			||||||
			     "bad inline directory (dir #%lu) - no `..'",
 | 
								     "bad inline directory (dir #%lu) - no `..'",
 | 
				
			||||||
			     dir->i_ino);
 | 
								     dir->i_ino);
 | 
				
			||||||
		ret = 1;
 | 
							ret = true;
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1784,11 +1784,11 @@ int empty_inline_dir(struct inode *dir, int *has_inline_data)
 | 
				
			||||||
				     dir->i_ino, le32_to_cpu(de->inode),
 | 
									     dir->i_ino, le32_to_cpu(de->inode),
 | 
				
			||||||
				     le16_to_cpu(de->rec_len), de->name_len,
 | 
									     le16_to_cpu(de->rec_len), de->name_len,
 | 
				
			||||||
				     inline_size);
 | 
									     inline_size);
 | 
				
			||||||
			ret = 1;
 | 
								ret = true;
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (le32_to_cpu(de->inode)) {
 | 
							if (le32_to_cpu(de->inode)) {
 | 
				
			||||||
			ret = 0;
 | 
								ret = false;
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		offset += ext4_rec_len_from_disk(de->rec_len, inline_size);
 | 
							offset += ext4_rec_len_from_disk(de->rec_len, inline_size);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -392,7 +392,7 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk,
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ext4_encrypted_inode(inode))
 | 
						if (ext4_encrypted_inode(inode))
 | 
				
			||||||
		return ext4_encrypted_zeroout(inode, lblk, pblk, len);
 | 
							return fscrypt_zeroout_range(inode, lblk, pblk, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = sb_issue_zeroout(inode->i_sb, pblk, len, GFP_NOFS);
 | 
						ret = sb_issue_zeroout(inode->i_sb, pblk, len, GFP_NOFS);
 | 
				
			||||||
	if (ret > 0)
 | 
						if (ret > 0)
 | 
				
			||||||
| 
						 | 
					@ -1158,7 +1158,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
 | 
				
			||||||
	if (unlikely(err))
 | 
						if (unlikely(err))
 | 
				
			||||||
		page_zero_new_buffers(page, from, to);
 | 
							page_zero_new_buffers(page, from, to);
 | 
				
			||||||
	else if (decrypt)
 | 
						else if (decrypt)
 | 
				
			||||||
		err = ext4_decrypt(page);
 | 
							err = fscrypt_decrypt_page(page);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -3735,9 +3735,9 @@ static int __ext4_block_zero_page_range(handle_t *handle,
 | 
				
			||||||
		if (S_ISREG(inode->i_mode) &&
 | 
							if (S_ISREG(inode->i_mode) &&
 | 
				
			||||||
		    ext4_encrypted_inode(inode)) {
 | 
							    ext4_encrypted_inode(inode)) {
 | 
				
			||||||
			/* We expect the key to be set. */
 | 
								/* We expect the key to be set. */
 | 
				
			||||||
			BUG_ON(!ext4_has_encryption_key(inode));
 | 
								BUG_ON(!fscrypt_has_encryption_key(inode));
 | 
				
			||||||
			BUG_ON(blocksize != PAGE_SIZE);
 | 
								BUG_ON(blocksize != PAGE_SIZE);
 | 
				
			||||||
			WARN_ON_ONCE(ext4_decrypt(page));
 | 
								WARN_ON_ONCE(fscrypt_decrypt_page(page));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ext4_should_journal_data(inode)) {
 | 
						if (ext4_should_journal_data(inode)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -770,19 +770,13 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 | 
				
			||||||
		return ext4_ext_precache(inode);
 | 
							return ext4_ext_precache(inode);
 | 
				
			||||||
	case EXT4_IOC_SET_ENCRYPTION_POLICY: {
 | 
						case EXT4_IOC_SET_ENCRYPTION_POLICY: {
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
		struct ext4_encryption_policy policy;
 | 
							struct fscrypt_policy policy;
 | 
				
			||||||
		int err = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (copy_from_user(&policy,
 | 
							if (copy_from_user(&policy,
 | 
				
			||||||
				   (struct ext4_encryption_policy __user *)arg,
 | 
									   (struct fscrypt_policy __user *)arg,
 | 
				
			||||||
				   sizeof(policy))) {
 | 
									   sizeof(policy)))
 | 
				
			||||||
			err = -EFAULT;
 | 
								return -EFAULT;
 | 
				
			||||||
			goto encryption_policy_out;
 | 
							return fscrypt_process_policy(inode, &policy);
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		err = ext4_process_policy(&policy, inode);
 | 
					 | 
				
			||||||
encryption_policy_out:
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -825,12 +819,12 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	case EXT4_IOC_GET_ENCRYPTION_POLICY: {
 | 
						case EXT4_IOC_GET_ENCRYPTION_POLICY: {
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
		struct ext4_encryption_policy policy;
 | 
							struct fscrypt_policy policy;
 | 
				
			||||||
		int err = 0;
 | 
							int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!ext4_encrypted_inode(inode))
 | 
							if (!ext4_encrypted_inode(inode))
 | 
				
			||||||
			return -ENOENT;
 | 
								return -ENOENT;
 | 
				
			||||||
		err = ext4_get_policy(inode, &policy);
 | 
							err = fscrypt_get_policy(inode, &policy);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
		if (copy_to_user((void __user *)arg, &policy, sizeof(policy)))
 | 
							if (copy_to_user((void __user *)arg, &policy, sizeof(policy)))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										113
									
								
								fs/ext4/namei.c
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								fs/ext4/namei.c
									
									
									
									
									
								
							| 
						 | 
					@ -611,19 +611,19 @@ static struct stats dx_show_leaf(struct inode *dir,
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
				int len;
 | 
									int len;
 | 
				
			||||||
				char *name;
 | 
									char *name;
 | 
				
			||||||
				struct ext4_str fname_crypto_str
 | 
									struct fscrypt_str fname_crypto_str =
 | 
				
			||||||
					= {.name = NULL, .len = 0};
 | 
										FSTR_INIT(NULL, 0);
 | 
				
			||||||
				int res = 0;
 | 
									int res = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				name  = de->name;
 | 
									name  = de->name;
 | 
				
			||||||
				len = de->name_len;
 | 
									len = de->name_len;
 | 
				
			||||||
				if (ext4_encrypted_inode(inode))
 | 
									if (ext4_encrypted_inode(dir))
 | 
				
			||||||
					res = ext4_get_encryption_info(dir);
 | 
										res = fscrypt_get_encryption_info(dir);
 | 
				
			||||||
				if (res) {
 | 
									if (res) {
 | 
				
			||||||
					printk(KERN_WARNING "Error setting up"
 | 
										printk(KERN_WARNING "Error setting up"
 | 
				
			||||||
					       " fname crypto: %d\n", res);
 | 
										       " fname crypto: %d\n", res);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if (ctx == NULL) {
 | 
									if (!fscrypt_has_encryption_key(dir)) {
 | 
				
			||||||
					/* Directory is not encrypted */
 | 
										/* Directory is not encrypted */
 | 
				
			||||||
					ext4fs_dirhash(de->name,
 | 
										ext4fs_dirhash(de->name,
 | 
				
			||||||
						de->name_len, &h);
 | 
											de->name_len, &h);
 | 
				
			||||||
| 
						 | 
					@ -632,18 +632,20 @@ static struct stats dx_show_leaf(struct inode *dir,
 | 
				
			||||||
					       (unsigned) ((char *) de
 | 
										       (unsigned) ((char *) de
 | 
				
			||||||
							   - base));
 | 
												   - base));
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
 | 
										struct fscrypt_str de_name =
 | 
				
			||||||
 | 
											FSTR_INIT(name, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					/* Directory is encrypted */
 | 
										/* Directory is encrypted */
 | 
				
			||||||
					res = ext4_fname_crypto_alloc_buffer(
 | 
										res = fscrypt_fname_alloc_buffer(
 | 
				
			||||||
						ctx, de->name_len,
 | 
											dir, len,
 | 
				
			||||||
						&fname_crypto_str);
 | 
											&fname_crypto_str);
 | 
				
			||||||
					if (res < 0) {
 | 
										if (res < 0)
 | 
				
			||||||
						printk(KERN_WARNING "Error "
 | 
											printk(KERN_WARNING "Error "
 | 
				
			||||||
							"allocating crypto "
 | 
												"allocating crypto "
 | 
				
			||||||
							"buffer--skipping "
 | 
												"buffer--skipping "
 | 
				
			||||||
							"crypto\n");
 | 
												"crypto\n");
 | 
				
			||||||
						ctx = NULL;
 | 
										res = fscrypt_fname_disk_to_usr(dir,
 | 
				
			||||||
					}
 | 
											0, 0, &de_name,
 | 
				
			||||||
					res = ext4_fname_disk_to_usr(ctx, NULL, de,
 | 
					 | 
				
			||||||
						&fname_crypto_str);
 | 
											&fname_crypto_str);
 | 
				
			||||||
					if (res < 0) {
 | 
										if (res < 0) {
 | 
				
			||||||
						printk(KERN_WARNING "Error "
 | 
											printk(KERN_WARNING "Error "
 | 
				
			||||||
| 
						 | 
					@ -661,7 +663,7 @@ static struct stats dx_show_leaf(struct inode *dir,
 | 
				
			||||||
					printk("%*.s:(E)%x.%u ", len, name,
 | 
										printk("%*.s:(E)%x.%u ", len, name,
 | 
				
			||||||
					       h.hash, (unsigned) ((char *) de
 | 
										       h.hash, (unsigned) ((char *) de
 | 
				
			||||||
								   - base));
 | 
													   - base));
 | 
				
			||||||
					ext4_fname_crypto_free_buffer(
 | 
										fscrypt_fname_free_buffer(
 | 
				
			||||||
							&fname_crypto_str);
 | 
												&fname_crypto_str);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					@ -951,7 +953,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
 | 
				
			||||||
	struct buffer_head *bh;
 | 
						struct buffer_head *bh;
 | 
				
			||||||
	struct ext4_dir_entry_2 *de, *top;
 | 
						struct ext4_dir_entry_2 *de, *top;
 | 
				
			||||||
	int err = 0, count = 0;
 | 
						int err = 0, count = 0;
 | 
				
			||||||
	struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}, tmp_str;
 | 
						struct fscrypt_str fname_crypto_str = FSTR_INIT(NULL, 0), tmp_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
 | 
						dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
 | 
				
			||||||
							(unsigned long)block));
 | 
												(unsigned long)block));
 | 
				
			||||||
| 
						 | 
					@ -966,12 +968,12 @@ static int htree_dirblock_to_tree(struct file *dir_file,
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
	/* Check if the directory is encrypted */
 | 
						/* Check if the directory is encrypted */
 | 
				
			||||||
	if (ext4_encrypted_inode(dir)) {
 | 
						if (ext4_encrypted_inode(dir)) {
 | 
				
			||||||
		err = ext4_get_encryption_info(dir);
 | 
							err = fscrypt_get_encryption_info(dir);
 | 
				
			||||||
		if (err < 0) {
 | 
							if (err < 0) {
 | 
				
			||||||
			brelse(bh);
 | 
								brelse(bh);
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		err = ext4_fname_crypto_alloc_buffer(dir, EXT4_NAME_LEN,
 | 
							err = fscrypt_fname_alloc_buffer(dir, EXT4_NAME_LEN,
 | 
				
			||||||
						     &fname_crypto_str);
 | 
											     &fname_crypto_str);
 | 
				
			||||||
		if (err < 0) {
 | 
							if (err < 0) {
 | 
				
			||||||
			brelse(bh);
 | 
								brelse(bh);
 | 
				
			||||||
| 
						 | 
					@ -1002,9 +1004,12 @@ static int htree_dirblock_to_tree(struct file *dir_file,
 | 
				
			||||||
				   &tmp_str);
 | 
									   &tmp_str);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			int save_len = fname_crypto_str.len;
 | 
								int save_len = fname_crypto_str.len;
 | 
				
			||||||
 | 
								struct fscrypt_str de_name = FSTR_INIT(de->name,
 | 
				
			||||||
 | 
													de->name_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Directory is encrypted */
 | 
								/* Directory is encrypted */
 | 
				
			||||||
			err = ext4_fname_disk_to_usr(dir, hinfo, de,
 | 
								err = fscrypt_fname_disk_to_usr(dir, hinfo->hash,
 | 
				
			||||||
 | 
										hinfo->minor_hash, &de_name,
 | 
				
			||||||
					&fname_crypto_str);
 | 
										&fname_crypto_str);
 | 
				
			||||||
			if (err < 0) {
 | 
								if (err < 0) {
 | 
				
			||||||
				count = err;
 | 
									count = err;
 | 
				
			||||||
| 
						 | 
					@ -1024,7 +1029,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
 | 
				
			||||||
errout:
 | 
					errout:
 | 
				
			||||||
	brelse(bh);
 | 
						brelse(bh);
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
	ext4_fname_crypto_free_buffer(&fname_crypto_str);
 | 
						fscrypt_fname_free_buffer(&fname_crypto_str);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	return count;
 | 
						return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1049,7 +1054,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
 | 
				
			||||||
	int count = 0;
 | 
						int count = 0;
 | 
				
			||||||
	int ret, err;
 | 
						int ret, err;
 | 
				
			||||||
	__u32 hashval;
 | 
						__u32 hashval;
 | 
				
			||||||
	struct ext4_str tmp_str;
 | 
						struct fscrypt_str tmp_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n",
 | 
						dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n",
 | 
				
			||||||
		       start_hash, start_minor_hash));
 | 
							       start_hash, start_minor_hash));
 | 
				
			||||||
| 
						 | 
					@ -1563,19 +1568,16 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
 | 
				
			||||||
	struct buffer_head *bh;
 | 
						struct buffer_head *bh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ext4_encrypted_inode(dir)) {
 | 
						if (ext4_encrypted_inode(dir)) {
 | 
				
			||||||
               int res = ext4_get_encryption_info(dir);
 | 
							int res = fscrypt_get_encryption_info(dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * This should be a properly defined flag for
 | 
							 * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
 | 
				
			||||||
		 * dentry->d_flags when we uplift this to the VFS.
 | 
					 | 
				
			||||||
		 * d_fsdata is set to (void *) 1 if if the dentry is
 | 
					 | 
				
			||||||
		 * created while the directory was encrypted and we
 | 
							 * created while the directory was encrypted and we
 | 
				
			||||||
		 * don't have access to the key.
 | 
							 * have access to the key.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
	       dentry->d_fsdata = NULL;
 | 
							if (fscrypt_has_encryption_key(dir))
 | 
				
			||||||
	       if (ext4_encryption_info(dir))
 | 
								fscrypt_set_encrypted_dentry(dentry);
 | 
				
			||||||
		       dentry->d_fsdata = (void *) 1;
 | 
							fscrypt_set_d_op(dentry);
 | 
				
			||||||
	       d_set_d_op(dentry, &ext4_encrypted_d_ops);
 | 
					 | 
				
			||||||
		if (res && res != -ENOKEY)
 | 
							if (res && res != -ENOKEY)
 | 
				
			||||||
			return ERR_PTR(res);
 | 
								return ERR_PTR(res);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1608,11 +1610,9 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!IS_ERR(inode) && ext4_encrypted_inode(dir) &&
 | 
							if (!IS_ERR(inode) && ext4_encrypted_inode(dir) &&
 | 
				
			||||||
		    (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
 | 
							    (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
 | 
				
			||||||
		    !ext4_is_child_context_consistent_with_parent(dir,
 | 
							    !fscrypt_has_permitted_context(dir, inode)) {
 | 
				
			||||||
								  inode)) {
 | 
					 | 
				
			||||||
			int nokey = ext4_encrypted_inode(inode) &&
 | 
								int nokey = ext4_encrypted_inode(inode) &&
 | 
				
			||||||
				!ext4_encryption_info(inode);
 | 
									!fscrypt_has_encryption_key(inode);
 | 
				
			||||||
 | 
					 | 
				
			||||||
			iput(inode);
 | 
								iput(inode);
 | 
				
			||||||
			if (nokey)
 | 
								if (nokey)
 | 
				
			||||||
				return ERR_PTR(-ENOKEY);
 | 
									return ERR_PTR(-ENOKEY);
 | 
				
			||||||
| 
						 | 
					@ -2689,30 +2689,30 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * routine to check that the specified directory is empty (for rmdir)
 | 
					 * routine to check that the specified directory is empty (for rmdir)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int ext4_empty_dir(struct inode *inode)
 | 
					bool ext4_empty_dir(struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int offset;
 | 
						unsigned int offset;
 | 
				
			||||||
	struct buffer_head *bh;
 | 
						struct buffer_head *bh;
 | 
				
			||||||
	struct ext4_dir_entry_2 *de, *de1;
 | 
						struct ext4_dir_entry_2 *de, *de1;
 | 
				
			||||||
	struct super_block *sb;
 | 
						struct super_block *sb;
 | 
				
			||||||
	int err = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ext4_has_inline_data(inode)) {
 | 
						if (ext4_has_inline_data(inode)) {
 | 
				
			||||||
		int has_inline_data = 1;
 | 
							int has_inline_data = 1;
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = empty_inline_dir(inode, &has_inline_data);
 | 
							ret = empty_inline_dir(inode, &has_inline_data);
 | 
				
			||||||
		if (has_inline_data)
 | 
							if (has_inline_data)
 | 
				
			||||||
			return err;
 | 
								return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sb = inode->i_sb;
 | 
						sb = inode->i_sb;
 | 
				
			||||||
	if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2)) {
 | 
						if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2)) {
 | 
				
			||||||
		EXT4_ERROR_INODE(inode, "invalid size");
 | 
							EXT4_ERROR_INODE(inode, "invalid size");
 | 
				
			||||||
		return 1;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bh = ext4_read_dirblock(inode, 0, EITHER);
 | 
						bh = ext4_read_dirblock(inode, 0, EITHER);
 | 
				
			||||||
	if (IS_ERR(bh))
 | 
						if (IS_ERR(bh))
 | 
				
			||||||
		return 1;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	de = (struct ext4_dir_entry_2 *) bh->b_data;
 | 
						de = (struct ext4_dir_entry_2 *) bh->b_data;
 | 
				
			||||||
	de1 = ext4_next_entry(de, sb->s_blocksize);
 | 
						de1 = ext4_next_entry(de, sb->s_blocksize);
 | 
				
			||||||
| 
						 | 
					@ -2721,7 +2721,7 @@ int ext4_empty_dir(struct inode *inode)
 | 
				
			||||||
			strcmp(".", de->name) || strcmp("..", de1->name)) {
 | 
								strcmp(".", de->name) || strcmp("..", de1->name)) {
 | 
				
			||||||
		ext4_warning_inode(inode, "directory missing '.' and/or '..'");
 | 
							ext4_warning_inode(inode, "directory missing '.' and/or '..'");
 | 
				
			||||||
		brelse(bh);
 | 
							brelse(bh);
 | 
				
			||||||
		return 1;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) +
 | 
						offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) +
 | 
				
			||||||
		 ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
 | 
							 ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
 | 
				
			||||||
| 
						 | 
					@ -2729,12 +2729,11 @@ int ext4_empty_dir(struct inode *inode)
 | 
				
			||||||
	while (offset < inode->i_size) {
 | 
						while (offset < inode->i_size) {
 | 
				
			||||||
		if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
 | 
							if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
 | 
				
			||||||
			unsigned int lblock;
 | 
								unsigned int lblock;
 | 
				
			||||||
			err = 0;
 | 
					 | 
				
			||||||
			brelse(bh);
 | 
								brelse(bh);
 | 
				
			||||||
			lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb);
 | 
								lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb);
 | 
				
			||||||
			bh = ext4_read_dirblock(inode, lblock, EITHER);
 | 
								bh = ext4_read_dirblock(inode, lblock, EITHER);
 | 
				
			||||||
			if (IS_ERR(bh))
 | 
								if (IS_ERR(bh))
 | 
				
			||||||
				return 1;
 | 
									return true;
 | 
				
			||||||
			de = (struct ext4_dir_entry_2 *) bh->b_data;
 | 
								de = (struct ext4_dir_entry_2 *) bh->b_data;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (ext4_check_dir_entry(inode, NULL, de, bh,
 | 
							if (ext4_check_dir_entry(inode, NULL, de, bh,
 | 
				
			||||||
| 
						 | 
					@ -2746,13 +2745,13 @@ int ext4_empty_dir(struct inode *inode)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (le32_to_cpu(de->inode)) {
 | 
							if (le32_to_cpu(de->inode)) {
 | 
				
			||||||
			brelse(bh);
 | 
								brelse(bh);
 | 
				
			||||||
			return 0;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
 | 
							offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
 | 
				
			||||||
		de = ext4_next_entry(de, sb->s_blocksize);
 | 
							de = ext4_next_entry(de, sb->s_blocksize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	brelse(bh);
 | 
						brelse(bh);
 | 
				
			||||||
	return 1;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -3075,8 +3074,8 @@ static int ext4_symlink(struct inode *dir,
 | 
				
			||||||
	int err, len = strlen(symname);
 | 
						int err, len = strlen(symname);
 | 
				
			||||||
	int credits;
 | 
						int credits;
 | 
				
			||||||
	bool encryption_required;
 | 
						bool encryption_required;
 | 
				
			||||||
	struct ext4_str disk_link;
 | 
						struct fscrypt_str disk_link;
 | 
				
			||||||
	struct ext4_encrypted_symlink_data *sd = NULL;
 | 
						struct fscrypt_symlink_data *sd = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	disk_link.len = len + 1;
 | 
						disk_link.len = len + 1;
 | 
				
			||||||
	disk_link.name = (char *) symname;
 | 
						disk_link.name = (char *) symname;
 | 
				
			||||||
| 
						 | 
					@ -3084,13 +3083,13 @@ static int ext4_symlink(struct inode *dir,
 | 
				
			||||||
	encryption_required = (ext4_encrypted_inode(dir) ||
 | 
						encryption_required = (ext4_encrypted_inode(dir) ||
 | 
				
			||||||
			       DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
 | 
								       DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
 | 
				
			||||||
	if (encryption_required) {
 | 
						if (encryption_required) {
 | 
				
			||||||
		err = ext4_get_encryption_info(dir);
 | 
							err = fscrypt_get_encryption_info(dir);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
		if (ext4_encryption_info(dir) == NULL)
 | 
							if (!fscrypt_has_encryption_key(dir))
 | 
				
			||||||
			return -EPERM;
 | 
								return -EPERM;
 | 
				
			||||||
		disk_link.len = (ext4_fname_encrypted_size(dir, len) +
 | 
							disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
 | 
				
			||||||
				 sizeof(struct ext4_encrypted_symlink_data));
 | 
									 sizeof(struct fscrypt_symlink_data));
 | 
				
			||||||
		sd = kzalloc(disk_link.len, GFP_KERNEL);
 | 
							sd = kzalloc(disk_link.len, GFP_KERNEL);
 | 
				
			||||||
		if (!sd)
 | 
							if (!sd)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -3138,13 +3137,12 @@ static int ext4_symlink(struct inode *dir,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (encryption_required) {
 | 
						if (encryption_required) {
 | 
				
			||||||
		struct qstr istr;
 | 
							struct qstr istr;
 | 
				
			||||||
		struct ext4_str ostr;
 | 
							struct fscrypt_str ostr =
 | 
				
			||||||
 | 
								FSTR_INIT(sd->encrypted_path, disk_link.len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		istr.name = (const unsigned char *) symname;
 | 
							istr.name = (const unsigned char *) symname;
 | 
				
			||||||
		istr.len = len;
 | 
							istr.len = len;
 | 
				
			||||||
		ostr.name = sd->encrypted_path;
 | 
							err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
 | 
				
			||||||
		ostr.len = disk_link.len;
 | 
					 | 
				
			||||||
		err = ext4_fname_usr_to_disk(inode, &istr, &ostr);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			goto err_drop_inode;
 | 
								goto err_drop_inode;
 | 
				
			||||||
		sd->len = cpu_to_le16(ostr.len);
 | 
							sd->len = cpu_to_le16(ostr.len);
 | 
				
			||||||
| 
						 | 
					@ -3233,7 +3231,7 @@ static int ext4_link(struct dentry *old_dentry,
 | 
				
			||||||
	if (inode->i_nlink >= EXT4_LINK_MAX)
 | 
						if (inode->i_nlink >= EXT4_LINK_MAX)
 | 
				
			||||||
		return -EMLINK;
 | 
							return -EMLINK;
 | 
				
			||||||
	if (ext4_encrypted_inode(dir) &&
 | 
						if (ext4_encrypted_inode(dir) &&
 | 
				
			||||||
	    !ext4_is_child_context_consistent_with_parent(dir, inode))
 | 
								!fscrypt_has_permitted_context(dir, inode))
 | 
				
			||||||
		return -EPERM;
 | 
							return -EPERM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) &&
 | 
					       if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) &&
 | 
				
			||||||
| 
						 | 
					@ -3556,8 +3554,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((old.dir != new.dir) &&
 | 
						if ((old.dir != new.dir) &&
 | 
				
			||||||
	    ext4_encrypted_inode(new.dir) &&
 | 
						    ext4_encrypted_inode(new.dir) &&
 | 
				
			||||||
	    !ext4_is_child_context_consistent_with_parent(new.dir,
 | 
						    !fscrypt_has_permitted_context(new.dir, old.inode)) {
 | 
				
			||||||
							  old.inode)) {
 | 
					 | 
				
			||||||
		retval = -EPERM;
 | 
							retval = -EPERM;
 | 
				
			||||||
		goto end_rename;
 | 
							goto end_rename;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -3729,10 +3726,8 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 | 
				
			||||||
	if ((ext4_encrypted_inode(old_dir) ||
 | 
						if ((ext4_encrypted_inode(old_dir) ||
 | 
				
			||||||
	     ext4_encrypted_inode(new_dir)) &&
 | 
						     ext4_encrypted_inode(new_dir)) &&
 | 
				
			||||||
	    (old_dir != new_dir) &&
 | 
						    (old_dir != new_dir) &&
 | 
				
			||||||
	    (!ext4_is_child_context_consistent_with_parent(new_dir,
 | 
						    (!fscrypt_has_permitted_context(new_dir, old.inode) ||
 | 
				
			||||||
							   old.inode) ||
 | 
						     !fscrypt_has_permitted_context(old_dir, new.inode)))
 | 
				
			||||||
	     !ext4_is_child_context_consistent_with_parent(old_dir,
 | 
					 | 
				
			||||||
							   new.inode)))
 | 
					 | 
				
			||||||
		return -EPERM;
 | 
							return -EPERM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT) &&
 | 
						if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT) &&
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/mm.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
#include <linux/backing-dev.h>
 | 
					#include <linux/backing-dev.h>
 | 
				
			||||||
 | 
					#include <linux/fscrypto.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ext4_jbd2.h"
 | 
					#include "ext4_jbd2.h"
 | 
				
			||||||
#include "xattr.h"
 | 
					#include "xattr.h"
 | 
				
			||||||
| 
						 | 
					@ -67,7 +68,6 @@ static void ext4_finish_bio(struct bio *bio)
 | 
				
			||||||
		struct page *page = bvec->bv_page;
 | 
							struct page *page = bvec->bv_page;
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
		struct page *data_page = NULL;
 | 
							struct page *data_page = NULL;
 | 
				
			||||||
		struct ext4_crypto_ctx *ctx = NULL;
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		struct buffer_head *bh, *head;
 | 
							struct buffer_head *bh, *head;
 | 
				
			||||||
		unsigned bio_start = bvec->bv_offset;
 | 
							unsigned bio_start = bvec->bv_offset;
 | 
				
			||||||
| 
						 | 
					@ -82,8 +82,7 @@ static void ext4_finish_bio(struct bio *bio)
 | 
				
			||||||
		if (!page->mapping) {
 | 
							if (!page->mapping) {
 | 
				
			||||||
			/* The bounce data pages are unmapped. */
 | 
								/* The bounce data pages are unmapped. */
 | 
				
			||||||
			data_page = page;
 | 
								data_page = page;
 | 
				
			||||||
			ctx = (struct ext4_crypto_ctx *)page_private(data_page);
 | 
								fscrypt_pullback_bio_page(&page, false);
 | 
				
			||||||
			page = ctx->w.control_page;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,8 +112,8 @@ static void ext4_finish_bio(struct bio *bio)
 | 
				
			||||||
		local_irq_restore(flags);
 | 
							local_irq_restore(flags);
 | 
				
			||||||
		if (!under_io) {
 | 
							if (!under_io) {
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
			if (ctx)
 | 
								if (data_page)
 | 
				
			||||||
				ext4_restore_control_page(data_page);
 | 
									fscrypt_restore_control_page(data_page);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
			end_page_writeback(page);
 | 
								end_page_writeback(page);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -472,7 +471,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
 | 
				
			||||||
		gfp_t gfp_flags = GFP_NOFS;
 | 
							gfp_t gfp_flags = GFP_NOFS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retry_encrypt:
 | 
						retry_encrypt:
 | 
				
			||||||
		data_page = ext4_encrypt(inode, page, gfp_flags);
 | 
							data_page = fscrypt_encrypt_page(inode, page, gfp_flags);
 | 
				
			||||||
		if (IS_ERR(data_page)) {
 | 
							if (IS_ERR(data_page)) {
 | 
				
			||||||
			ret = PTR_ERR(data_page);
 | 
								ret = PTR_ERR(data_page);
 | 
				
			||||||
			if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
 | 
								if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
 | 
				
			||||||
| 
						 | 
					@ -510,7 +509,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
	out:
 | 
						out:
 | 
				
			||||||
		if (data_page)
 | 
							if (data_page)
 | 
				
			||||||
			ext4_restore_control_page(data_page);
 | 
								fscrypt_restore_control_page(data_page);
 | 
				
			||||||
		printk_ratelimited(KERN_ERR "%s: ret = %d\n", __func__, ret);
 | 
							printk_ratelimited(KERN_ERR "%s: ret = %d\n", __func__, ret);
 | 
				
			||||||
		redirty_page_for_writepage(wbc, page);
 | 
							redirty_page_for_writepage(wbc, page);
 | 
				
			||||||
		do {
 | 
							do {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,37 +46,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ext4.h"
 | 
					#include "ext4.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Call ext4_decrypt on every single page, reusing the encryption
 | 
					 | 
				
			||||||
 * context.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void completion_pages(struct work_struct *work)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
	struct ext4_crypto_ctx *ctx =
 | 
					 | 
				
			||||||
		container_of(work, struct ext4_crypto_ctx, r.work);
 | 
					 | 
				
			||||||
	struct bio	*bio	= ctx->r.bio;
 | 
					 | 
				
			||||||
	struct bio_vec	*bv;
 | 
					 | 
				
			||||||
	int		i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bio_for_each_segment_all(bv, bio, i) {
 | 
					 | 
				
			||||||
		struct page *page = bv->bv_page;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int ret = ext4_decrypt(page);
 | 
					 | 
				
			||||||
		if (ret) {
 | 
					 | 
				
			||||||
			WARN_ON_ONCE(1);
 | 
					 | 
				
			||||||
			SetPageError(page);
 | 
					 | 
				
			||||||
		} else
 | 
					 | 
				
			||||||
			SetPageUptodate(page);
 | 
					 | 
				
			||||||
		unlock_page(page);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ext4_release_crypto_ctx(ctx);
 | 
					 | 
				
			||||||
	bio_put(bio);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	BUG();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline bool ext4_bio_encrypted(struct bio *bio)
 | 
					static inline bool ext4_bio_encrypted(struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
| 
						 | 
					@ -104,14 +73,10 @@ static void mpage_end_io(struct bio *bio)
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ext4_bio_encrypted(bio)) {
 | 
						if (ext4_bio_encrypted(bio)) {
 | 
				
			||||||
		struct ext4_crypto_ctx *ctx = bio->bi_private;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (bio->bi_error) {
 | 
							if (bio->bi_error) {
 | 
				
			||||||
			ext4_release_crypto_ctx(ctx);
 | 
								fscrypt_release_ctx(bio->bi_private);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			INIT_WORK(&ctx->r.work, completion_pages);
 | 
								fscrypt_decrypt_bio_pages(bio->bi_private, bio);
 | 
				
			||||||
			ctx->r.bio = bio;
 | 
					 | 
				
			||||||
			queue_work(ext4_read_workqueue, &ctx->r.work);
 | 
					 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -274,11 +239,11 @@ int ext4_mpage_readpages(struct address_space *mapping,
 | 
				
			||||||
			bio = NULL;
 | 
								bio = NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (bio == NULL) {
 | 
							if (bio == NULL) {
 | 
				
			||||||
			struct ext4_crypto_ctx *ctx = NULL;
 | 
								struct fscrypt_ctx *ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (ext4_encrypted_inode(inode) &&
 | 
								if (ext4_encrypted_inode(inode) &&
 | 
				
			||||||
			    S_ISREG(inode->i_mode)) {
 | 
								    S_ISREG(inode->i_mode)) {
 | 
				
			||||||
				ctx = ext4_get_crypto_ctx(inode, GFP_NOFS);
 | 
									ctx = fscrypt_get_ctx(inode, GFP_NOFS);
 | 
				
			||||||
				if (IS_ERR(ctx))
 | 
									if (IS_ERR(ctx))
 | 
				
			||||||
					goto set_error_page;
 | 
										goto set_error_page;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -286,7 +251,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
 | 
				
			||||||
				min_t(int, nr_pages, BIO_MAX_PAGES));
 | 
									min_t(int, nr_pages, BIO_MAX_PAGES));
 | 
				
			||||||
			if (!bio) {
 | 
								if (!bio) {
 | 
				
			||||||
				if (ctx)
 | 
									if (ctx)
 | 
				
			||||||
					ext4_release_crypto_ctx(ctx);
 | 
										fscrypt_release_ctx(ctx);
 | 
				
			||||||
				goto set_error_page;
 | 
									goto set_error_page;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			bio->bi_bdev = bdev;
 | 
								bio->bi_bdev = bdev;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -945,9 +945,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
 | 
				
			||||||
	ei->i_datasync_tid = 0;
 | 
						ei->i_datasync_tid = 0;
 | 
				
			||||||
	atomic_set(&ei->i_unwritten, 0);
 | 
						atomic_set(&ei->i_unwritten, 0);
 | 
				
			||||||
	INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
 | 
						INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
	ei->i_crypt_info = NULL;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	return &ei->vfs_inode;
 | 
						return &ei->vfs_inode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1026,8 +1023,7 @@ void ext4_clear_inode(struct inode *inode)
 | 
				
			||||||
		EXT4_I(inode)->jinode = NULL;
 | 
							EXT4_I(inode)->jinode = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
	if (EXT4_I(inode)->i_crypt_info)
 | 
						fscrypt_put_encryption_info(inode, NULL);
 | 
				
			||||||
		ext4_free_encryption_info(inode, EXT4_I(inode)->i_crypt_info);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1094,6 +1090,90 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
 | 
				
			||||||
	return try_to_free_buffers(page);
 | 
						return try_to_free_buffers(page);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
 | 
					static int ext4_get_context(struct inode *inode, void *ctx, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
				
			||||||
 | 
									 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ext4_key_prefix(struct inode *inode, u8 **key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						*key = EXT4_SB(inode->i_sb)->key_prefix;
 | 
				
			||||||
 | 
						return EXT4_SB(inode->i_sb)->key_prefix_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ext4_prepare_context(struct inode *inode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ext4_convert_inline_data(inode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
 | 
				
			||||||
 | 
												void *fs_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						handle_t *handle;
 | 
				
			||||||
 | 
						int res, res2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* fs_data is null when internally used. */
 | 
				
			||||||
 | 
						if (fs_data) {
 | 
				
			||||||
 | 
							res  = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
				
			||||||
 | 
									EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
 | 
				
			||||||
 | 
									len, 0);
 | 
				
			||||||
 | 
							if (!res) {
 | 
				
			||||||
 | 
								ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
 | 
				
			||||||
 | 
								ext4_clear_inode_state(inode,
 | 
				
			||||||
 | 
										EXT4_STATE_MAY_INLINE_DATA);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return res;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handle = ext4_journal_start(inode, EXT4_HT_MISC,
 | 
				
			||||||
 | 
								ext4_jbd2_credits_xattr(inode));
 | 
				
			||||||
 | 
						if (IS_ERR(handle))
 | 
				
			||||||
 | 
							return PTR_ERR(handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 | 
				
			||||||
 | 
								EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
 | 
				
			||||||
 | 
								len, 0);
 | 
				
			||||||
 | 
						if (!res) {
 | 
				
			||||||
 | 
							ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
 | 
				
			||||||
 | 
							res = ext4_mark_inode_dirty(handle, inode);
 | 
				
			||||||
 | 
							if (res)
 | 
				
			||||||
 | 
								EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						res2 = ext4_journal_stop(handle);
 | 
				
			||||||
 | 
						if (!res)
 | 
				
			||||||
 | 
							res = res2;
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ext4_dummy_context(struct inode *inode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned ext4_max_namelen(struct inode *inode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize :
 | 
				
			||||||
 | 
							EXT4_NAME_LEN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct fscrypt_operations ext4_cryptops = {
 | 
				
			||||||
 | 
						.get_context		= ext4_get_context,
 | 
				
			||||||
 | 
						.key_prefix		= ext4_key_prefix,
 | 
				
			||||||
 | 
						.prepare_context	= ext4_prepare_context,
 | 
				
			||||||
 | 
						.set_context		= ext4_set_context,
 | 
				
			||||||
 | 
						.dummy_context		= ext4_dummy_context,
 | 
				
			||||||
 | 
						.is_encrypted		= ext4_encrypted_inode,
 | 
				
			||||||
 | 
						.empty_dir		= ext4_empty_dir,
 | 
				
			||||||
 | 
						.max_namelen		= ext4_max_namelen,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static struct fscrypt_operations ext4_cryptops = {
 | 
				
			||||||
 | 
						.is_encrypted		= ext4_encrypted_inode,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_QUOTA
 | 
					#ifdef CONFIG_QUOTA
 | 
				
			||||||
static char *quotatypes[] = INITQFNAMES;
 | 
					static char *quotatypes[] = INITQFNAMES;
 | 
				
			||||||
#define QTYPE2NAME(t) (quotatypes[t])
 | 
					#define QTYPE2NAME(t) (quotatypes[t])
 | 
				
			||||||
| 
						 | 
					@ -3693,6 +3773,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 | 
				
			||||||
	sb->s_op = &ext4_sops;
 | 
						sb->s_op = &ext4_sops;
 | 
				
			||||||
	sb->s_export_op = &ext4_export_ops;
 | 
						sb->s_export_op = &ext4_export_ops;
 | 
				
			||||||
	sb->s_xattr = ext4_xattr_handlers;
 | 
						sb->s_xattr = ext4_xattr_handlers;
 | 
				
			||||||
 | 
						sb->s_cop = &ext4_cryptops;
 | 
				
			||||||
#ifdef CONFIG_QUOTA
 | 
					#ifdef CONFIG_QUOTA
 | 
				
			||||||
	sb->dq_op = &ext4_quota_operations;
 | 
						sb->dq_op = &ext4_quota_operations;
 | 
				
			||||||
	if (ext4_has_feature_quota(sb))
 | 
						if (ext4_has_feature_quota(sb))
 | 
				
			||||||
| 
						 | 
					@ -4003,6 +4084,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 | 
				
			||||||
	ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
 | 
						ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(orig_data);
 | 
						kfree(orig_data);
 | 
				
			||||||
 | 
					#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
				
			||||||
 | 
						memcpy(sbi->key_prefix, EXT4_KEY_DESC_PREFIX,
 | 
				
			||||||
 | 
									EXT4_KEY_DESC_PREFIX_SIZE);
 | 
				
			||||||
 | 
						sbi->key_prefix_size = EXT4_KEY_DESC_PREFIX_SIZE;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cantfind_ext4:
 | 
					cantfind_ext4:
 | 
				
			||||||
| 
						 | 
					@ -5431,7 +5517,6 @@ static int __init ext4_init_fs(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __exit ext4_exit_fs(void)
 | 
					static void __exit ext4_exit_fs(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ext4_exit_crypto();
 | 
					 | 
				
			||||||
	ext4_destroy_lazyinit_thread();
 | 
						ext4_destroy_lazyinit_thread();
 | 
				
			||||||
	unregister_as_ext2();
 | 
						unregister_as_ext2();
 | 
				
			||||||
	unregister_as_ext3();
 | 
						unregister_as_ext3();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,23 +22,22 @@
 | 
				
			||||||
#include "ext4.h"
 | 
					#include "ext4.h"
 | 
				
			||||||
#include "xattr.h"
 | 
					#include "xattr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
 | 
					 | 
				
			||||||
static const char *ext4_encrypted_get_link(struct dentry *dentry,
 | 
					static const char *ext4_encrypted_get_link(struct dentry *dentry,
 | 
				
			||||||
					   struct inode *inode,
 | 
										   struct inode *inode,
 | 
				
			||||||
					   struct delayed_call *done)
 | 
										   struct delayed_call *done)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct page *cpage = NULL;
 | 
						struct page *cpage = NULL;
 | 
				
			||||||
	char *caddr, *paddr = NULL;
 | 
						char *caddr, *paddr = NULL;
 | 
				
			||||||
	struct ext4_str cstr, pstr;
 | 
						struct fscrypt_str cstr, pstr;
 | 
				
			||||||
	struct ext4_encrypted_symlink_data *sd;
 | 
						struct fscrypt_symlink_data *sd;
 | 
				
			||||||
	loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
 | 
						loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	u32 plen, max_size = inode->i_sb->s_blocksize;
 | 
						u32 max_size = inode->i_sb->s_blocksize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dentry)
 | 
						if (!dentry)
 | 
				
			||||||
		return ERR_PTR(-ECHILD);
 | 
							return ERR_PTR(-ECHILD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = ext4_get_encryption_info(inode);
 | 
						res = fscrypt_get_encryption_info(inode);
 | 
				
			||||||
	if (res)
 | 
						if (res)
 | 
				
			||||||
		return ERR_PTR(res);
 | 
							return ERR_PTR(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,30 +53,27 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Symlink is encrypted */
 | 
						/* Symlink is encrypted */
 | 
				
			||||||
	sd = (struct ext4_encrypted_symlink_data *)caddr;
 | 
						sd = (struct fscrypt_symlink_data *)caddr;
 | 
				
			||||||
	cstr.name = sd->encrypted_path;
 | 
						cstr.name = sd->encrypted_path;
 | 
				
			||||||
	cstr.len  = le16_to_cpu(sd->len);
 | 
						cstr.len  = le16_to_cpu(sd->len);
 | 
				
			||||||
	if ((cstr.len +
 | 
						if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
 | 
				
			||||||
	     sizeof(struct ext4_encrypted_symlink_data) - 1) >
 | 
					 | 
				
			||||||
	    max_size) {
 | 
					 | 
				
			||||||
		/* Symlink data on the disk is corrupted */
 | 
							/* Symlink data on the disk is corrupted */
 | 
				
			||||||
		res = -EFSCORRUPTED;
 | 
							res = -EFSCORRUPTED;
 | 
				
			||||||
		goto errout;
 | 
							goto errout;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ?
 | 
					
 | 
				
			||||||
		EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len;
 | 
						res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
 | 
				
			||||||
	paddr = kmalloc(plen + 1, GFP_NOFS);
 | 
						if (res)
 | 
				
			||||||
	if (!paddr) {
 | 
					 | 
				
			||||||
		res = -ENOMEM;
 | 
					 | 
				
			||||||
		goto errout;
 | 
							goto errout;
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
	pstr.name = paddr;
 | 
						res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
 | 
				
			||||||
	pstr.len = plen;
 | 
					 | 
				
			||||||
	res = _ext4_fname_disk_to_usr(inode, NULL, &cstr, &pstr);
 | 
					 | 
				
			||||||
	if (res < 0)
 | 
						if (res < 0)
 | 
				
			||||||
		goto errout;
 | 
							goto errout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						paddr = pstr.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Null-terminate the name */
 | 
						/* Null-terminate the name */
 | 
				
			||||||
	if (res <= plen)
 | 
						if (res <= pstr.len)
 | 
				
			||||||
		paddr[res] = '\0';
 | 
							paddr[res] = '\0';
 | 
				
			||||||
	if (cpage)
 | 
						if (cpage)
 | 
				
			||||||
		put_page(cpage);
 | 
							put_page(cpage);
 | 
				
			||||||
| 
						 | 
					@ -99,7 +95,6 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {
 | 
				
			||||||
	.listxattr	= ext4_listxattr,
 | 
						.listxattr	= ext4_listxattr,
 | 
				
			||||||
	.removexattr	= generic_removexattr,
 | 
						.removexattr	= generic_removexattr,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct inode_operations ext4_symlink_inode_operations = {
 | 
					const struct inode_operations ext4_symlink_inode_operations = {
 | 
				
			||||||
	.readlink	= generic_readlink,
 | 
						.readlink	= generic_readlink,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue