diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-10-22 19:31:08 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-10-22 19:31:08 -0300 |
commit | 670027c507e99521d416994a18a498def9ef2ea3 (patch) | |
tree | 74b4d761a9e7904a4f8aa4b58b2dc9801f22284d /fs | |
parent | d0b2f91bede3bd5e3d24dd6803e56eee959c1797 (diff) |
Linux-libre 4.8.3-gnupck-4.8.3-gnu
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/crypto.c | 536 | ||||
-rw-r--r-- | fs/ext4/crypto_fname.c | 468 | ||||
-rw-r--r-- | fs/ext4/crypto_key.c | 274 | ||||
-rw-r--r-- | fs/ext4/crypto_policy.c | 232 | ||||
-rw-r--r-- | fs/ext4/ext4_crypto.h | 159 | ||||
-rw-r--r-- | fs/xfs/xfs_xattr.c | 1 |
6 files changed, 1 insertions, 1669 deletions
diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c deleted file mode 100644 index 6a6c27373..000000000 --- a/fs/ext4/crypto.c +++ /dev/null @@ -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, -}; diff --git a/fs/ext4/crypto_fname.c b/fs/ext4/crypto_fname.c deleted file mode 100644 index 1a2f36040..000000000 --- a/fs/ext4/crypto_fname.c +++ /dev/null @@ -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; -} diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c deleted file mode 100644 index 0129d688d..000000000 --- a/fs/ext4/crypto_key.c +++ /dev/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); -} diff --git a/fs/ext4/crypto_policy.c b/fs/ext4/crypto_policy.c deleted file mode 100644 index 8a9feb341..000000000 --- a/fs/ext4/crypto_policy.c +++ /dev/null @@ -1,232 +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 (!inode_owner_or_capable(inode)) - return -EACCES; - - 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; -} diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h deleted file mode 100644 index 1f73c2971..000000000 --- a/fs/ext4/ext4_crypto.h +++ /dev/null @@ -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 */ diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index ea62245fe..62900938f 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -147,6 +147,7 @@ __xfs_xattr_put_listent( arraytop = context->count + prefix_len + namelen + 1; if (arraytop > context->firstu) { context->count = -1; /* insufficient space */ + context->seen_enough = 1; return 0; } offset = (char *)context->alist + context->count; |