diff options
-rw-r--r-- | fs/namespace.c | 37 | ||||
-rw-r--r-- | fs/proc/root.c | 7 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 3 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | include/linux/user_namespace.h | 4 | ||||
-rw-r--r-- | kernel/user.c | 2 | ||||
-rw-r--r-- | kernel/user_namespace.c | 2 |
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 | ||
2870 | void update_mnt_policy(struct user_namespace *userns) | 2870 | bool 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); | 2899 | found: |
2900 | namespace_unlock(); | ||
2901 | return visible; | ||
2889 | } | 2902 | } |
2890 | 2903 | ||
2891 | static void *mntns_get(struct task_struct *task) | 2904 | static 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 *); | |||
1897 | extern int freeze_super(struct super_block *super); | 1897 | extern int freeze_super(struct super_block *super); |
1898 | extern int thaw_super(struct super_block *super); | 1898 | extern int thaw_super(struct super_block *super); |
1899 | extern bool our_mnt(struct vfsmount *mnt); | 1899 | extern bool our_mnt(struct vfsmount *mnt); |
1900 | extern bool fs_fully_visible(struct file_system_type *); | ||
1900 | 1901 | ||
1901 | extern int current_umask(void); | 1902 | extern 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 | ||
33 | extern struct user_namespace init_user_ns; | 31 | extern 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 | ||
87 | void 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 | }; |
57 | EXPORT_SYMBOL_GPL(init_user_ns); | 55 | EXPORT_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 | ||