linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Al Viro <viro@zeniv.linux.org.uk>,
	Vivek Goyal <vgoyal@redhat.com>,
	linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	"#v4 . 16" <stable@vger.kernel.org>
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	[thread overview]
Message-ID: <1526379972-20923-2-git-send-email-amir73il@gmail.com> (raw)
In-Reply-To: <1526379972-20923-1-git-send-email-amir73il@gmail.com>

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 <viro@zeniv.linux.org.uk>
Cc: <stable@vger.kernel.org> #v4.16
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 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,
-- 
2.7.4

  reply	other threads:[~2018-05-15 10:26 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-15 10:26 [PATCH v3 0/4] Overlayfs mkdir related fixes Amir Goldstein
2018-05-15 10:26 ` Amir Goldstein [this message]
2018-05-15 13:23   ` [PATCH v3 1/4] ovl: use insert_inode_locked4() to hash a newly created inode Vivek Goyal
2018-05-15 13:37     ` Amir Goldstein
2018-05-16  8:34       ` Miklos Szeredi
2018-05-16  9:51         ` Amir Goldstein
2018-05-16 10:14           ` Miklos Szeredi
2018-05-16 11:03             ` Amir Goldstein
2018-05-17  6:03       ` Amir Goldstein
2018-05-17  8:10         ` Miklos Szeredi
2018-05-17  8:45           ` Amir Goldstein
2018-05-17  8:53           ` Miklos Szeredi
2018-05-17  8:58             ` Amir Goldstein
2018-05-17  9:07               ` Miklos Szeredi
2018-05-17 16:14                 ` Amir Goldstein
2018-05-15 10:26 ` [PATCH v3 2/4] ovl: relax WARN_ON() real inode attributes mismatch Amir Goldstein
2018-05-15 12:48   ` Vivek Goyal
2018-05-15 12:55     ` Amir Goldstein
2018-05-16 10:29   ` Miklos Szeredi
2018-05-16 11:06     ` Amir Goldstein
2018-05-16 11:18       ` Miklos Szeredi
2018-05-16 13:46         ` Amir Goldstein
2018-05-15 10:26 ` [PATCH v3 3/4] ovl: create helper ovl_create_temp() Amir Goldstein
2018-05-16 10:41   ` Miklos Szeredi
2018-05-16 11:15     ` Amir Goldstein
2018-05-16 11:37       ` Miklos Szeredi
2018-05-15 10:26 ` [PATCH v3 4/4] ovl: make ovl_create_real() cope with vfs_mkdir() safely Amir Goldstein

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1526379972-20923-2-git-send-email-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=stable@vger.kernel.org \
    --cc=vgoyal@redhat.com \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).