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

Commit 6da22013 authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

Merge branch 'fscrypt' into origin

parents a2f6d9c4 a6e08912
Loading
Loading
Loading
Loading
+51 −32
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ EXPORT_SYMBOL(fscrypt_release_ctx);
 * Return: An allocated and initialized encryption context on success; error
 * value or NULL otherwise.
 */
struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags)
struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags)
{
	struct fscrypt_ctx *ctx = NULL;
	struct fscrypt_info *ci = inode->i_crypt_info;
@@ -146,9 +146,10 @@ typedef enum {
	FS_ENCRYPT,
} fscrypt_direction_t;

static int do_page_crypto(struct inode *inode,
static int do_page_crypto(const struct inode *inode,
			fscrypt_direction_t rw, pgoff_t index,
			struct page *src_page, struct page *dest_page,
			unsigned int src_len, unsigned int src_offset,
			gfp_t gfp_flags)
{
	struct {
@@ -179,10 +180,10 @@ static int do_page_crypto(struct inode *inode,
	memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding));

	sg_init_table(&dst, 1);
	sg_set_page(&dst, dest_page, PAGE_SIZE, 0);
	sg_set_page(&dst, dest_page, src_len, src_offset);
	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);
	sg_set_page(&src, src_page, src_len, src_offset);
	skcipher_request_set_crypt(req, &src, &dst, src_len, &xts_tweak);
	if (rw == FS_DECRYPT)
		res = crypto_skcipher_decrypt(req);
	else
@@ -215,10 +216,15 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags)
 * 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.
 * @gfp_flags:        The gfp flag for memory allocation
 *
 * Allocates a ciphertext page and encrypts plaintext_page into it using the ctx
 * encryption context.
 * 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.
 *
 * Called on the page write path.  The caller must call
 * fscrypt_restore_control_page() on the returned ciphertext page to
@@ -227,35 +233,44 @@ static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags)
 * Return: An allocated page with the encrypted content on success. Else, an
 * error value or NULL.
 */
struct page *fscrypt_encrypt_page(struct inode *inode,
				struct page *plaintext_page, gfp_t gfp_flags)
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 fscrypt_ctx *ctx;
	struct page *ciphertext_page = NULL;
	struct page *ciphertext_page = plaintext_page;
	int err;

	BUG_ON(!PageLocked(plaintext_page));
	BUG_ON(plaintext_len % FS_CRYPTO_BLOCK_SIZE != 0);

	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, plaintext_page->index,
	err = do_page_crypto(inode, FS_ENCRYPT, index,
					plaintext_page, ciphertext_page,
					plaintext_len, plaintext_offset,
					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:
@@ -265,8 +280,12 @@ struct page *fscrypt_encrypt_page(struct inode *inode,
EXPORT_SYMBOL(fscrypt_encrypt_page);

/**
 * f2crypt_decrypt_page() - Decrypts a page in-place
 * fscrypt_decrypt_page() - Decrypts a page in-place
 * @inode: Encrypted inode to decrypt.
 * @page:  The page to decrypt. Must be locked.
 * @len:   Number of bytes in @page to be decrypted.
 * @offs:  Start of data in @page.
 * @index: Index for encryption.
 *
 * Decrypts page in-place using the ctx encryption context.
 *
@@ -274,16 +293,15 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);
 *
 * Return: Zero on success, non-zero otherwise.
 */
int fscrypt_decrypt_page(struct page *page)
int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
			unsigned int len, unsigned int offs, pgoff_t index)
{
	BUG_ON(!PageLocked(page));

	return do_page_crypto(page->mapping->host,
			FS_DECRYPT, page->index, page, page, GFP_NOFS);
	return do_page_crypto(inode, FS_DECRYPT, page->index, page, page, len, offs,
			GFP_NOFS);
}
EXPORT_SYMBOL(fscrypt_decrypt_page);

int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk,
int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
				sector_t pblk, unsigned int len)
{
	struct fscrypt_ctx *ctx;
@@ -306,7 +324,7 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk,
	while (len--) {
		err = do_page_crypto(inode, FS_ENCRYPT, lblk,
					ZERO_PAGE(0), ciphertext_page,
					GFP_NOFS);
					PAGE_SIZE, 0, GFP_NOFS);
		if (err)
			goto errout;

@@ -414,7 +432,8 @@ static void completion_pages(struct work_struct *work)

	bio_for_each_segment_all(bv, bio, i) {
		struct page *page = bv->bv_page;
		int ret = fscrypt_decrypt_page(page);
		int ret = fscrypt_decrypt_page(page->mapping->host, page,
				PAGE_SIZE, 0, page->index);

		if (ret) {
			WARN_ON_ONCE(1);
+23 −34
Original line number Diff line number Diff line
@@ -39,65 +39,54 @@ static void fname_crypt_complete(struct crypto_async_request *req, int res)
static int fname_encrypt(struct inode *inode,
			const struct qstr *iname, struct fscrypt_str *oname)
{
	u32 ciphertext_len;
	struct skcipher_request *req = NULL;
	DECLARE_FS_COMPLETION_RESULT(ecr);
	struct fscrypt_info *ci = inode->i_crypt_info;
	struct crypto_skcipher *tfm = ci->ci_ctfm;
	int res = 0;
	char iv[FS_CRYPTO_BLOCK_SIZE];
	struct scatterlist src_sg, dst_sg;
	struct scatterlist sg;
	int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
	char *workbuf, buf[32], *alloc_buf = NULL;
	unsigned lim;
	unsigned int lim;
	unsigned int cryptlen;

	lim = inode->i_sb->s_cop->max_namelen(inode);
	if (iname->len <= 0 || iname->len > lim)
		return -EIO;

	ciphertext_len = max(iname->len, (u32)FS_CRYPTO_BLOCK_SIZE);
	ciphertext_len = round_up(ciphertext_len, padding);
	ciphertext_len = min(ciphertext_len, lim);
	/*
	 * Copy the filename to the output buffer for encrypting in-place and
	 * pad it with the needed number of NUL bytes.
	 */
	cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE);
	cryptlen = round_up(cryptlen, padding);
	cryptlen = min(cryptlen, lim);
	memcpy(oname->name, iname->name, iname->len);
	memset(oname->name + iname->len, 0, cryptlen - iname->len);

	if (ciphertext_len <= sizeof(buf)) {
		workbuf = buf;
	} else {
		alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
		if (!alloc_buf)
			return -ENOMEM;
		workbuf = alloc_buf;
	}
	/* Initialize the IV */
	memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);

	/* Allocate request */
	/* Set up the encryption request */
	req = skcipher_request_alloc(tfm, GFP_NOFS);
	if (!req) {
		printk_ratelimited(KERN_ERR
			"%s: crypto_request_alloc() failed\n", __func__);
		kfree(alloc_buf);
			"%s: skcipher_request_alloc() failed\n", __func__);
		return -ENOMEM;
	}
	skcipher_request_set_callback(req,
			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
			fname_crypt_complete, &ecr);
	sg_init_one(&sg, oname->name, cryptlen);
	skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);

	/* 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, FS_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);
	/* Do the encryption */
	res = crypto_skcipher_encrypt(req);
	if (res == -EINPROGRESS || res == -EBUSY) {
		/* Request is being completed asynchronously; wait for it */
		wait_for_completion(&ecr.completion);
		res = ecr.res;
	}
	kfree(alloc_buf);
	skcipher_request_free(req);
	if (res < 0) {
		printk_ratelimited(KERN_ERR
@@ -105,7 +94,7 @@ static int fname_encrypt(struct inode *inode,
		return res;
	}

	oname->len = ciphertext_len;
	oname->len = cryptlen;
	return 0;
}

@@ -220,7 +209,7 @@ static int digest_decode(const char *src, int len, char *dst)
	return cp - dst;
}

u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen)
u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen)
{
	int padding = 32;
	struct fscrypt_info *ci = inode->i_crypt_info;
@@ -238,7 +227,7 @@ EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
 * Allocates an output buffer that is sufficient for the crypto operation
 * specified by the context and the direction.
 */
int fscrypt_fname_alloc_buffer(struct inode *inode,
int fscrypt_fname_alloc_buffer(const struct inode *inode,
				u32 ilen, struct fscrypt_str *crypto_str)
{
	unsigned int olen = fscrypt_fname_encrypted_size(inode, ilen);
+13 −3
Original line number Diff line number Diff line
@@ -185,7 +185,7 @@ int get_crypt_info(struct inode *inode)
	struct crypto_skcipher *ctfm;
	const char *cipher_str;
	int keysize;
	u8 raw_key[FS_MAX_KEY_SIZE];
	u8 *raw_key = NULL;
	int res;

	res = fscrypt_initialize();
@@ -238,6 +238,15 @@ int get_crypt_info(struct inode *inode)
	if (res)
		goto out;

	/*
	 * This cannot be a stack buffer because it is passed to the scatterlist
	 * crypto API as part of key derivation.
	 */
	res = -ENOMEM;
	raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS);
	if (!raw_key)
		goto out;

	if (fscrypt_dummy_context_enabled(inode)) {
		memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
		goto got_key;
@@ -276,7 +285,8 @@ int get_crypt_info(struct inode *inode)
	if (res)
		goto out;

	memzero_explicit(raw_key, sizeof(raw_key));
	kzfree(raw_key);
	raw_key = NULL;
	if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
		put_crypt_info(crypt_info);
		goto retry;
@@ -287,7 +297,7 @@ int get_crypt_info(struct inode *inode)
	if (res == -ENOKEY)
		res = 0;
	put_crypt_info(crypt_info);
	memzero_explicit(raw_key, sizeof(raw_key));
	kzfree(raw_key);
	return res;
}

+5 −2
Original line number Diff line number Diff line
@@ -1169,7 +1169,8 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
	if (unlikely(err))
		page_zero_new_buffers(page, from, to);
	else if (decrypt)
		err = fscrypt_decrypt_page(page);
		err = fscrypt_decrypt_page(page->mapping->host, page,
				PAGE_SIZE, 0, page->index);
	return err;
}
#endif
@@ -3746,7 +3747,9 @@ static int __ext4_block_zero_page_range(handle_t *handle,
			/* We expect the key to be set. */
			BUG_ON(!fscrypt_has_encryption_key(inode));
			BUG_ON(blocksize != PAGE_SIZE);
			WARN_ON_ONCE(fscrypt_decrypt_page(page));
			BUG_ON(!PageLocked(page));
			WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host,
						page, PAGE_SIZE, 0, page->index));
		}
	}
	if (ext4_should_journal_data(inode)) {
+2 −1
Original line number Diff line number Diff line
@@ -470,7 +470,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
		gfp_t gfp_flags = GFP_NOFS;

	retry_encrypt:
		data_page = fscrypt_encrypt_page(inode, page, gfp_flags);
		data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0,
						page->index, gfp_flags);
		if (IS_ERR(data_page)) {
			ret = PTR_ERR(data_page);
			if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
Loading