Received: by 10.213.65.68 with SMTP id h4csp988978imn; Wed, 28 Mar 2018 17:35:37 -0700 (PDT) X-Google-Smtp-Source: AIpwx4/Qe2WI1X1CS40FjdpHAUSn2xXCIwamg3K7jKYYlmi6W5+qFHNkXwPXkzWU8/1nD5VCn0UM X-Received: by 2002:a17:902:9001:: with SMTP id a1-v6mr1369479plp.211.1522283737474; Wed, 28 Mar 2018 17:35:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522283737; cv=none; d=google.com; s=arc-20160816; b=Q33jEPdb5q76BJQFGm832yuNXTtXeGEQTzt7PcYbqYyiFUvTdVV8/8TwrQDHHfKHsg WNrYGbKIP5jLrMFDQ38AEGVtuSyN9upzVmcJ2hVG20ogAwFcOmwWbLwG/oQquNcaCBy+ u/HF3+R/gHDgl/oqQq5B0sSgfViaWZ8QMvPKqFklYfxFeimT1gXBmYU9uU7k+KcsA62b 42SoWY/PhaeliGiT7jVfLt892jkXzZC4c0oLdE5yfxOc+B9kL/XUiNP9oZuyzwkngAoW tu/4c8VgRc59WK2TlPMdcJ059lQhuszZ4oy5jAefyyRiR++mbudcAVJix80Sab7SuvSw Mfhw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=A+onRo2axTRG+WvVF+DmykwU84tgnPqYsEjv9HYGC7I=; b=e0h29TMjxIw9ndBc9ES3+aFUcLGMTYAp+dkHLJ9EL61OX6QqOk7wzJQa/AYNBnf2HG DjCp1MxbqsT/Q2uNJ2fWsPNG3vA65Kp1hsClhof2zM+0/EOuDn4ZHMLvQNQWiT9LrSNJ FFELYc1jWk+OlbMV8/HJycW7++Ivv2miaUY33LB+mNfJdmvjUthtmitsBcM3vZ4VFdTi /d8QwwD0BXDtVNu4/sgQjpoakgEYgaV+8wyf4ScTw6c8wWWMliCR7iK19o38OxBsstP3 s0QHin78dPAnv4TITqEzyM7O/sMrrdMSZCsLO/PTazs+gIX9SULJBiOaH2wyS3ugD7l7 Z2Tg== 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=canonical.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c18si3561459pfn.113.2018.03.28.17.35.12; Wed, 28 Mar 2018 17:35:37 -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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=canonical.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751096AbeC2Adq (ORCPT + 99 others); Wed, 28 Mar 2018 20:33:46 -0400 Received: from youngberry.canonical.com ([91.189.89.112]:56148 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750858AbeC2Adp (ORCPT ); Wed, 28 Mar 2018 20:33:45 -0400 Received: from 162-237-133-238.lightspeed.rcsntx.sbcglobal.net ([162.237.133.238] helo=sec.l.tihix.com) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1f1LVf-00055e-Pb; Thu, 29 Mar 2018 00:33:44 +0000 From: Tyler Hicks To: ecryptfs@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Guenter Roeck , Al Viro Subject: [PATCH] eCryptfs: don't pass up plaintext names when using filename encryption Date: Thu, 29 Mar 2018 00:32:47 +0000 Message-Id: <1522283567-4889-1-git-send-email-tyhicks@canonical.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <891ab33d-a140-0a6d-6907-ba226590eb3f@canonical.com> References: <891ab33d-a140-0a6d-6907-ba226590eb3f@canonical.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- fs/ecryptfs/crypto.c | 41 ++++++++++++++++++++++++++++------------- fs/ecryptfs/file.c | 21 ++++++++++++++++----- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 846ca15..4dd842f 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1997,6 +1997,16 @@ int ecryptfs_encrypt_and_encode_filename( 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(char **plaintext_name, 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(char **plaintext_name, 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 { diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index c74ed3c..b76a985 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -82,17 +82,28 @@ ecryptfs_filldir(struct dir_context *ctx, const char *lower_name, 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; } -- 2.7.4