[Devel] [PATCH rh7] fs: hold reference on original path

Maxim Patlasov mpatlasov at virtuozzo.com
Wed Sep 21 17:15:40 PDT 2016


struct file holds references on its f_path.mnt and f_path.dentry by calling
path_get(&f->f_path) from do_dentry_open(). Let's use the same technique
for f->f_original_path. Otherwise, f_original_path.dentry can be deleted while
file still references it leading to NULL-ptr-deref on f->f_original_path.dentry->d_inode.

https://jira.sw.ru/browse/PSBM-52373

Signed-off-by: Maxim Patlasov <mpatlasov at virtuozzo.com>
---
 fs/file_table.c |    6 ++++++
 fs/open.c       |   18 +++++++++++++++---
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/fs/file_table.c b/fs/file_table.c
index 957c476..b8982d8 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -242,6 +242,8 @@ static void __fput(struct file *file)
 	struct dentry *dentry = file->f_path.dentry;
 	struct vfsmount *mnt = file->f_path.mnt;
 	struct inode *inode = dentry->d_inode;
+	struct dentry *original_dentry = file->f_original_path.dentry;
+	struct vfsmount *original_mnt = file->f_original_path.mnt;
 
 	might_sleep();
 
@@ -273,10 +275,14 @@ static void __fput(struct file *file)
 		drop_file_write_access(file);
 	file->f_path.dentry = NULL;
 	file->f_path.mnt = NULL;
+	file->f_original_path.dentry = NULL;
+	file->f_original_path.mnt = NULL;
 	file->f_inode = NULL;
 	file_free(file);
 	dput(dentry);
 	mntput(mnt);
+	dput(original_dentry);
+	mntput(original_mnt);
 }
 
 static DEFINE_SPINLOCK(delayed_fput_lock);
diff --git a/fs/open.c b/fs/open.c
index 8c066b1..25dbc85 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -893,16 +893,28 @@ int vfs_open(const struct path *path, struct file *filp,
 {
 	struct inode *inode = path->dentry->d_inode;
 	iop_dentry_open_t dentry_open = get_dentry_open_iop(inode);
+	int do_cleanup = 0;
+	int ret;
 
-	if (!filp->f_original_path.mnt)
+	if (!filp->f_original_path.mnt) {
 		filp->f_original_path = *path;
+		path_get(&filp->f_original_path);
+		do_cleanup = 1;
+	}
 
 	if (dentry_open)
-		return dentry_open(path->dentry, filp, cred);
+		ret = dentry_open(path->dentry, filp, cred);
 	else {
 		filp->f_path = *path;
-		return do_dentry_open(filp, NULL, cred);
+		ret = do_dentry_open(filp, NULL, cred);
 	}
+
+	if (ret && do_cleanup) {
+		path_put(&filp->f_original_path);
+		filp->f_original_path.mnt = NULL;
+		filp->f_original_path.dentry = NULL;
+	}
+	return ret;
 }
 EXPORT_SYMBOL(vfs_open);
 



More information about the Devel mailing list