diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/namespace.c | 18 | ||||
| -rw-r--r-- | fs/pnode.c | 1 | ||||
| -rw-r--r-- | fs/proc/base.c | 53 |
3 files changed, 69 insertions, 3 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 30df6e7dd807..820af6a1dd6b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -963,7 +963,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, | |||
| 963 | } | 963 | } |
| 964 | 964 | ||
| 965 | /* Don't allow unprivileged users to reveal what is under a mount */ | 965 | /* Don't allow unprivileged users to reveal what is under a mount */ |
| 966 | if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire)) | 966 | if ((flag & CL_UNPRIVILEGED) && |
| 967 | (!(flag & CL_EXPIRE) || list_empty(&old->mnt_expire))) | ||
| 967 | mnt->mnt.mnt_flags |= MNT_LOCKED; | 968 | mnt->mnt.mnt_flags |= MNT_LOCKED; |
| 968 | 969 | ||
| 969 | atomic_inc(&sb->s_active); | 970 | atomic_inc(&sb->s_active); |
| @@ -1544,6 +1545,9 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) | |||
| 1544 | goto dput_and_out; | 1545 | goto dput_and_out; |
| 1545 | if (mnt->mnt.mnt_flags & MNT_LOCKED) | 1546 | if (mnt->mnt.mnt_flags & MNT_LOCKED) |
| 1546 | goto dput_and_out; | 1547 | goto dput_and_out; |
| 1548 | retval = -EPERM; | ||
| 1549 | if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) | ||
| 1550 | goto dput_and_out; | ||
| 1547 | 1551 | ||
| 1548 | retval = do_umount(mnt, flags); | 1552 | retval = do_umount(mnt, flags); |
| 1549 | dput_and_out: | 1553 | dput_and_out: |
| @@ -1606,7 +1610,6 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
| 1606 | if (IS_ERR(q)) | 1610 | if (IS_ERR(q)) |
| 1607 | return q; | 1611 | return q; |
| 1608 | 1612 | ||
| 1609 | q->mnt.mnt_flags &= ~MNT_LOCKED; | ||
| 1610 | q->mnt_mountpoint = mnt->mnt_mountpoint; | 1613 | q->mnt_mountpoint = mnt->mnt_mountpoint; |
| 1611 | 1614 | ||
| 1612 | p = mnt; | 1615 | p = mnt; |
| @@ -2097,7 +2100,13 @@ static int do_remount(struct path *path, int flags, int mnt_flags, | |||
| 2097 | } | 2100 | } |
| 2098 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && | 2101 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && |
| 2099 | !(mnt_flags & MNT_NODEV)) { | 2102 | !(mnt_flags & MNT_NODEV)) { |
| 2100 | return -EPERM; | 2103 | /* Was the nodev implicitly added in mount? */ |
| 2104 | if ((mnt->mnt_ns->user_ns != &init_user_ns) && | ||
| 2105 | !(sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT)) { | ||
| 2106 | mnt_flags |= MNT_NODEV; | ||
| 2107 | } else { | ||
| 2108 | return -EPERM; | ||
| 2109 | } | ||
| 2101 | } | 2110 | } |
| 2102 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) && | 2111 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) && |
| 2103 | !(mnt_flags & MNT_NOSUID)) { | 2112 | !(mnt_flags & MNT_NOSUID)) { |
| @@ -2958,6 +2967,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
| 2958 | /* mount new_root on / */ | 2967 | /* mount new_root on / */ |
| 2959 | attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp); | 2968 | attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp); |
| 2960 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2969 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
| 2970 | /* A moved mount should not expire automatically */ | ||
| 2971 | list_del_init(&new_mnt->mnt_expire); | ||
| 2961 | unlock_mount_hash(); | 2972 | unlock_mount_hash(); |
| 2962 | chroot_fs_refs(&root, &new); | 2973 | chroot_fs_refs(&root, &new); |
| 2963 | put_mountpoint(root_mp); | 2974 | put_mountpoint(root_mp); |
| @@ -3002,6 +3013,7 @@ static void __init init_mount_tree(void) | |||
| 3002 | 3013 | ||
| 3003 | root.mnt = mnt; | 3014 | root.mnt = mnt; |
| 3004 | root.dentry = mnt->mnt_root; | 3015 | root.dentry = mnt->mnt_root; |
| 3016 | mnt->mnt_flags |= MNT_LOCKED; | ||
| 3005 | 3017 | ||
| 3006 | set_fs_pwd(current->fs, &root); | 3018 | set_fs_pwd(current->fs, &root); |
| 3007 | set_fs_root(current->fs, &root); | 3019 | set_fs_root(current->fs, &root); |
diff --git a/fs/pnode.c b/fs/pnode.c index aae331a5d03b..260ac8f898a4 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
| @@ -242,6 +242,7 @@ static int propagate_one(struct mount *m) | |||
| 242 | child = copy_tree(last_source, last_source->mnt.mnt_root, type); | 242 | child = copy_tree(last_source, last_source->mnt.mnt_root, type); |
| 243 | if (IS_ERR(child)) | 243 | if (IS_ERR(child)) |
| 244 | return PTR_ERR(child); | 244 | return PTR_ERR(child); |
| 245 | child->mnt.mnt_flags &= ~MNT_LOCKED; | ||
| 245 | mnt_set_mountpoint(m, mp, child); | 246 | mnt_set_mountpoint(m, mp, child); |
| 246 | last_dest = m; | 247 | last_dest = m; |
| 247 | last_source = child; | 248 | last_source = child; |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 590aeda5af12..3f3d7aeb0712 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -2464,6 +2464,57 @@ static const struct file_operations proc_projid_map_operations = { | |||
| 2464 | .llseek = seq_lseek, | 2464 | .llseek = seq_lseek, |
| 2465 | .release = proc_id_map_release, | 2465 | .release = proc_id_map_release, |
| 2466 | }; | 2466 | }; |
| 2467 | |||
| 2468 | static int proc_setgroups_open(struct inode *inode, struct file *file) | ||
| 2469 | { | ||
| 2470 | struct user_namespace *ns = NULL; | ||
| 2471 | struct task_struct *task; | ||
| 2472 | int ret; | ||
| 2473 | |||
| 2474 | ret = -ESRCH; | ||
| 2475 | task = get_proc_task(inode); | ||
| 2476 | if (task) { | ||
| 2477 | rcu_read_lock(); | ||
| 2478 | ns = get_user_ns(task_cred_xxx(task, user_ns)); | ||
| 2479 | rcu_read_unlock(); | ||
| 2480 | put_task_struct(task); | ||
| 2481 | } | ||
| 2482 | if (!ns) | ||
| 2483 | goto err; | ||
| 2484 | |||
| 2485 | if (file->f_mode & FMODE_WRITE) { | ||
| 2486 | ret = -EACCES; | ||
| 2487 | if (!ns_capable(ns, CAP_SYS_ADMIN)) | ||
| 2488 | goto err_put_ns; | ||
| 2489 | } | ||
| 2490 | |||
| 2491 | ret = single_open(file, &proc_setgroups_show, ns); | ||
| 2492 | if (ret) | ||
| 2493 | goto err_put_ns; | ||
| 2494 | |||
| 2495 | return 0; | ||
| 2496 | err_put_ns: | ||
| 2497 | put_user_ns(ns); | ||
| 2498 | err: | ||
| 2499 | return ret; | ||
| 2500 | } | ||
| 2501 | |||
| 2502 | static int proc_setgroups_release(struct inode *inode, struct file *file) | ||
| 2503 | { | ||
| 2504 | struct seq_file *seq = file->private_data; | ||
| 2505 | struct user_namespace *ns = seq->private; | ||
| 2506 | int ret = single_release(inode, file); | ||
| 2507 | put_user_ns(ns); | ||
| 2508 | return ret; | ||
| 2509 | } | ||
| 2510 | |||
| 2511 | static const struct file_operations proc_setgroups_operations = { | ||
| 2512 | .open = proc_setgroups_open, | ||
| 2513 | .write = proc_setgroups_write, | ||
| 2514 | .read = seq_read, | ||
| 2515 | .llseek = seq_lseek, | ||
| 2516 | .release = proc_setgroups_release, | ||
| 2517 | }; | ||
| 2467 | #endif /* CONFIG_USER_NS */ | 2518 | #endif /* CONFIG_USER_NS */ |
| 2468 | 2519 | ||
| 2469 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, | 2520 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, |
| @@ -2572,6 +2623,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 2572 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), | 2623 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), |
| 2573 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | 2624 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), |
| 2574 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), | 2625 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), |
| 2626 | REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), | ||
| 2575 | #endif | 2627 | #endif |
| 2576 | #ifdef CONFIG_CHECKPOINT_RESTORE | 2628 | #ifdef CONFIG_CHECKPOINT_RESTORE |
| 2577 | REG("timers", S_IRUGO, proc_timers_operations), | 2629 | REG("timers", S_IRUGO, proc_timers_operations), |
| @@ -2916,6 +2968,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
| 2916 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), | 2968 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), |
| 2917 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | 2969 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), |
| 2918 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), | 2970 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), |
| 2971 | REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), | ||
| 2919 | #endif | 2972 | #endif |
| 2920 | }; | 2973 | }; |
| 2921 | 2974 | ||
