Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3775392imm; Mon, 18 Jun 2018 04:00:01 -0700 (PDT) X-Google-Smtp-Source: ADUXVKJ+Ui/4gxB/iV9A1vxjvZCvLbmyRThvjndarCWeRlD8g1uGiv5n7UCx8/Ncv7FVfV+97Y9r X-Received: by 2002:a63:b407:: with SMTP id s7-v6mr10816882pgf.334.1529319601918; Mon, 18 Jun 2018 04:00:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529319601; cv=none; d=google.com; s=arc-20160816; b=bXHoE9IZjVXqAguoVt1FitIoEmrNEdw5GU0bvHfXT+e2MjrTNZVmGgMt6aEc+3V/oY t0+Wc/nnBAny2VaAmlKxLILxBC1VH6VMrkZOnGMRdSziBHcBIkmU94TtmdY6c17brGS+ E9VQMLRKyGgGANrAcFeYJap3gmMSGnIXf4ULXbNY9Uxk85FNECYKGVtVqG7vhNIbm/3W iVzJpJsrx7GEaVF1WGqshg4rnAFbPWaqjY6DVC0jEarxX6V4ImQUT+HN78/Hnapq1AGI mOB2J2ty3n8Jz9h9a9mW2X2dQ/+qLyiWQkHNP5mIurUb3mj3KwCwEYoKnDNyiEfUC5RP +2ig== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=XV81jk+NG7o6eplNe5jJhsrmnL1DlZEoI/uk3alOtLE=; b=0aZIQAubyLBJKFRBdJoG0gXIfY/v4DT+OmGlOOqXx90Ep3LS5GlFP0mAp2vjqJ4+NL GxM0jgsjp+B13AmsdaLvuGrXiipNr0rM/kstIrRrfHY9FDX4QdtJ3pVzjW6Wn8FiOkq8 7j+5YqDzNMiTQeH3ZBwKxW71rvIeL/uTk+mAkfvtBX462u/8MBro7z9gXnqhpXoP02Eq MnCEuZYkTBH3bjQsZIVqvscPVb5Hd2G9sb9KQ8gNir3G1+JaCwCRzbBAFJhQuroCFbpA CKsY6wQrXylTwntWMfJ9FzyePHAFXantNqU+0lx77RKsoIxqSYR2KYS3V30qwVZOZuJP 6aaw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d16-v6si14615941pll.197.2018.06.18.03.59.48; Mon, 18 Jun 2018 04:00:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935091AbeFRKRG (ORCPT + 99 others); Mon, 18 Jun 2018 06:17:06 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:52926 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934125AbeFRIP7 (ORCPT ); Mon, 18 Jun 2018 04:15:59 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id E59DEC7A; Mon, 18 Jun 2018 08:15:58 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Guenter Roeck , Al Viro , Tyler Hicks , Sasha Levin Subject: [PATCH 4.16 028/279] eCryptfs: dont pass up plaintext names when using filename encryption Date: Mon, 18 Jun 2018 10:10:13 +0200 Message-Id: <20180618080610.004679101@linuxfoundation.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180618080608.851973560@linuxfoundation.org> References: <20180618080608.851973560@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.16-stable review patch. If anyone has any objections, please let me know. ------------------ From: Tyler Hicks [ Upstream commit e86281e700cca8a773f9a572fa406adf2784ba5c ] Both ecryptfs_filldir() and ecryptfs_readlink_lower() use ecryptfs_decode_and_decrypt_filename() to translate lower filenames to upper filenames. The function correctly passes up lower filenames, unchanged, when filename encryption isn't in use. However, it was also passing up lower filenames when the filename wasn't encrypted or when decryption failed. Since 88ae4ab9802e, eCryptfs refuses to lookup lower plaintext names when filename encryption is enabled so this resulted in a situation where userspace would see lower plaintext filenames in calls to getdents(2) but then not be able to lookup those filenames. An example of this can be seen when enabling filename encryption on an eCryptfs mount at the root directory of an Ext4 filesystem: $ ls -1i /lower 12 ECRYPTFS_FNEK_ENCRYPTED.FWYZD8TcW.5FV-TKTEYOHsheiHX9a-w.NURCCYIMjI8pn5BDB9-h3fXwrE-- 11 lost+found $ ls -1i /upper ls: cannot access '/upper/lost+found': No such file or directory ? lost+found 12 test With this change, the lower lost+found dentry is ignored: $ ls -1i /lower 12 ECRYPTFS_FNEK_ENCRYPTED.FWYZD8TcW.5FV-TKTEYOHsheiHX9a-w.NURCCYIMjI8pn5BDB9-h3fXwrE-- 11 lost+found $ ls -1i /upper 12 test Additionally, some potentially noisy error/info messages in the related code paths are turned into debug messages so that the logs can't be easily filled. Fixes: 88ae4ab9802e ("ecryptfs_lookup(): try either only encrypted or plaintext name") Reported-by: Guenter Roeck Cc: Al Viro Signed-off-by: Tyler Hicks Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/crypto.c | 41 ++++++++++++++++++++++++++++------------- fs/ecryptfs/file.c | 21 ++++++++++++++++----- 2 files changed, 44 insertions(+), 18 deletions(-) --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1997,6 +1997,16 @@ out: return rc; } +static bool is_dot_dotdot(const char *name, size_t name_size) +{ + if (name_size == 1 && name[0] == '.') + return true; + else if (name_size == 2 && name[0] == '.' && name[1] == '.') + return true; + + return false; +} + /** * ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext * @plaintext_name: The plaintext name @@ -2021,13 +2031,21 @@ int ecryptfs_decode_and_decrypt_filename size_t packet_size; int rc = 0; - if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) - && !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) - && (name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) - && (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, - ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) { - const char *orig_name = name; - size_t orig_name_size = name_size; + if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) && + !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)) { + if (is_dot_dotdot(name, name_size)) { + rc = ecryptfs_copy_filename(plaintext_name, + plaintext_name_size, + name, name_size); + goto out; + } + + if (name_size <= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE || + strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, + ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE)) { + rc = -EINVAL; + goto out; + } name += ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE; name_size -= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE; @@ -2047,12 +2065,9 @@ int ecryptfs_decode_and_decrypt_filename decoded_name, decoded_name_size); if (rc) { - printk(KERN_INFO "%s: Could not parse tag 70 packet " - "from filename; copying through filename " - "as-is\n", __func__); - rc = ecryptfs_copy_filename(plaintext_name, - plaintext_name_size, - orig_name, orig_name_size); + ecryptfs_printk(KERN_DEBUG, + "%s: Could not parse tag 70 packet from filename\n", + __func__); goto out_free; } } else { --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -82,17 +82,28 @@ ecryptfs_filldir(struct dir_context *ctx buf->sb, lower_name, lower_namelen); if (rc) { - printk(KERN_ERR "%s: Error attempting to decode and decrypt " - "filename [%s]; rc = [%d]\n", __func__, lower_name, - rc); - goto out; + if (rc != -EINVAL) { + ecryptfs_printk(KERN_DEBUG, + "%s: Error attempting to decode and decrypt filename [%s]; rc = [%d]\n", + __func__, lower_name, rc); + return rc; + } + + /* Mask -EINVAL errors as these are most likely due a plaintext + * filename present in the lower filesystem despite filename + * encryption being enabled. One unavoidable example would be + * the "lost+found" dentry in the root directory of an Ext4 + * filesystem. + */ + return 0; } + buf->caller->pos = buf->ctx.pos; rc = !dir_emit(buf->caller, name, name_size, ino, d_type); kfree(name); if (!rc) buf->entries_written++; -out: + return rc; }