aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c37
-rw-r--r--fs/proc/root.c7
-rw-r--r--fs/sysfs/mount.c3
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/user_namespace.h4
-rw-r--r--kernel/user.c2
-rw-r--r--kernel/user_namespace.c2
7 files changed, 33 insertions, 23 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 64627f883bf2..877e4277f496 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2867,25 +2867,38 @@ bool current_chrooted(void)
2867 return chrooted; 2867 return chrooted;
2868} 2868}
2869 2869
2870void update_mnt_policy(struct user_namespace *userns) 2870bool fs_fully_visible(struct file_system_type *type)
2871{ 2871{
2872 struct mnt_namespace *ns = current->nsproxy->mnt_ns; 2872 struct mnt_namespace *ns = current->nsproxy->mnt_ns;
2873 struct mount *mnt; 2873 struct mount *mnt;
2874 bool visible = false;
2874 2875
2875 down_read(&namespace_sem); 2876 if (unlikely(!ns))
2877 return false;
2878
2879 namespace_lock();
2876 list_for_each_entry(mnt, &ns->list, mnt_list) { 2880 list_for_each_entry(mnt, &ns->list, mnt_list) {
2877 switch (mnt->mnt.mnt_sb->s_magic) { 2881 struct mount *child;
2878 case SYSFS_MAGIC: 2882 if (mnt->mnt.mnt_sb->s_type != type)
2879 userns->may_mount_sysfs = true; 2883 continue;
2880 break; 2884
2881 case PROC_SUPER_MAGIC: 2885 /* This mount is not fully visible if there are any child mounts
2882 userns->may_mount_proc = true; 2886 * that cover anything except for empty directories.
2883 break; 2887 */
2888 list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
2889 struct inode *inode = child->mnt_mountpoint->d_inode;
2890 if (!S_ISDIR(inode->i_mode))
2891 goto next;
2892 if (inode->i_nlink != 2)
2893 goto next;
2884 } 2894 }
2885 if (userns->may_mount_sysfs && userns->may_mount_proc) 2895 visible = true;
2886 break; 2896 goto found;
2897 next: ;
2887 } 2898 }
2888 up_read(&namespace_sem); 2899found:
2900 namespace_unlock();
2901 return visible;
2889} 2902}
2890 2903
2891static void *mntns_get(struct task_struct *task) 2904static void *mntns_get(struct task_struct *task)
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 38bd5d423fcd..45e5fb7da09b 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -110,8 +110,11 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
110 ns = task_active_pid_ns(current); 110 ns = task_active_pid_ns(current);
111 options = data; 111 options = data;
112 112
113 if (!current_user_ns()->may_mount_proc || 113 if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
114 !ns_capable(ns->user_ns, CAP_SYS_ADMIN)) 114 return ERR_PTR(-EPERM);
115
116 /* Does the mounter have privilege over the pid namespace? */
117 if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
115 return ERR_PTR(-EPERM); 118 return ERR_PTR(-EPERM);
116 } 119 }
117 120
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index afd83273e6ce..4a2da3a4b1b1 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -112,7 +112,8 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
112 struct super_block *sb; 112 struct super_block *sb;
113 int error; 113 int error;
114 114
115 if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs) 115 if (!(flags & MS_KERNMOUNT) && !capable(CAP_SYS_ADMIN) &&
116 !fs_fully_visible(fs_type))
116 return ERR_PTR(-EPERM); 117 return ERR_PTR(-EPERM);
117 118
118 info = kzalloc(sizeof(*info), GFP_KERNEL); 119 info = kzalloc(sizeof(*info), GFP_KERNEL);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 981874773e85..3050c620f062 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1897,6 +1897,7 @@ extern int vfs_ustat(dev_t, struct kstatfs *);
1897extern int freeze_super(struct super_block *super); 1897extern int freeze_super(struct super_block *super);
1898extern int thaw_super(struct super_block *super); 1898extern int thaw_super(struct super_block *super);
1899extern bool our_mnt(struct vfsmount *mnt); 1899extern bool our_mnt(struct vfsmount *mnt);
1900extern bool fs_fully_visible(struct file_system_type *);
1900 1901
1901extern int current_umask(void); 1902extern int current_umask(void);
1902 1903
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index b6b215f13b45..4ce009324933 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -26,8 +26,6 @@ struct user_namespace {
26 kuid_t owner; 26 kuid_t owner;
27 kgid_t group; 27 kgid_t group;
28 unsigned int proc_inum; 28 unsigned int proc_inum;
29 bool may_mount_sysfs;
30 bool may_mount_proc;
31}; 29};
32 30
33extern struct user_namespace init_user_ns; 31extern struct user_namespace init_user_ns;
@@ -84,6 +82,4 @@ static inline void put_user_ns(struct user_namespace *ns)
84 82
85#endif 83#endif
86 84
87void update_mnt_policy(struct user_namespace *userns);
88
89#endif /* _LINUX_USER_H */ 85#endif /* _LINUX_USER_H */
diff --git a/kernel/user.c b/kernel/user.c
index 69b4c3d48cde..5bbb91988e69 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -51,8 +51,6 @@ struct user_namespace init_user_ns = {
51 .owner = GLOBAL_ROOT_UID, 51 .owner = GLOBAL_ROOT_UID,
52 .group = GLOBAL_ROOT_GID, 52 .group = GLOBAL_ROOT_GID,
53 .proc_inum = PROC_USER_INIT_INO, 53 .proc_inum = PROC_USER_INIT_INO,
54 .may_mount_sysfs = true,
55 .may_mount_proc = true,
56}; 54};
57EXPORT_SYMBOL_GPL(init_user_ns); 55EXPORT_SYMBOL_GPL(init_user_ns);
58 56
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index d8c30db06c5b..d58ad1e7a794 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -97,8 +97,6 @@ int create_user_ns(struct cred *new)
97 97
98 set_cred_user_ns(new, ns); 98 set_cred_user_ns(new, ns);
99 99
100 update_mnt_policy(ns);
101
102 return 0; 100 return 0;
103} 101}
104 102