48f65f6
From c0ea161a6e7158281f64bc6d41126da43cb08f14 Mon Sep 17 00:00:00 2001
48f65f6
From: "Eric W. Biederman" <ebiederm@xmission.com>
48f65f6
Date: Sat, 15 Aug 2015 13:36:12 -0500
48f65f6
Subject: [PATCH 1/2] dcache: Handle escaped paths in prepend_path
48f65f6
48f65f6
commit cde93be45a8a90d8c264c776fab63487b5038a65 upstream.
48f65f6
48f65f6
A rename can result in a dentry that by walking up d_parent
48f65f6
will never reach it's mnt_root.  For lack of a better term
48f65f6
I call this an escaped path.
48f65f6
48f65f6
prepend_path is called by four different functions __d_path,
48f65f6
d_absolute_path, d_path, and getcwd.
48f65f6
48f65f6
__d_path only wants to see paths are connected to the root it passes
48f65f6
in.  So __d_path needs prepend_path to return an error.
48f65f6
48f65f6
d_absolute_path similarly wants to see paths that are connected to
48f65f6
some root.  Escaped paths are not connected to any mnt_root so
48f65f6
d_absolute_path needs prepend_path to return an error greater
48f65f6
than 1.  So escaped paths will be treated like paths on lazily
48f65f6
unmounted mounts.
48f65f6
48f65f6
getcwd needs to prepend "(unreachable)" so getcwd also needs
48f65f6
prepend_path to return an error.
48f65f6
48f65f6
d_path is the interesting hold out.  d_path just wants to print
48f65f6
something, and does not care about the weird cases.  Which raises
48f65f6
the question what should be printed?
48f65f6
48f65f6
Given that <escaped_path>/<anything> should result in -ENOENT I
48f65f6
believe it is desirable for escaped paths to be printed as empty
48f65f6
paths.  As there are not really any meaninful path components when
48f65f6
considered from the perspective of a mount tree.
48f65f6
48f65f6
So tweak prepend_path to return an empty path with an new error
48f65f6
code of 3 when it encounters an escaped path.
48f65f6
48f65f6
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
48f65f6
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
48f65f6
---
48f65f6
 fs/dcache.c | 7 +++++++
48f65f6
 1 file changed, 7 insertions(+)
48f65f6
48f65f6
diff --git a/fs/dcache.c b/fs/dcache.c
48f65f6
index 9b5fe503f6cb..e3b44ca75a1b 100644
48f65f6
--- a/fs/dcache.c
48f65f6
+++ b/fs/dcache.c
48f65f6
@@ -2926,6 +2926,13 @@ restart:
48f65f6
 
48f65f6
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
48f65f6
 			struct mount *parent = ACCESS_ONCE(mnt->mnt_parent);
48f65f6
+			/* Escaped? */
48f65f6
+			if (dentry != vfsmnt->mnt_root) {
48f65f6
+				bptr = *buffer;
48f65f6
+				blen = *buflen;
48f65f6
+				error = 3;
48f65f6
+				break;
48f65f6
+			}
48f65f6
 			/* Global root? */
48f65f6
 			if (mnt != parent) {
48f65f6
 				dentry = ACCESS_ONCE(mnt->mnt_mountpoint);
48f65f6
-- 
48f65f6
2.4.3
48f65f6