Loading fs/crypto/crypto.c +13 −13 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include <linux/dcache.h> #include <linux/namei.h> #include <linux/fscrypto.h> #include <linux/ecryptfs.h> static unsigned int num_prealloc_crypto_pages = 32; static unsigned int num_prealloc_crypto_ctxs = 128; Loading Loading @@ -128,11 +127,11 @@ struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags) EXPORT_SYMBOL(fscrypt_get_ctx); /** * fscrypt_complete() - The completion callback for page encryption * @req: The asynchronous encryption request context * @res: The result of the encryption operation * page_crypt_complete() - completion callback for page crypto * @req: The asynchronous cipher request context * @res: The result of the cipher operation */ static void fscrypt_complete(struct crypto_async_request *req, int res) static void page_crypt_complete(struct crypto_async_request *req, int res) { struct fscrypt_completion_result *ecr = req->data; Loading @@ -152,7 +151,10 @@ static int do_page_crypto(struct inode *inode, struct page *src_page, struct page *dest_page, gfp_t gfp_flags) { u8 xts_tweak[FS_XTS_TWEAK_SIZE]; struct { __le64 index; u8 padding[FS_XTS_TWEAK_SIZE - sizeof(__le64)]; } xts_tweak; struct skcipher_request *req = NULL; DECLARE_FS_COMPLETION_RESULT(ecr); struct scatterlist dst, src; Loading @@ -170,19 +172,17 @@ static int do_page_crypto(struct inode *inode, skcipher_request_set_callback( req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, fscrypt_complete, &ecr); page_crypt_complete, &ecr); BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index)); memcpy(xts_tweak, &index, sizeof(index)); memset(&xts_tweak[sizeof(index)], 0, FS_XTS_TWEAK_SIZE - sizeof(index)); BUILD_BUG_ON(sizeof(xts_tweak) != FS_XTS_TWEAK_SIZE); xts_tweak.index = cpu_to_le64(index); memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding)); 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); skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, &xts_tweak); if (rw == FS_DECRYPT) res = crypto_skcipher_decrypt(req); else Loading fs/crypto/fname.c +61 −71 Original line number Diff line number Diff line Loading @@ -10,21 +10,16 @@ * This has not yet undergone a rigorous security audit. */ #include <keys/encrypted-type.h> #include <keys/user-type.h> #include <linux/scatterlist.h> #include <linux/ratelimit.h> #include <linux/fscrypto.h> static u32 size_round_up(size_t size, size_t blksize) { return ((size + blksize - 1) / blksize) * blksize; } /** * dir_crypt_complete() - * fname_crypt_complete() - completion callback for filename crypto * @req: The asynchronous cipher request context * @res: The result of the cipher operation */ static void dir_crypt_complete(struct crypto_async_request *req, int res) static void fname_crypt_complete(struct crypto_async_request *req, int res) { struct fscrypt_completion_result *ecr = req->data; Loading @@ -35,90 +30,80 @@ static void dir_crypt_complete(struct crypto_async_request *req, int res) } /** * fname_encrypt() - * fname_encrypt() - encrypt a filename * * 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. * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ 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 = (iname->len < FS_CRYPTO_BLOCK_SIZE) ? FS_CRYPTO_BLOCK_SIZE : iname->len; ciphertext_len = size_round_up(ciphertext_len, padding); ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len; /* * 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, 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); fname_crypt_complete, &ecr); sg_init_one(&sg, oname->name, cryptlen); skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); /* 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) if (res < 0) { printk_ratelimited(KERN_ERR "%s: Error (error code %d)\n", __func__, res); oname->len = ciphertext_len; return res; } /* * 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. oname->len = cryptlen; return 0; } /** * fname_decrypt() - decrypt a filename * * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ static int fname_decrypt(struct inode *inode, const struct fscrypt_str *iname, Loading Loading @@ -146,7 +131,7 @@ static int fname_decrypt(struct inode *inode, } skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, dir_crypt_complete, &ecr); fname_crypt_complete, &ecr); /* Initialize IV */ memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); Loading @@ -168,7 +153,7 @@ static int fname_decrypt(struct inode *inode, } oname->len = strnlen(oname->name, iname->len); return oname->len; return 0; } static const char *lookup_table = Loading Loading @@ -231,9 +216,8 @@ u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen) if (ci) padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); if (ilen < FS_CRYPTO_BLOCK_SIZE) ilen = FS_CRYPTO_BLOCK_SIZE; return size_round_up(ilen, padding); ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE); return round_up(ilen, padding); } EXPORT_SYMBOL(fscrypt_fname_encrypted_size); Loading Loading @@ -279,6 +263,10 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer); /** * fscrypt_fname_disk_to_usr() - converts a filename from disk space to user * space * * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ int fscrypt_fname_disk_to_usr(struct inode *inode, u32 hash, u32 minor_hash, Loading @@ -287,13 +275,12 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, { const struct qstr qname = FSTR_TO_QSTR(iname); char buf[24]; int ret; if (fscrypt_is_dot_dotdot(&qname)) { oname->name[0] = '.'; oname->name[iname->len - 1] = '.'; oname->len = iname->len; return oname->len; return 0; } if (iname->len < FS_CRYPTO_BLOCK_SIZE) Loading @@ -303,9 +290,9 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, return fname_decrypt(inode, iname, oname); if (iname->len <= FS_FNAME_CRYPTO_DIGEST_SIZE) { ret = digest_encode(iname->name, iname->len, oname->name); oname->len = ret; return ret; oname->len = digest_encode(iname->name, iname->len, oname->name); return 0; } if (hash) { memcpy(buf, &hash, 4); Loading @@ -315,15 +302,18 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, } 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; oname->len = 1 + digest_encode(buf, 24, oname->name + 1); return 0; } EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); /** * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk * space * * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ int fscrypt_fname_usr_to_disk(struct inode *inode, const struct qstr *iname, Loading @@ -333,7 +323,7 @@ int fscrypt_fname_usr_to_disk(struct inode *inode, oname->name[0] = '.'; oname->name[iname->len - 1] = '.'; oname->len = iname->len; return oname->len; return 0; } if (inode->i_crypt_info) return fname_encrypt(inode, iname, oname); Loading Loading @@ -367,10 +357,10 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, if (dir->i_crypt_info) { ret = fscrypt_fname_alloc_buffer(dir, iname->len, &fname->crypto_buf); if (ret < 0) if (ret) return ret; ret = fname_encrypt(dir, iname, &fname->crypto_buf); if (ret < 0) if (ret) goto errout; fname->disk_name.name = fname->crypto_buf.name; fname->disk_name.len = fname->crypto_buf.len; Loading fs/crypto/keyinfo.c +58 −29 Original line number Diff line number Diff line Loading @@ -8,11 +8,8 @@ * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. */ #include <keys/encrypted-type.h> #include <keys/user-type.h> #include <linux/random.h> #include <linux/scatterlist.h> #include <uapi/linux/keyctl.h> #include <linux/fscrypto.h> static void derive_crypt_complete(struct crypto_async_request *req, int rc) Loading Loading @@ -139,6 +136,38 @@ out: return res; } static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, const char **cipher_str_ret, int *keysize_ret) { if (S_ISREG(inode->i_mode)) { if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) { *cipher_str_ret = "xts(aes)"; *keysize_ret = FS_AES_256_XTS_KEY_SIZE; return 0; } pr_warn_once("fscrypto: unsupported contents encryption mode " "%d for inode %lu\n", ci->ci_data_mode, inode->i_ino); return -ENOKEY; } if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) { *cipher_str_ret = "cts(cbc(aes))"; *keysize_ret = FS_AES_256_CTS_KEY_SIZE; return 0; } pr_warn_once("fscrypto: unsupported filenames encryption mode " "%d for inode %lu\n", ci->ci_filename_mode, inode->i_ino); return -ENOKEY; } pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n", (inode->i_mode & S_IFMT), inode->i_ino); return -ENOKEY; } static void put_crypt_info(struct fscrypt_info *ci) { if (!ci) Loading @@ -155,8 +184,8 @@ int get_crypt_info(struct inode *inode) struct fscrypt_context ctx; struct crypto_skcipher *ctfm; const char *cipher_str; u8 raw_key[FS_MAX_KEY_SIZE]; u8 mode; int keysize; u8 *raw_key = NULL; int res; res = fscrypt_initialize(); Loading @@ -179,13 +208,19 @@ retry: if (res < 0) { if (!fscrypt_dummy_context_enabled(inode)) return res; ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; ctx.flags = 0; } else if (res != sizeof(ctx)) { return -EINVAL; } res = 0; if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) return -EINVAL; if (ctx.flags & ~FS_POLICY_FLAGS_VALID) return -EINVAL; crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS); if (!crypt_info) Loading @@ -198,27 +233,20 @@ retry: 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 FS_ENCRYPTION_MODE_AES_256_XTS: cipher_str = "xts(aes)"; break; case FS_ENCRYPTION_MODE_AES_256_CTS: cipher_str = "cts(cbc(aes))"; break; default: printk_once(KERN_WARNING "%s: unsupported key mode %d (ino %u)\n", __func__, mode, (unsigned) inode->i_ino); res = -ENOKEY; res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); 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; Loading Loading @@ -253,11 +281,12 @@ got_key: crypt_info->ci_ctfm = ctfm; crypto_skcipher_clear_flags(ctfm, ~0); crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); res = crypto_skcipher_setkey(ctfm, raw_key, fscrypt_key_size(mode)); res = crypto_skcipher_setkey(ctfm, raw_key, keysize); 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; Loading @@ -268,7 +297,7 @@ out: if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); memzero_explicit(raw_key, sizeof(raw_key)); kzfree(raw_key); return res; } Loading fs/crypto/policy.c +4 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ int fscrypt_process_policy(struct file *filp, if (ret) return ret; inode_lock(inode); if (!inode_has_encryption_context(inode)) { if (!S_ISDIR(inode->i_mode)) ret = -EINVAL; Loading @@ -127,6 +129,8 @@ int fscrypt_process_policy(struct file *filp, ret = -EINVAL; } inode_unlock(inode); mnt_drop_write_file(filp); return ret; } Loading fs/f2fs/dir.c +3 −3 Original line number Diff line number Diff line Loading @@ -814,12 +814,12 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, if (f2fs_encrypted_inode(d->inode)) { int save_len = fstr->len; int ret; int err; ret = fscrypt_fname_disk_to_usr(d->inode, err = fscrypt_fname_disk_to_usr(d->inode, (u32)de->hash_code, 0, &de_name, fstr); if (ret < 0) if (err) return true; de_name = *fstr; Loading Loading
fs/crypto/crypto.c +13 −13 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include <linux/dcache.h> #include <linux/namei.h> #include <linux/fscrypto.h> #include <linux/ecryptfs.h> static unsigned int num_prealloc_crypto_pages = 32; static unsigned int num_prealloc_crypto_ctxs = 128; Loading Loading @@ -128,11 +127,11 @@ struct fscrypt_ctx *fscrypt_get_ctx(struct inode *inode, gfp_t gfp_flags) EXPORT_SYMBOL(fscrypt_get_ctx); /** * fscrypt_complete() - The completion callback for page encryption * @req: The asynchronous encryption request context * @res: The result of the encryption operation * page_crypt_complete() - completion callback for page crypto * @req: The asynchronous cipher request context * @res: The result of the cipher operation */ static void fscrypt_complete(struct crypto_async_request *req, int res) static void page_crypt_complete(struct crypto_async_request *req, int res) { struct fscrypt_completion_result *ecr = req->data; Loading @@ -152,7 +151,10 @@ static int do_page_crypto(struct inode *inode, struct page *src_page, struct page *dest_page, gfp_t gfp_flags) { u8 xts_tweak[FS_XTS_TWEAK_SIZE]; struct { __le64 index; u8 padding[FS_XTS_TWEAK_SIZE - sizeof(__le64)]; } xts_tweak; struct skcipher_request *req = NULL; DECLARE_FS_COMPLETION_RESULT(ecr); struct scatterlist dst, src; Loading @@ -170,19 +172,17 @@ static int do_page_crypto(struct inode *inode, skcipher_request_set_callback( req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, fscrypt_complete, &ecr); page_crypt_complete, &ecr); BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index)); memcpy(xts_tweak, &index, sizeof(index)); memset(&xts_tweak[sizeof(index)], 0, FS_XTS_TWEAK_SIZE - sizeof(index)); BUILD_BUG_ON(sizeof(xts_tweak) != FS_XTS_TWEAK_SIZE); xts_tweak.index = cpu_to_le64(index); memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding)); 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); skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, &xts_tweak); if (rw == FS_DECRYPT) res = crypto_skcipher_decrypt(req); else Loading
fs/crypto/fname.c +61 −71 Original line number Diff line number Diff line Loading @@ -10,21 +10,16 @@ * This has not yet undergone a rigorous security audit. */ #include <keys/encrypted-type.h> #include <keys/user-type.h> #include <linux/scatterlist.h> #include <linux/ratelimit.h> #include <linux/fscrypto.h> static u32 size_round_up(size_t size, size_t blksize) { return ((size + blksize - 1) / blksize) * blksize; } /** * dir_crypt_complete() - * fname_crypt_complete() - completion callback for filename crypto * @req: The asynchronous cipher request context * @res: The result of the cipher operation */ static void dir_crypt_complete(struct crypto_async_request *req, int res) static void fname_crypt_complete(struct crypto_async_request *req, int res) { struct fscrypt_completion_result *ecr = req->data; Loading @@ -35,90 +30,80 @@ static void dir_crypt_complete(struct crypto_async_request *req, int res) } /** * fname_encrypt() - * fname_encrypt() - encrypt a filename * * 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. * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ 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 = (iname->len < FS_CRYPTO_BLOCK_SIZE) ? FS_CRYPTO_BLOCK_SIZE : iname->len; ciphertext_len = size_round_up(ciphertext_len, padding); ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len; /* * 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, 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); fname_crypt_complete, &ecr); sg_init_one(&sg, oname->name, cryptlen); skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); /* 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) if (res < 0) { printk_ratelimited(KERN_ERR "%s: Error (error code %d)\n", __func__, res); oname->len = ciphertext_len; return res; } /* * 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. oname->len = cryptlen; return 0; } /** * fname_decrypt() - decrypt a filename * * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ static int fname_decrypt(struct inode *inode, const struct fscrypt_str *iname, Loading Loading @@ -146,7 +131,7 @@ static int fname_decrypt(struct inode *inode, } skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, dir_crypt_complete, &ecr); fname_crypt_complete, &ecr); /* Initialize IV */ memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); Loading @@ -168,7 +153,7 @@ static int fname_decrypt(struct inode *inode, } oname->len = strnlen(oname->name, iname->len); return oname->len; return 0; } static const char *lookup_table = Loading Loading @@ -231,9 +216,8 @@ u32 fscrypt_fname_encrypted_size(struct inode *inode, u32 ilen) if (ci) padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); if (ilen < FS_CRYPTO_BLOCK_SIZE) ilen = FS_CRYPTO_BLOCK_SIZE; return size_round_up(ilen, padding); ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE); return round_up(ilen, padding); } EXPORT_SYMBOL(fscrypt_fname_encrypted_size); Loading Loading @@ -279,6 +263,10 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer); /** * fscrypt_fname_disk_to_usr() - converts a filename from disk space to user * space * * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ int fscrypt_fname_disk_to_usr(struct inode *inode, u32 hash, u32 minor_hash, Loading @@ -287,13 +275,12 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, { const struct qstr qname = FSTR_TO_QSTR(iname); char buf[24]; int ret; if (fscrypt_is_dot_dotdot(&qname)) { oname->name[0] = '.'; oname->name[iname->len - 1] = '.'; oname->len = iname->len; return oname->len; return 0; } if (iname->len < FS_CRYPTO_BLOCK_SIZE) Loading @@ -303,9 +290,9 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, return fname_decrypt(inode, iname, oname); if (iname->len <= FS_FNAME_CRYPTO_DIGEST_SIZE) { ret = digest_encode(iname->name, iname->len, oname->name); oname->len = ret; return ret; oname->len = digest_encode(iname->name, iname->len, oname->name); return 0; } if (hash) { memcpy(buf, &hash, 4); Loading @@ -315,15 +302,18 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, } 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; oname->len = 1 + digest_encode(buf, 24, oname->name + 1); return 0; } EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); /** * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk * space * * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ int fscrypt_fname_usr_to_disk(struct inode *inode, const struct qstr *iname, Loading @@ -333,7 +323,7 @@ int fscrypt_fname_usr_to_disk(struct inode *inode, oname->name[0] = '.'; oname->name[iname->len - 1] = '.'; oname->len = iname->len; return oname->len; return 0; } if (inode->i_crypt_info) return fname_encrypt(inode, iname, oname); Loading Loading @@ -367,10 +357,10 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, if (dir->i_crypt_info) { ret = fscrypt_fname_alloc_buffer(dir, iname->len, &fname->crypto_buf); if (ret < 0) if (ret) return ret; ret = fname_encrypt(dir, iname, &fname->crypto_buf); if (ret < 0) if (ret) goto errout; fname->disk_name.name = fname->crypto_buf.name; fname->disk_name.len = fname->crypto_buf.len; Loading
fs/crypto/keyinfo.c +58 −29 Original line number Diff line number Diff line Loading @@ -8,11 +8,8 @@ * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015. */ #include <keys/encrypted-type.h> #include <keys/user-type.h> #include <linux/random.h> #include <linux/scatterlist.h> #include <uapi/linux/keyctl.h> #include <linux/fscrypto.h> static void derive_crypt_complete(struct crypto_async_request *req, int rc) Loading Loading @@ -139,6 +136,38 @@ out: return res; } static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, const char **cipher_str_ret, int *keysize_ret) { if (S_ISREG(inode->i_mode)) { if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) { *cipher_str_ret = "xts(aes)"; *keysize_ret = FS_AES_256_XTS_KEY_SIZE; return 0; } pr_warn_once("fscrypto: unsupported contents encryption mode " "%d for inode %lu\n", ci->ci_data_mode, inode->i_ino); return -ENOKEY; } if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) { *cipher_str_ret = "cts(cbc(aes))"; *keysize_ret = FS_AES_256_CTS_KEY_SIZE; return 0; } pr_warn_once("fscrypto: unsupported filenames encryption mode " "%d for inode %lu\n", ci->ci_filename_mode, inode->i_ino); return -ENOKEY; } pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n", (inode->i_mode & S_IFMT), inode->i_ino); return -ENOKEY; } static void put_crypt_info(struct fscrypt_info *ci) { if (!ci) Loading @@ -155,8 +184,8 @@ int get_crypt_info(struct inode *inode) struct fscrypt_context ctx; struct crypto_skcipher *ctfm; const char *cipher_str; u8 raw_key[FS_MAX_KEY_SIZE]; u8 mode; int keysize; u8 *raw_key = NULL; int res; res = fscrypt_initialize(); Loading @@ -179,13 +208,19 @@ retry: if (res < 0) { if (!fscrypt_dummy_context_enabled(inode)) return res; ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS; ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; ctx.flags = 0; } else if (res != sizeof(ctx)) { return -EINVAL; } res = 0; if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) return -EINVAL; if (ctx.flags & ~FS_POLICY_FLAGS_VALID) return -EINVAL; crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS); if (!crypt_info) Loading @@ -198,27 +233,20 @@ retry: 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 FS_ENCRYPTION_MODE_AES_256_XTS: cipher_str = "xts(aes)"; break; case FS_ENCRYPTION_MODE_AES_256_CTS: cipher_str = "cts(cbc(aes))"; break; default: printk_once(KERN_WARNING "%s: unsupported key mode %d (ino %u)\n", __func__, mode, (unsigned) inode->i_ino); res = -ENOKEY; res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); 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; Loading Loading @@ -253,11 +281,12 @@ got_key: crypt_info->ci_ctfm = ctfm; crypto_skcipher_clear_flags(ctfm, ~0); crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); res = crypto_skcipher_setkey(ctfm, raw_key, fscrypt_key_size(mode)); res = crypto_skcipher_setkey(ctfm, raw_key, keysize); 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; Loading @@ -268,7 +297,7 @@ out: if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); memzero_explicit(raw_key, sizeof(raw_key)); kzfree(raw_key); return res; } Loading
fs/crypto/policy.c +4 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ int fscrypt_process_policy(struct file *filp, if (ret) return ret; inode_lock(inode); if (!inode_has_encryption_context(inode)) { if (!S_ISDIR(inode->i_mode)) ret = -EINVAL; Loading @@ -127,6 +129,8 @@ int fscrypt_process_policy(struct file *filp, ret = -EINVAL; } inode_unlock(inode); mnt_drop_write_file(filp); return ret; } Loading
fs/f2fs/dir.c +3 −3 Original line number Diff line number Diff line Loading @@ -814,12 +814,12 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, if (f2fs_encrypted_inode(d->inode)) { int save_len = fstr->len; int ret; int err; ret = fscrypt_fname_disk_to_usr(d->inode, err = fscrypt_fname_disk_to_usr(d->inode, (u32)de->hash_code, 0, &de_name, fstr); if (ret < 0) if (err) return true; de_name = *fstr; Loading