Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a551d7c8 authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

Merge branch 'fscrypt' into dev

parents 0cb80b48 6a34e4d2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5138,6 +5138,7 @@ F: include/linux/fscache*.h
FS-CRYPTO: FILE SYSTEM LEVEL ENCRYPTION SUPPORT
M:	Theodore Y. Ts'o <tytso@mit.edu>
M:	Jaegeuk Kim <jaegeuk@kernel.org>
L:	linux-fsdevel@vger.kernel.org
S:	Supported
F:	fs/crypto/
F:	include/linux/fscrypto.h
+0 −2
Original line number Diff line number Diff line
@@ -8,9 +8,7 @@ config FS_ENCRYPTION
	select CRYPTO_XTS
	select CRYPTO_CTS
	select CRYPTO_CTR
	select CRYPTO_SHA256
	select KEYS
	select ENCRYPTED_KEYS
	help
	  Enable encryption of files and directories.  This
	  feature is similar to ecryptfs, but it is more memory
+83 −55
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@
#include <linux/bio.h>
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/fscrypto.h>
#include "fscrypt_private.h"

static unsigned int num_prealloc_crypto_pages = 32;
static unsigned int num_prealloc_crypto_ctxs = 128;
@@ -63,7 +63,7 @@ void fscrypt_release_ctx(struct fscrypt_ctx *ctx)
{
	unsigned long flags;

	if (ctx->flags & FS_WRITE_PATH_FL && ctx->w.bounce_page) {
	if (ctx->flags & FS_CTX_HAS_BOUNCE_BUFFER_FL && ctx->w.bounce_page) {
		mempool_free(ctx->w.bounce_page, fscrypt_bounce_page_pool);
		ctx->w.bounce_page = NULL;
	}
@@ -121,7 +121,7 @@ struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags)
	} else {
		ctx->flags &= ~FS_CTX_REQUIRES_FREE_ENCRYPT_FL;
	}
	ctx->flags &= ~FS_WRITE_PATH_FL;
	ctx->flags &= ~FS_CTX_HAS_BOUNCE_BUFFER_FL;
	return ctx;
}
EXPORT_SYMBOL(fscrypt_get_ctx);
@@ -147,9 +147,9 @@ typedef enum {
} fscrypt_direction_t;

static int do_page_crypto(const struct inode *inode,
			fscrypt_direction_t rw, pgoff_t index,
			fscrypt_direction_t rw, u64 lblk_num,
			struct page *src_page, struct page *dest_page,
			unsigned int src_len, unsigned int src_offset,
			unsigned int len, unsigned int offs,
			gfp_t gfp_flags)
{
	struct {
@@ -163,6 +163,8 @@ static int do_page_crypto(const struct inode *inode,
	struct crypto_skcipher *tfm = ci->ci_ctfm;
	int res = 0;

	BUG_ON(len == 0);

	req = skcipher_request_alloc(tfm, gfp_flags);
	if (!req) {
		printk_ratelimited(KERN_ERR
@@ -176,14 +178,14 @@ static int do_page_crypto(const struct inode *inode,
		page_crypt_complete, &ecr);

	BUILD_BUG_ON(sizeof(xts_tweak) != FS_XTS_TWEAK_SIZE);
	xts_tweak.index = cpu_to_le64(index);
	xts_tweak.index = cpu_to_le64(lblk_num);
	memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding));

	sg_init_table(&dst, 1);
	sg_set_page(&dst, dest_page, src_len, src_offset);
	sg_set_page(&dst, dest_page, len, offs);
	sg_init_table(&src, 1);
	sg_set_page(&src, src_page, src_len, src_offset);
	skcipher_request_set_crypt(req, &src, &dst, src_len, &xts_tweak);
	sg_set_page(&src, src_page, len, offs);
	skcipher_request_set_crypt(req, &src, &dst, len, &xts_tweak);
	if (rw == FS_DECRYPT)
		res = crypto_skcipher_decrypt(req);
	else
@@ -208,69 +210,87 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags)
	ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
	if (ctx->w.bounce_page == NULL)
		return ERR_PTR(-ENOMEM);
	ctx->flags |= FS_WRITE_PATH_FL;
	ctx->flags |= FS_CTX_HAS_BOUNCE_BUFFER_FL;
	return ctx->w.bounce_page;
}

/**
 * fscypt_encrypt_page() - Encrypts a page
 * @inode:     The inode for which the encryption should take place
 * @plaintext_page:   The page to encrypt. Must be locked.
 * @plaintext_len:    Length of plaintext within page
 * @plaintext_offset: Offset of plaintext within page
 * @index:            Index for encryption. This is mainly the page index, but
 *                    but might be different for multiple calls on same page.
 * @page:      The page to encrypt. Must be locked for bounce-page
 *             encryption.
 * @len:       Length of data to encrypt in @page and encrypted
 *             data in returned page.
 * @offs:      Offset of data within @page and returned
 *             page holding encrypted data.
 * @lblk_num:  Logical block number. This must be unique for multiple
 *             calls with same inode, except when overwriting
 *             previously written data.
 * @gfp_flags: The gfp flag for memory allocation
 *
 * Encrypts plaintext_page using the ctx encryption context. If
 * the filesystem supports it, encryption is performed in-place, otherwise a
 * new ciphertext_page is allocated and returned.
 * Encrypts @page using the ctx encryption context. Performs encryption
 * either in-place or into a newly allocated bounce page.
 * Called on the page write path.
 *
 * Called on the page write path.  The caller must call
 * Bounce page allocation is the default.
 * In this case, the contents of @page are encrypted and stored in an
 * allocated bounce page. @page has to be locked and the caller must call
 * fscrypt_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
 * In-place encryption is used by setting the FS_CFLG_OWN_PAGES flag in
 * fscrypt_operations. Here, the input-page is returned with its content
 * encrypted.
 *
 * Return: A page with the encrypted content on success. Else, an
 * error value or NULL.
 */
struct page *fscrypt_encrypt_page(const struct inode *inode,
				struct page *plaintext_page,
				unsigned int plaintext_len,
				unsigned int plaintext_offset,
				pgoff_t index, gfp_t gfp_flags)
				struct page *page,
				unsigned int len,
				unsigned int offs,
				u64 lblk_num, gfp_t gfp_flags)

{
	struct fscrypt_ctx *ctx;
	struct page *ciphertext_page = plaintext_page;
	struct page *ciphertext_page = page;
	int err;

	BUG_ON(plaintext_len % FS_CRYPTO_BLOCK_SIZE != 0);
	BUG_ON(len % FS_CRYPTO_BLOCK_SIZE != 0);

	if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) {
		/* with inplace-encryption we just encrypt the page */
		err = do_page_crypto(inode, FS_ENCRYPT, lblk_num,
					page, ciphertext_page,
					len, offs, gfp_flags);
		if (err)
			return ERR_PTR(err);

		return ciphertext_page;
	}

	BUG_ON(!PageLocked(page));

	ctx = fscrypt_get_ctx(inode, gfp_flags);
	if (IS_ERR(ctx))
		return (struct page *)ctx;

	if (!(inode->i_sb->s_cop->flags & FS_CFLG_INPLACE_ENCRYPTION)) {
	/* 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 = do_page_crypto(inode, FS_ENCRYPT, index,
					plaintext_page, ciphertext_page,
					plaintext_len, plaintext_offset,
					gfp_flags);
	ctx->w.control_page = page;
	err = do_page_crypto(inode, FS_ENCRYPT, lblk_num,
					page, ciphertext_page,
					len, offs, gfp_flags);
	if (err) {
		ciphertext_page = ERR_PTR(err);
		goto errout;
	}
	if (!(inode->i_sb->s_cop->flags & FS_CFLG_INPLACE_ENCRYPTION)) {
	SetPagePrivate(ciphertext_page);
	set_page_private(ciphertext_page, (unsigned long)ctx);
	lock_page(ciphertext_page);
	}
	return ciphertext_page;

errout:
@@ -281,11 +301,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);

/**
 * fscrypt_decrypt_page() - Decrypts a page in-place
 * @inode: Encrypted inode to decrypt.
 * @page:  The page to decrypt. Must be locked.
 * @inode:     The corresponding inode for the page to decrypt.
 * @page:      The page to decrypt. Must be locked in case
 *             it is a writeback page (FS_CFLG_OWN_PAGES unset).
 * @len:       Number of bytes in @page to be decrypted.
 * @offs:      Start of data in @page.
 * @index: Index for encryption.
 * @lblk_num:  Logical block number.
 *
 * Decrypts page in-place using the ctx encryption context.
 *
@@ -294,10 +315,13 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);
 * Return: Zero on success, non-zero otherwise.
 */
int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
			unsigned int len, unsigned int offs, pgoff_t index)
			unsigned int len, unsigned int offs, u64 lblk_num)
{
	return do_page_crypto(inode, FS_DECRYPT, page->index, page, page, len, offs,
			GFP_NOFS);
	if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
		BUG_ON(!PageLocked(page));

	return do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, len,
			offs, GFP_NOFS);
}
EXPORT_SYMBOL(fscrypt_decrypt_page);

@@ -501,17 +525,22 @@ static void fscrypt_destroy(void)

/**
 * fscrypt_initialize() - allocate major buffers for fs encryption.
 * @cop_flags:  fscrypt operations flags
 *
 * 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 fscrypt_initialize(void)
int fscrypt_initialize(unsigned int cop_flags)
{
	int i, res = -ENOMEM;

	if (fscrypt_bounce_page_pool)
	/*
	 * No need to allocate a bounce page pool if there already is one or
	 * this FS won't use it.
	 */
	if (cop_flags & FS_CFLG_OWN_PAGES || fscrypt_bounce_page_pool)
		return 0;

	mutex_lock(&fscrypt_init_mutex);
@@ -540,7 +569,6 @@ int fscrypt_initialize(void)
	mutex_unlock(&fscrypt_init_mutex);
	return res;
}
EXPORT_SYMBOL(fscrypt_initialize);

/**
 * fscrypt_init() - Set up for fs encryption.
+2 −2
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@

#include <linux/scatterlist.h>
#include <linux/ratelimit.h>
#include <linux/fscrypto.h>
#include "fscrypt_private.h"

/**
 * fname_crypt_complete() - completion callback for filename crypto
@@ -350,7 +350,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
		fname->disk_name.len = iname->len;
		return 0;
	}
	ret = get_crypt_info(dir);
	ret = fscrypt_get_crypt_info(dir);
	if (ret && ret != -EOPNOTSUPP)
		return ret;

+93 −0
Original line number Diff line number Diff line
/*
 * fscrypt_private.h
 *
 * Copyright (C) 2015, Google, Inc.
 *
 * This contains encryption key functions.
 *
 * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
 */

#ifndef _FSCRYPT_PRIVATE_H
#define _FSCRYPT_PRIVATE_H

#include <linux/fscrypto.h>

#define FS_FNAME_CRYPTO_DIGEST_SIZE	32

/* Encryption parameters */
#define FS_XTS_TWEAK_SIZE		16
#define FS_AES_128_ECB_KEY_SIZE		16
#define FS_AES_256_GCM_KEY_SIZE		32
#define FS_AES_256_CBC_KEY_SIZE		32
#define FS_AES_256_CTS_KEY_SIZE		32
#define FS_AES_256_XTS_KEY_SIZE		64
#define FS_MAX_KEY_SIZE			64

#define FS_KEY_DESC_PREFIX		"fscrypt:"
#define FS_KEY_DESC_PREFIX_SIZE		8

#define FS_KEY_DERIVATION_NONCE_SIZE		16

/**
 * 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: Flags
 *  8 bytes: Master Key descriptor
 *  16 bytes: Encryption Key derivation nonce
 */
struct fscrypt_context {
	u8 format;
	u8 contents_encryption_mode;
	u8 filenames_encryption_mode;
	u8 flags;
	u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
	u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
} __packed;

#define FS_ENCRYPTION_CONTEXT_FORMAT_V1		1

/* This is passed in from userspace into the kernel keyring */
struct fscrypt_key {
	u32 mode;
	u8 raw[FS_MAX_KEY_SIZE];
	u32 size;
} __packed;

/*
 * A pointer to this structure is stored in the file system's in-core
 * representation of an inode.
 */
struct fscrypt_info {
	u8 ci_data_mode;
	u8 ci_filename_mode;
	u8 ci_flags;
	struct crypto_skcipher *ci_ctfm;
	struct key *ci_keyring_key;
	u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
};

#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL		0x00000001
#define FS_CTX_HAS_BOUNCE_BUFFER_FL		0x00000002

struct fscrypt_completion_result {
	struct completion completion;
	int res;
};

#define DECLARE_FS_COMPLETION_RESULT(ecr) \
	struct fscrypt_completion_result ecr = { \
		COMPLETION_INITIALIZER((ecr).completion), 0 }


/* crypto.c */
int fscrypt_initialize(unsigned int cop_flags);

/* keyinfo.c */
extern int fscrypt_get_crypt_info(struct inode *);

#endif /* _FSCRYPT_PRIVATE_H */
Loading