From patchwork Tue May 15 10:26:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 10400803 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 1EAD2600F4 for ; Tue, 15 May 2018 10:25:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 077362872E for ; Tue, 15 May 2018 10:25:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EE3A028734; Tue, 15 May 2018 10:25:07 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI 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 6B7022872E for ; Tue, 15 May 2018 10:25:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752689AbeEOKZC (ORCPT ); Tue, 15 May 2018 06:25:02 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:38535 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752313AbeEOKY7 (ORCPT ); Tue, 15 May 2018 06:24:59 -0400 Received: by mail-wm0-f66.google.com with SMTP id m129-v6so54726wmb.3; Tue, 15 May 2018 03:24:58 -0700 (PDT) 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=gIgiNfeHqaK5Aw5VxDNKLyfvIYAH4+Vzi1hJEmYwCeg=; b=ZlW9eEnKmb8ZyQDrI0ROooZPmQojFTIPYw2+HC8LSZ67SykbAL+XT6RaP1sE7OhuLD 3hODHge9k4h/7J4gUk+qnRauljv1UdH9FQHEQOO4IwcqB43TL7iJRabiAkqT4efxkQdF pZKDHvsXvJOcBNIezO2GaGuyDZh64RYkXVNiINWPwGDRdaAENsDjJWm8q6AaB+3IlSqE jo7XIZztSOgQOJZrP2B7YjTVZWueRt/8/r/DcjceeSG7YLpTZ9JQW3+KSeRw/C7Nz66g NmDE6jmf1SeFzU/j5YmDgsdxjaL/Euv+7+Qw5gpBz2MWfr1DuW9e/1oKdLmuhEOje6Y6 Xh8A== 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=gIgiNfeHqaK5Aw5VxDNKLyfvIYAH4+Vzi1hJEmYwCeg=; b=Gpjz3it0MbErOYPSeOQeLbn09bA5WnLILb3NY80f4XNke4ZjFHcYWf3txEvxhgAicK QNagOTV+Ee08mIgBELF30UTZmpi6oVMXwGxDVhDLzmMdLOpV7Ndp1OeohYPXUtRgcdL+ KjLeS3up0J+9N8bkKs66b7ACYw3OChV1I7eymMMLxgt/rYTyNksLV4OLqTb5R3fQ4wVV qvnXXjh7QNrsmv1rrRJV27ZRDCCnb1KI69cu5f7ZasJUi+bLHTSJ7PKQPYMtKAjYkUo1 vT4WExI5ch2Az9bjF3qrFRvovwMfRR5q3mwHN6N76OMH4SL/8OLcUkmYtESfw6dd2tND mcKA== X-Gm-Message-State: ALKqPwfzCNNsYErJp/yhwuZMPkIZHZQQXIdPqZ8OJFEdGaCWFV6UkgsQ zhAjd9wjEw0olwTsyXCs1I8TYQ== X-Google-Smtp-Source: AB8JxZpX5guSpFOr/6fVi31vAxv2ooCxr6PGsHaIz49t0TBSeRzZ6ACaXUpsjD3efyxuoTc+TacF8g== X-Received: by 2002:a50:b36a:: with SMTP id r39-v6mr17503428edd.145.1526379898177; Tue, 15 May 2018 03:24:58 -0700 (PDT) Received: from amir-VirtualBox.ctera.local (bzq-166-168-31-246.red.bezeqint.net. [31.168.166.246]) by smtp.gmail.com with ESMTPSA id v22-v6sm10039edq.15.2018.05.15.03.24.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 15 May 2018 03:24:57 -0700 (PDT) From: Amir Goldstein To: Miklos Szeredi Cc: Al Viro , Vivek Goyal , linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, "#v4 . 16" Subject: [PATCH v3 1/4] ovl: use insert_inode_locked4() to hash a newly created inode Date: Tue, 15 May 2018 13:26:09 +0300 Message-Id: <1526379972-20923-2-git-send-email-amir73il@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1526379972-20923-1-git-send-email-amir73il@gmail.com> References: <1526379972-20923-1-git-send-email-amir73il@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Currently, there is a small window where ovl_obtain_alias() can race with ovl_instantiate() and create two different overlay inodes with the same underlying real non-dir non-hardlink inode. The race requires an adversary to guess the file handle of the yet to be created upper inode and decode the guessed file handle after ovl_creat_real(), but before ovl_instantiate(). This patch fixes the race, by using insert_inode_locked4() to add a newly created inode to icache. If the newly created inode apears to already exist in icache (hashed by the same real upper inode), we export this error to user instead of silently not hashing the new inode. This race does not affect overlay directory inodes, because those are decoded via ovl_lookup_real() and not with ovl_obtain_alias(), so avoid using the new helper d_instantiate_new() to reduce backport dependencies. Backporting only makes sense for v4.16 where NFS export was introduced. Cc: Al Viro Cc: #v4.16 Signed-off-by: Amir Goldstein --- fs/overlayfs/dir.c | 24 ++++++++++++++++++------ fs/overlayfs/inode.c | 18 ++++++++++++++++++ fs/overlayfs/overlayfs.h | 1 + 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 47dc980e8b33..62e6733b755c 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -183,14 +183,24 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) } /* Common operations required to be done after creation of file on upper */ -static void ovl_instantiate(struct dentry *dentry, struct inode *inode, - struct dentry *newdentry, bool hardlink) +static int ovl_instantiate(struct dentry *dentry, struct inode *inode, + struct dentry *newdentry, bool hardlink) { ovl_dir_modified(dentry->d_parent, false); - ovl_copyattr(d_inode(newdentry), inode); ovl_dentry_set_upper_alias(dentry); if (!hardlink) { - ovl_inode_update(inode, newdentry); + int err; + + ovl_inode_init(inode, newdentry, NULL); + /* + * XXX: if we ever use ovl_obtain_alias() to decode directory + * file handles, need to use ovl_insert_inode_locked() and + * d_instantiate_new() here to prevent ovl_obtain_alias() + * from sneaking in before d_instantiate(). + */ + err = ovl_insert_inode(inode, d_inode(newdentry)); + if (err) + return err; } else { WARN_ON(ovl_inode_real(inode) != d_inode(newdentry)); dput(newdentry); @@ -200,6 +210,8 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode, /* Force lookup of new upper hardlink to find its lower */ if (hardlink) d_drop(dentry); + + return 0; } static bool ovl_type_merge(struct dentry *dentry) @@ -238,7 +250,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, ovl_set_opaque(dentry, newdentry); } - ovl_instantiate(dentry, inode, newdentry, !!hardlink); + err = ovl_instantiate(dentry, inode, newdentry, !!hardlink); newdentry = NULL; out_dput: dput(newdentry); @@ -439,7 +451,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, if (err) goto out_cleanup; } - ovl_instantiate(dentry, inode, newdentry, !!hardlink); + err = ovl_instantiate(dentry, inode, newdentry, !!hardlink); newdentry = NULL; out_dput2: dput(upper); diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 7abcf96e94fc..060c534998d1 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -741,6 +741,24 @@ static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry, return true; } +static int ovl_insert_inode_locked(struct inode *inode, struct inode *realinode) +{ + return insert_inode_locked4(inode, (unsigned long) realinode, + ovl_inode_test, realinode); +} + +int ovl_insert_inode(struct inode *inode, struct inode *realinode) +{ + int err; + + err = ovl_insert_inode_locked(inode, realinode); + if (err) + return err; + + unlock_new_inode(inode); + return 0; +} + struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real, bool is_upper) { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index caaa47cea2aa..642b25702092 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -343,6 +343,7 @@ int ovl_update_time(struct inode *inode, struct timespec *ts, int flags); bool ovl_is_private_xattr(const char *name); struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev); +int ovl_insert_inode(struct inode *inode, struct inode *realinode); struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real, bool is_upper); struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,