From patchwork Fri Dec 15 17:42:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 10115719 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3506F6019C for ; Fri, 15 Dec 2017 17:47:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2101C29EE1 for ; Fri, 15 Dec 2017 17:47:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 15BDF2A024; Fri, 15 Dec 2017 17:47:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7EE0629EE1 for ; Fri, 15 Dec 2017 17:47:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756187AbdLORrU (ORCPT ); Fri, 15 Dec 2017 12:47:20 -0500 Received: from mail-pf0-f193.google.com ([209.85.192.193]:36587 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755534AbdLORrC (ORCPT ); Fri, 15 Dec 2017 12:47:02 -0500 Received: by mail-pf0-f193.google.com with SMTP id p84so6639810pfd.3; Fri, 15 Dec 2017 09:47:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Z2wz02sYnJj/aLtYzyINYUs05Zn2AZ2pMhjHWr3CJcE=; b=fFcwsURmS3U9E1++H5V4sgc7LL5uJBFuBCCnZcxR6M2pL5GsyYke2B07SPDUGqTW4B VP+TC8hAGJwKd3mx4x6Fo/Ju7+3DwDzUa7dBR3fnsIHH5KAY3wY2Y3EfT6QJIGpEXwM5 4G9zfs2N+57OZfzrVSjlMDxJeKOcUPKsE159auSmqvb2pf20l8Cm15yovrltyyAg2I4T 8zZhfbVXMQiD/94sdB+tQVkr3WKJp6nrMkE10lbOYju+voya1jpmizDyD9q+F3XR1d6X 3vC/CG0Dcb1av8WIDp8RvNvpKzbKpeTiFF6O98ZF9I8ZVHCR8FeBVkwFy7OKh56tSyNv 7bXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Z2wz02sYnJj/aLtYzyINYUs05Zn2AZ2pMhjHWr3CJcE=; b=ba2ezHJl2UF9ct/kkTJR4gWDOjAq8kI3BykhKpTr1mnMo21zl6v2sucweQCETjpQuC 5uhxAv2tzolTWcv8tIVOLpLrr0RuUcVUzjHyd/3X88t3MwwO6mdokJYWvIdh5UxYRKtp t4ONYwdbnBuWmL4rTAc4nfbmjxJEX0ec9uCccKJlbWrpFSsMBqBugwe4V/qgUcMA3BOt tscUK0aZE1H2WkJeL+qP+Xs73IjXVYvctllJEGHrNpPaLR82nKo+wJdk0l4+hO1rzN/a uqKLYqWU2b3R6nI+6JlATp1TSum+HFErjcUkubNjOEaNnvafS6SmDPZ/+5Cp+yrxP3/K 96zA== X-Gm-Message-State: AKGB3mI2+m8EBPMr42YiqmYM6yYnX7wReeukYhxdvxb4ys8sWHWRRzJa dDZNkhPYxXKJNt193aVk5x1ZTJDcNu8= X-Google-Smtp-Source: ACJfBovvAEV3njuMeK5kkbyYLjaQdI0km5fbYEexOIrvvZbiVlJ1PoEexH0/xwkzmmW0Vym4caK4Mw== X-Received: by 10.84.246.197 with SMTP id j5mr14328131plt.168.1513360021796; Fri, 15 Dec 2017 09:47:01 -0800 (PST) Received: from zzz.localdomain (c-67-185-97-198.hsd1.wa.comcast.net. [67.185.97.198]) by smtp.gmail.com with ESMTPSA id j62sm12980149pfc.18.2017.12.15.09.47.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Dec 2017 09:47:00 -0800 (PST) From: Eric Biggers To: linux-fscrypt@vger.kernel.org Cc: "Theodore Y . Ts'o" , Jaegeuk Kim , linux-ext4@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, linux-mtd@lists.infradead.org, Eric Biggers Subject: [PATCH 21/24] fscrypt: calculate NUL-padding length in one place only Date: Fri, 15 Dec 2017 09:42:22 -0800 Message-Id: <20171215174225.31583-22-ebiggers3@gmail.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20171215174225.31583-1-ebiggers3@gmail.com> References: <20171215174225.31583-1-ebiggers3@gmail.com> Sender: linux-fscrypt-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Eric Biggers Currently, when encrypting a filename (either a real filename or a symlink target) we calculate the amount of NUL-padding twice: once before encryption and once during encryption in fname_encrypt(). It is needed before encryption to allocate the needed buffer size as well as calculate the size the symlink target will take up on-disk before creating the symlink inode. Calculating the size during encryption as well is redundant. Remove this redundancy by always calculating the exact size beforehand, and making fname_encrypt() just add as much NUL padding as is needed to fill the output buffer. Signed-off-by: Eric Biggers --- fs/crypto/fname.c | 53 ++++++++++++++++++++++----------------------- fs/crypto/fscrypt_private.h | 4 ++-- fs/crypto/hooks.c | 7 +----- 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index cae7d1bcc8c5..65424b89a1d1 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -30,39 +30,29 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) /** * fname_encrypt() - encrypt a filename * - * The caller must have allocated sufficient memory for the @oname string. + * The output buffer must be at least as large as the input buffer. + * Any extra space is filled with NUL padding before encryption. * * Return: 0 on success, -errno on failure */ -int fname_encrypt(struct inode *inode, - const struct qstr *iname, struct fscrypt_str *oname) +int fname_encrypt(struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen) { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); - struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_ctfm; + struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm; int res = 0; char iv[FS_CRYPTO_BLOCK_SIZE]; struct scatterlist sg; - int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); - unsigned int lim; - unsigned int cryptlen; - - lim = inode->i_sb->s_cop->max_namelen(inode); - if (iname->len <= 0 || iname->len > lim) - return -EIO; /* * Copy the filename to the output buffer for encrypting in-place and * pad it with the needed number of NUL bytes. */ - if (WARN_ON(oname->len < iname->len)) + if (WARN_ON(olen < iname->len)) return -ENOBUFS; - cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE); - cryptlen = round_up(cryptlen, padding); - cryptlen = min3(cryptlen, lim, oname->len); - memcpy(oname->name, iname->name, iname->len); - memset(oname->name + iname->len, 0, cryptlen - iname->len); + memcpy(out, iname->name, iname->len); + memset(out + iname->len, 0, olen - iname->len); /* Initialize the IV */ memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); @@ -77,8 +67,8 @@ int fname_encrypt(struct inode *inode, skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait); - sg_init_one(&sg, oname->name, cryptlen); - skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); + sg_init_one(&sg, out, olen); + skcipher_request_set_crypt(req, &sg, &sg, olen, iv); /* Do the encryption */ res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); @@ -89,7 +79,6 @@ int fname_encrypt(struct inode *inode, return res; } - oname->len = cryptlen; return 0; } @@ -354,11 +343,21 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return ret; if (dir->i_crypt_info) { - ret = fscrypt_fname_alloc_buffer(dir, iname->len, - &fname->crypto_buf); - if (ret) - return ret; - ret = fname_encrypt(dir, iname, &fname->crypto_buf); + unsigned int max_len = dir->i_sb->s_cop->max_namelen(dir); + + if (iname->len > max_len) + return -ENAMETOOLONG; + + fname->crypto_buf.len = + min(fscrypt_fname_encrypted_size(dir, iname->len), + max_len); + fname->crypto_buf.name = kmalloc(fname->crypto_buf.len, + GFP_NOFS); + if (!fname->crypto_buf.name) + return -ENOMEM; + + ret = fname_encrypt(dir, iname, fname->crypto_buf.name, + fname->crypto_buf.len); if (ret) goto errout; fname->disk_name.name = fname->crypto_buf.name; @@ -410,7 +409,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return 0; errout: - fscrypt_fname_free_buffer(&fname->crypto_buf); + kfree(fname->crypto_buf.name); return ret; } EXPORT_SYMBOL(fscrypt_setup_filename); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index cec9ce309f41..053917587200 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -108,8 +108,8 @@ extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags); /* fname.c */ -extern int fname_encrypt(struct inode *inode, - const struct qstr *iname, struct fscrypt_str *oname); +extern int fname_encrypt(struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen); /* keyinfo.c */ extern void __exit fscrypt_essiv_cleanup(void); diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 0f103a5cb1aa..ff20cacdea94 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -157,7 +157,6 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, struct qstr iname = { .name = target, .len = len }; struct fscrypt_symlink_data *sd; unsigned int ciphertext_len; - struct fscrypt_str oname; err = fscrypt_require_key(inode); if (err) @@ -174,16 +173,12 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, ciphertext_len = disk_link->len - sizeof(*sd); sd->len = cpu_to_le16(ciphertext_len); - oname.name = sd->encrypted_path; - oname.len = ciphertext_len; - err = fname_encrypt(inode, &iname, &oname); + err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len); if (err) { if (!disk_link->name) kfree(sd); return err; } - BUG_ON(oname.len != ciphertext_len); - /* * Null-terminating the ciphertext doesn't make sense, but we still * count the null terminator in the length, so we might as well