* [PATCH] vfs: Test for and handle paths that are unreachable from their mnt_root
[not found] ` <87bne82glg.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
@ 2015-08-16 1:27 ` Eric W. Biederman
2015-08-17 3:56 ` NeilBrown
0 siblings, 1 reply; 3+ messages in thread
From: Eric W. Biederman @ 2015-08-16 1:27 UTC (permalink / raw)
To: Linus Torvalds
Cc: Andrey Vagin, Miklos Szeredi, Richard Weinberger,
Linux Containers, Andy Lutomirski, J. Bruce Fields, Al Viro,
linux-fsdevel, Jann Horn, Willy Tarreau
In rare cases a directory can be renamed out from under a bind mount.
In those cases without special handling it becomes possible to walk up
the directory tree to the root dentry of the filesystem and down
from the root dentry to every other file or directory on the filesystem.
Like division by zero .. from an unconnected path can not be given
a useful semantic as there is no predicting at which path component
the code will realize it is unconnected. We certainly can not match
the current behavior as the current behavior is a security hole.
Therefore when encounting .. when following an unconnected path
return -ENOENT.
- Add a function path_connected to verify path->dentry is reachable
from path->mnt.mnt_root. AKA to validate that rename did not do
something nasty to the bind mount.
To avoid races path_connected must be called after following a path
component to it's next path component.
Signed-off-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
This is the simple version that needs no extra vfs support.
My availability is likely to be a bit spotty for the next while
as I am travelling to and then attending Linux Plumbers Conference.
fs/namei.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index ae4e4c18b2ac..5303e994f8d6 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -560,6 +560,24 @@ static int __nd_alloc_stack(struct nameidata *nd)
return 0;
}
+/**
+ * path_connected - Verify that a path->dentry is below path->mnt.mnt_root
+ * @path: nameidate to verify
+ *
+ * Rename can sometimes move a file or directory outside of a bind
+ * mount, path_connected allows those cases to be detected.
+ */
+static bool path_connected(const struct path *path)
+{
+ struct vfsmount *mnt = path->mnt;
+
+ /* Only bind mounts can have disconnected paths */
+ if (mnt->mnt_root == mnt->mnt_sb->s_root)
+ return true;
+
+ return is_subdir(path->dentry, mnt->mnt_root);
+}
+
static inline int nd_alloc_stack(struct nameidata *nd)
{
if (likely(nd->depth != EMBEDDED_LEVELS))
@@ -1296,6 +1314,8 @@ static int follow_dotdot_rcu(struct nameidata *nd)
return -ECHILD;
nd->path.dentry = parent;
nd->seq = seq;
+ if (unlikely(!path_connected(&nd->path)))
+ return -ENOENT;
break;
} else {
struct mount *mnt = real_mount(nd->path.mnt);
@@ -1396,7 +1416,7 @@ static void follow_mount(struct path *path)
}
}
-static void follow_dotdot(struct nameidata *nd)
+static int follow_dotdot(struct nameidata *nd)
{
if (!nd->root.mnt)
set_root(nd);
@@ -1412,6 +1432,8 @@ static void follow_dotdot(struct nameidata *nd)
/* rare case of legitimate dget_parent()... */
nd->path.dentry = dget_parent(nd->path.dentry);
dput(old);
+ if (unlikely(!path_connected(&nd->path)))
+ return -ENOENT;
break;
}
if (!follow_up(&nd->path))
@@ -1419,6 +1441,7 @@ static void follow_dotdot(struct nameidata *nd)
}
follow_mount(&nd->path);
nd->inode = nd->path.dentry->d_inode;
+ return 0;
}
/*
@@ -1634,7 +1657,7 @@ static inline int handle_dots(struct nameidata *nd, int type)
if (nd->flags & LOOKUP_RCU) {
return follow_dotdot_rcu(nd);
} else
- follow_dotdot(nd);
+ return follow_dotdot(nd);
}
return 0;
}
--
2.2.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] vfs: Test for and handle paths that are unreachable from their mnt_root
2015-08-16 1:27 ` [PATCH] vfs: Test for and handle paths that are unreachable from their mnt_root Eric W. Biederman
@ 2015-08-17 3:56 ` NeilBrown
0 siblings, 0 replies; 3+ messages in thread
From: NeilBrown @ 2015-08-17 3:56 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Linus Torvalds, Linux Containers, linux-fsdevel, Al Viro,
Andy Lutomirski, Serge E. Hallyn, Richard Weinberger,
Andrey Vagin, Jann Horn, Willy Tarreau, Omar Sandoval,
Miklos Szeredi, J. Bruce Fields
On Sat, 15 Aug 2015 20:27:13 -0500 ebiederm@xmission.com (Eric W.
Biederman) wrote:
>
> In rare cases a directory can be renamed out from under a bind mount.
> In those cases without special handling it becomes possible to walk up
> the directory tree to the root dentry of the filesystem and down
> from the root dentry to every other file or directory on the filesystem.
>
> Like division by zero .. from an unconnected path can not be given
> a useful semantic as there is no predicting at which path component
> the code will realize it is unconnected. We certainly can not match
> the current behavior as the current behavior is a security hole.
>
> Therefore when encounting .. when following an unconnected path
> return -ENOENT.
>
> - Add a function path_connected to verify path->dentry is reachable
> from path->mnt.mnt_root. AKA to validate that rename did not do
> something nasty to the bind mount.
>
> To avoid races path_connected must be called after following a path
> component to it's next path component.
>
> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
> ---
>
> This is the simple version that needs no extra vfs support.
>
> My availability is likely to be a bit spotty for the next while
> as I am travelling to and then attending Linux Plumbers Conference.
>
> fs/namei.c | 27 +++++++++++++++++++++++++--
> 1 file changed, 25 insertions(+), 2 deletions(-)
>
> diff --git a/fs/namei.c b/fs/namei.c
> index ae4e4c18b2ac..5303e994f8d6 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -560,6 +560,24 @@ static int __nd_alloc_stack(struct nameidata *nd)
> return 0;
> }
>
> +/**
> + * path_connected - Verify that a path->dentry is below path->mnt.mnt_root
> + * @path: nameidate to verify
> + *
> + * Rename can sometimes move a file or directory outside of a bind
> + * mount, path_connected allows those cases to be detected.
While it is obviously true that a rename can move a file outside of a
bind mount, it doesn't seem relevant and so could be confusing.
This is only ever used for directories, and a file could already be
outside a bind mount even while it is inside.
I would stick with "Rename can sometimes move a directory outside..."
> + */
> +static bool path_connected(const struct path *path)
> +{
> + struct vfsmount *mnt = path->mnt;
> +
> + /* Only bind mounts can have disconnected paths */
> + if (mnt->mnt_root == mnt->mnt_sb->s_root)
> + return true;
> +
> + return is_subdir(path->dentry, mnt->mnt_root);
> +}
> +
> static inline int nd_alloc_stack(struct nameidata *nd)
> {
> if (likely(nd->depth != EMBEDDED_LEVELS))
> @@ -1296,6 +1314,8 @@ static int follow_dotdot_rcu(struct nameidata *nd)
> return -ECHILD;
> nd->path.dentry = parent;
> nd->seq = seq;
> + if (unlikely(!path_connected(&nd->path)))
> + return -ENOENT;
> break;
> } else {
> struct mount *mnt = real_mount(nd->path.mnt);
> @@ -1396,7 +1416,7 @@ static void follow_mount(struct path *path)
> }
> }
>
> -static void follow_dotdot(struct nameidata *nd)
> +static int follow_dotdot(struct nameidata *nd)
> {
> if (!nd->root.mnt)
> set_root(nd);
> @@ -1412,6 +1432,8 @@ static void follow_dotdot(struct nameidata *nd)
> /* rare case of legitimate dget_parent()... */
> nd->path.dentry = dget_parent(nd->path.dentry);
> dput(old);
> + if (unlikely(!path_connected(&nd->path)))
> + return -ENOENT;
> break;
> }
> if (!follow_up(&nd->path))
> @@ -1419,6 +1441,7 @@ static void follow_dotdot(struct nameidata *nd)
> }
> follow_mount(&nd->path);
> nd->inode = nd->path.dentry->d_inode;
> + return 0;
> }
>
> /*
> @@ -1634,7 +1657,7 @@ static inline int handle_dots(struct nameidata *nd, int type)
> if (nd->flags & LOOKUP_RCU) {
> return follow_dotdot_rcu(nd);
> } else
> - follow_dotdot(nd);
> + return follow_dotdot(nd);
> }
> return 0;
> }
I really like this patch, particularly from the standpoint of
backporting to -stable and enterprise kernels. I suspect that all the
tracking of which mounts might have been escaped from should be
classified as premature optimisation, until measurements show otherwise.
path_connected() adds no locks or even atomics. The path that it walks
will be well-trodden and so very likely most of it will be in the CPU
cache.
And I particularly like that follow_dotdot() and follow_dotdot_rcu()
now both that the same signature :-) What's not to like?
Reviewed-by: NeilBrown <neilb@suse.com>
in case it helps.
NeilBrown
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] vfs: Test for and handle paths that are unreachable from their mnt_root
@ 2015-08-17 6:41 George Spelvin
0 siblings, 0 replies; 3+ messages in thread
From: George Spelvin @ 2015-08-17 6:41 UTC (permalink / raw)
To: ebiederm; +Cc: linux, linux-fsdevel, neilb
I can't claim to understnd the code well enough, but may I request the
commit message:
To avoid races path_connected must be called after following a path
- component to it's next path component.
+ component to its next path component.
The recommended mnemonic is:
Whose? My, your, his, her, its, our, their.
Whose? Mine, yours, his, hers, its, ours, theirs.
Who's? I'm, you're, he's, she's, it's, we're they're.
Who's? I've, you've, he's, she's, it's, we've, they've.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2015-08-17 6:48 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-17 6:41 [PATCH] vfs: Test for and handle paths that are unreachable from their mnt_root George Spelvin
-- strict thread matches above, loose matches on Subject: below --
2015-01-02 21:42 [PATCH review 0/9] Call for testing and review of mount detach fixes Eric W. Biederman
2015-01-05 20:45 ` [PATCH review 0/11 Call for testing and review of mount detach fixes (take 2) Eric W. Biederman
2015-04-03 1:53 ` [PATCH review 0/19] Locked mount and loopback mount fixes Eric W. Biederman
2015-04-08 23:31 ` [PATCH review 0/4] Loopback mount escape fixes Eric W. Biederman
2015-08-03 21:25 ` [PATCH review 0/6] Bind " Eric W. Biederman
2015-08-03 21:27 ` [PATCH review 4/6] mnt: Track when a directory escapes a bind mount Eric W. Biederman
2015-08-10 4:36 ` Al Viro
2015-08-14 4:10 ` Eric W. Biederman
2015-08-14 4:29 ` [PATCH review 0/8] Bind mount escape fixes Eric W. Biederman
2015-08-14 4:31 ` [PATCH review 3/8] dcache: Clearly separate the two directory rename cases in d_splice_alias Eric W. Biederman
2015-08-15 6:16 ` Al Viro
2015-08-15 18:25 ` Eric W. Biederman
2015-08-15 18:35 ` [PATCH review 0/7] Bind mount escape fixes Eric W. Biederman
2015-08-15 19:36 ` Linus Torvalds
2015-08-15 19:48 ` Linus Torvalds
2015-08-15 21:07 ` Eric W. Biederman
2015-08-15 22:47 ` Linus Torvalds
2015-08-16 0:59 ` Eric W. Biederman
[not found] ` <87bne82glg.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
2015-08-16 1:27 ` [PATCH] vfs: Test for and handle paths that are unreachable from their mnt_root Eric W. Biederman
2015-08-17 3:56 ` NeilBrown
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).