diff options
| author | Eric W. Biederman <ebiederm@xmission.com> | 2013-03-22 04:08:05 -0700 | 
|---|---|---|
| committer | Eric W. Biederman <ebiederm@xmission.com> | 2013-03-27 07:50:05 -0700 | 
| commit | 132c94e31b8bca8ea921f9f96a57d684fa4ae0a9 (patch) | |
| tree | 52db12073a31f62301367416b2a3afec185975ef | |
| parent | 90563b198e4c6674c63672fae1923da467215f45 (diff) | |
| download | olio-linux-3.10-132c94e31b8bca8ea921f9f96a57d684fa4ae0a9.tar.xz olio-linux-3.10-132c94e31b8bca8ea921f9f96a57d684fa4ae0a9.zip  | |
vfs: Carefully propogate mounts across user namespaces
As a matter of policy MNT_READONLY should not be changable if the
original mounter had more privileges than creator of the mount
namespace.
Add the flag CL_UNPRIVILEGED to note when we are copying a mount from
a mount namespace that requires more privileges to a mount namespace
that requires fewer privileges.
When the CL_UNPRIVILEGED flag is set cause clone_mnt to set MNT_NO_REMOUNT
if any of the mnt flags that should never be changed are set.
This protects both mount propagation and the initial creation of a less
privileged mount namespace.
Cc: stable@vger.kernel.org
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Reported-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
| -rw-r--r-- | fs/namespace.c | 6 | ||||
| -rw-r--r-- | fs/pnode.c | 6 | ||||
| -rw-r--r-- | fs/pnode.h | 1 | 
3 files changed, 12 insertions, 1 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 8505b5ece5d..968d4c5eae0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -798,6 +798,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,  	}  	mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; +	/* Don't allow unprivileged users to change mount flags */ +	if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) +		mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; +  	atomic_inc(&sb->s_active);  	mnt->mnt.mnt_sb = sb;  	mnt->mnt.mnt_root = dget(root); @@ -2342,7 +2346,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,  	/* First pass: copy the tree topology */  	copy_flags = CL_COPY_ALL | CL_EXPIRE;  	if (user_ns != mnt_ns->user_ns) -		copy_flags |= CL_SHARED_TO_SLAVE; +		copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;  	new = copy_tree(old, old->mnt.mnt_root, copy_flags);  	if (IS_ERR(new)) {  		up_write(&namespace_sem); diff --git a/fs/pnode.c b/fs/pnode.c index 3e000a51ac0..8b29d2164da 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -9,6 +9,7 @@  #include <linux/mnt_namespace.h>  #include <linux/mount.h>  #include <linux/fs.h> +#include <linux/nsproxy.h>  #include "internal.h"  #include "pnode.h" @@ -220,6 +221,7 @@ static struct mount *get_source(struct mount *dest,  int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry,  		    struct mount *source_mnt, struct list_head *tree_list)  { +	struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;  	struct mount *m, *child;  	int ret = 0;  	struct mount *prev_dest_mnt = dest_mnt; @@ -237,6 +239,10 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry,  		source =  get_source(m, prev_dest_mnt, prev_src_mnt, &type); +		/* Notice when we are propagating across user namespaces */ +		if (m->mnt_ns->user_ns != user_ns) +			type |= CL_UNPRIVILEGED; +  		child = copy_tree(source, source->mnt.mnt_root, type);  		if (IS_ERR(child)) {  			ret = PTR_ERR(child); diff --git a/fs/pnode.h b/fs/pnode.h index 19b853a3445..a0493d5ebfb 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -23,6 +23,7 @@  #define CL_MAKE_SHARED 		0x08  #define CL_PRIVATE 		0x10  #define CL_SHARED_TO_SLAVE	0x20 +#define CL_UNPRIVILEGED		0x40  static inline void set_mnt_shared(struct mount *mnt)  {  |