aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c99
1 files changed, 47 insertions, 52 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 419f746d851d..7bb2cda3bfef 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2186,13 +2186,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
2186 } 2186 }
2187 if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && 2187 if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
2188 !(mnt_flags & MNT_NODEV)) { 2188 !(mnt_flags & MNT_NODEV)) {
2189 /* Was the nodev implicitly added in mount? */ 2189 return -EPERM;
2190 if ((mnt->mnt_ns->user_ns != &init_user_ns) &&
2191 !(sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT)) {
2192 mnt_flags |= MNT_NODEV;
2193 } else {
2194 return -EPERM;
2195 }
2196 } 2190 }
2197 if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) && 2191 if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
2198 !(mnt_flags & MNT_NOSUID)) { 2192 !(mnt_flags & MNT_NOSUID)) {
@@ -2376,7 +2370,7 @@ unlock:
2376 return err; 2370 return err;
2377} 2371}
2378 2372
2379static bool fs_fully_visible(struct file_system_type *fs_type, int *new_mnt_flags); 2373static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags);
2380 2374
2381/* 2375/*
2382 * create a new mount for userspace and request it to be added into the 2376 * create a new mount for userspace and request it to be added into the
@@ -2386,7 +2380,6 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
2386 int mnt_flags, const char *name, void *data) 2380 int mnt_flags, const char *name, void *data)
2387{ 2381{
2388 struct file_system_type *type; 2382 struct file_system_type *type;
2389 struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
2390 struct vfsmount *mnt; 2383 struct vfsmount *mnt;
2391 int err; 2384 int err;
2392 2385
@@ -2397,26 +2390,6 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
2397 if (!type) 2390 if (!type)
2398 return -ENODEV; 2391 return -ENODEV;
2399 2392
2400 if (user_ns != &init_user_ns) {
2401 if (!(type->fs_flags & FS_USERNS_MOUNT)) {
2402 put_filesystem(type);
2403 return -EPERM;
2404 }
2405 /* Only in special cases allow devices from mounts
2406 * created outside the initial user namespace.
2407 */
2408 if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) {
2409 flags |= MS_NODEV;
2410 mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
2411 }
2412 if (type->fs_flags & FS_USERNS_VISIBLE) {
2413 if (!fs_fully_visible(type, &mnt_flags)) {
2414 put_filesystem(type);
2415 return -EPERM;
2416 }
2417 }
2418 }
2419
2420 mnt = vfs_kern_mount(type, flags, name, data); 2393 mnt = vfs_kern_mount(type, flags, name, data);
2421 if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && 2394 if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
2422 !mnt->mnt_sb->s_subtype) 2395 !mnt->mnt_sb->s_subtype)
@@ -2426,6 +2399,11 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
2426 if (IS_ERR(mnt)) 2399 if (IS_ERR(mnt))
2427 return PTR_ERR(mnt); 2400 return PTR_ERR(mnt);
2428 2401
2402 if (mount_too_revealing(mnt, &mnt_flags)) {
2403 mntput(mnt);
2404 return -EPERM;
2405 }
2406
2429 err = do_add_mount(real_mount(mnt), path, mnt_flags); 2407 err = do_add_mount(real_mount(mnt), path, mnt_flags);
2430 if (err) 2408 if (err)
2431 mntput(mnt); 2409 mntput(mnt);
@@ -3217,22 +3195,19 @@ bool current_chrooted(void)
3217 return chrooted; 3195 return chrooted;
3218} 3196}
3219 3197
3220static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) 3198static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
3199 int *new_mnt_flags)
3221{ 3200{
3222 struct mnt_namespace *ns = current->nsproxy->mnt_ns;
3223 int new_flags = *new_mnt_flags; 3201 int new_flags = *new_mnt_flags;
3224 struct mount *mnt; 3202 struct mount *mnt;
3225 bool visible = false; 3203 bool visible = false;
3226 3204
3227 if (unlikely(!ns))
3228 return false;
3229
3230 down_read(&namespace_sem); 3205 down_read(&namespace_sem);
3231 list_for_each_entry(mnt, &ns->list, mnt_list) { 3206 list_for_each_entry(mnt, &ns->list, mnt_list) {
3232 struct mount *child; 3207 struct mount *child;
3233 int mnt_flags; 3208 int mnt_flags;
3234 3209
3235 if (mnt->mnt.mnt_sb->s_type != type) 3210 if (mnt->mnt.mnt_sb->s_type != new->mnt_sb->s_type)
3236 continue; 3211 continue;
3237 3212
3238 /* This mount is not fully visible if it's root directory 3213 /* This mount is not fully visible if it's root directory
@@ -3241,12 +3216,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
3241 if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) 3216 if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
3242 continue; 3217 continue;
3243 3218
3244 /* Read the mount flags and filter out flags that 3219 /* A local view of the mount flags */
3245 * may safely be ignored.
3246 */
3247 mnt_flags = mnt->mnt.mnt_flags; 3220 mnt_flags = mnt->mnt.mnt_flags;
3248 if (mnt->mnt.mnt_sb->s_iflags & SB_I_NOEXEC)
3249 mnt_flags &= ~(MNT_LOCK_NOSUID | MNT_LOCK_NOEXEC);
3250 3221
3251 /* Don't miss readonly hidden in the superblock flags */ 3222 /* Don't miss readonly hidden in the superblock flags */
3252 if (mnt->mnt.mnt_sb->s_flags & MS_RDONLY) 3223 if (mnt->mnt.mnt_sb->s_flags & MS_RDONLY)
@@ -3258,15 +3229,6 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
3258 if ((mnt_flags & MNT_LOCK_READONLY) && 3229 if ((mnt_flags & MNT_LOCK_READONLY) &&
3259 !(new_flags & MNT_READONLY)) 3230 !(new_flags & MNT_READONLY))
3260 continue; 3231 continue;
3261 if ((mnt_flags & MNT_LOCK_NODEV) &&
3262 !(new_flags & MNT_NODEV))
3263 continue;
3264 if ((mnt_flags & MNT_LOCK_NOSUID) &&
3265 !(new_flags & MNT_NOSUID))
3266 continue;
3267 if ((mnt_flags & MNT_LOCK_NOEXEC) &&
3268 !(new_flags & MNT_NOEXEC))
3269 continue;
3270 if ((mnt_flags & MNT_LOCK_ATIME) && 3232 if ((mnt_flags & MNT_LOCK_ATIME) &&
3271 ((mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) 3233 ((mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
3272 continue; 3234 continue;
@@ -3286,9 +3248,6 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
3286 } 3248 }
3287 /* Preserve the locked attributes */ 3249 /* Preserve the locked attributes */
3288 *new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \ 3250 *new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \
3289 MNT_LOCK_NODEV | \
3290 MNT_LOCK_NOSUID | \
3291 MNT_LOCK_NOEXEC | \
3292 MNT_LOCK_ATIME); 3251 MNT_LOCK_ATIME);
3293 visible = true; 3252 visible = true;
3294 goto found; 3253 goto found;
@@ -3299,6 +3258,42 @@ found:
3299 return visible; 3258 return visible;
3300} 3259}
3301 3260
3261static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
3262{
3263 const unsigned long required_iflags = SB_I_NOEXEC | SB_I_NODEV;
3264 struct mnt_namespace *ns = current->nsproxy->mnt_ns;
3265 unsigned long s_iflags;
3266
3267 if (ns->user_ns == &init_user_ns)
3268 return false;
3269
3270 /* Can this filesystem be too revealing? */
3271 s_iflags = mnt->mnt_sb->s_iflags;
3272 if (!(s_iflags & SB_I_USERNS_VISIBLE))
3273 return false;
3274
3275 if ((s_iflags & required_iflags) != required_iflags) {
3276 WARN_ONCE(1, "Expected s_iflags to contain 0x%lx\n",
3277 required_iflags);
3278 return true;
3279 }
3280
3281 return !mnt_already_visible(ns, mnt, new_mnt_flags);
3282}
3283
3284bool mnt_may_suid(struct vfsmount *mnt)
3285{
3286 /*
3287 * Foreign mounts (accessed via fchdir or through /proc
3288 * symlinks) are always treated as if they are nosuid. This
3289 * prevents namespaces from trusting potentially unsafe
3290 * suid/sgid bits, file caps, or security labels that originate
3291 * in other namespaces.
3292 */
3293 return !(mnt->mnt_flags & MNT_NOSUID) && check_mnt(real_mount(mnt)) &&
3294 current_in_userns(mnt->mnt_sb->s_user_ns);
3295}
3296
3302static struct ns_common *mntns_get(struct task_struct *task) 3297static struct ns_common *mntns_get(struct task_struct *task)
3303{ 3298{
3304 struct ns_common *ns = NULL; 3299 struct ns_common *ns = NULL;