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