diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-21 08:19:02 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-22 20:48:18 -0400 |
commit | 156cacb1d0d36b0d0582d9e798e58e0044f516b3 (patch) | |
tree | 79eddbde8671b1899d77dcfabb3ae3e21ce39072 | |
parent | fea7a08acb13524b47711625eebea40a0ede69a0 (diff) | |
download | op-kernel-dev-156cacb1d0d36b0d0582d9e798e58e0044f516b3.zip op-kernel-dev-156cacb1d0d36b0d0582d9e798e58e0044f516b3.tar.gz |
do_add_mount()/umount -l races
normally we deal with lock_mount()/umount races by checking that
mountpoint to be is still in our namespace after lock_mount() has
been done. However, do_add_mount() skips that check when called
with MNT_SHRINKABLE in flags (i.e. from finish_automount()). The
reason is that ->mnt_ns may be a temporary namespace created exactly
to contain automounts a-la NFS4 referral handling. It's not the
namespace of the caller, though, so check_mnt() would fail here.
We still need to check that ->mnt_ns is non-NULL in that case,
though.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namespace.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 4d31f73..7bdf790 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1886,8 +1886,14 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) return err; err = -EINVAL; - if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(real_mount(path->mnt))) - goto unlock; + if (unlikely(!check_mnt(real_mount(path->mnt)))) { + /* that's acceptable only for automounts done in private ns */ + if (!(mnt_flags & MNT_SHRINKABLE)) + goto unlock; + /* ... and for those we'd better have mountpoint still alive */ + if (!real_mount(path->mnt)->mnt_ns) + goto unlock; + } /* Refuse the same filesystem on the same mount point */ err = -EBUSY; |