aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sys.c5
-rw-r--r--kernel/user.c4
-rw-r--r--kernel/user_namespace.c62
3 files changed, 52 insertions, 19 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index 840cfdad7bfc..2e18d33ca775 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -434,11 +434,12 @@ static DEFINE_MUTEX(reboot_mutex);
434SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, 434SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
435 void __user *, arg) 435 void __user *, arg)
436{ 436{
437 struct pid_namespace *pid_ns = task_active_pid_ns(current);
437 char buffer[256]; 438 char buffer[256];
438 int ret = 0; 439 int ret = 0;
439 440
440 /* We only trust the superuser with rebooting the system. */ 441 /* We only trust the superuser with rebooting the system. */
441 if (!capable(CAP_SYS_BOOT)) 442 if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
442 return -EPERM; 443 return -EPERM;
443 444
444 /* For safety, we require "magic" arguments. */ 445 /* For safety, we require "magic" arguments. */
@@ -454,7 +455,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
454 * pid_namespace, the command is handled by reboot_pid_ns() which will 455 * pid_namespace, the command is handled by reboot_pid_ns() which will
455 * call do_exit(). 456 * call do_exit().
456 */ 457 */
457 ret = reboot_pid_ns(task_active_pid_ns(current), cmd); 458 ret = reboot_pid_ns(pid_ns, cmd);
458 if (ret) 459 if (ret)
459 return ret; 460 return ret;
460 461
diff --git a/kernel/user.c b/kernel/user.c
index 33acb5e53a5f..57ebfd42023c 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -47,9 +47,7 @@ struct user_namespace init_user_ns = {
47 .count = 4294967295U, 47 .count = 4294967295U,
48 }, 48 },
49 }, 49 },
50 .kref = { 50 .count = ATOMIC_INIT(3),
51 .refcount = ATOMIC_INIT(3),
52 },
53 .owner = GLOBAL_ROOT_UID, 51 .owner = GLOBAL_ROOT_UID,
54 .group = GLOBAL_ROOT_GID, 52 .group = GLOBAL_ROOT_GID,
55 .proc_inum = PROC_USER_INIT_INO, 53 .proc_inum = PROC_USER_INIT_INO,
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 2b042c42fbc4..8b650837083e 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -78,7 +78,7 @@ int create_user_ns(struct cred *new)
78 return ret; 78 return ret;
79 } 79 }
80 80
81 kref_init(&ns->kref); 81 atomic_set(&ns->count, 1);
82 /* Leave the new->user_ns reference with the new user namespace. */ 82 /* Leave the new->user_ns reference with the new user namespace. */
83 ns->parent = parent_ns; 83 ns->parent = parent_ns;
84 ns->owner = owner; 84 ns->owner = owner;
@@ -104,15 +104,16 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
104 return create_user_ns(cred); 104 return create_user_ns(cred);
105} 105}
106 106
107void free_user_ns(struct kref *kref) 107void free_user_ns(struct user_namespace *ns)
108{ 108{
109 struct user_namespace *parent, *ns = 109 struct user_namespace *parent;
110 container_of(kref, struct user_namespace, kref);
111 110
112 parent = ns->parent; 111 do {
113 proc_free_inum(ns->proc_inum); 112 parent = ns->parent;
114 kmem_cache_free(user_ns_cachep, ns); 113 proc_free_inum(ns->proc_inum);
115 put_user_ns(parent); 114 kmem_cache_free(user_ns_cachep, ns);
115 ns = parent;
116 } while (atomic_dec_and_test(&parent->count));
116} 117}
117EXPORT_SYMBOL(free_user_ns); 118EXPORT_SYMBOL(free_user_ns);
118 119
@@ -519,6 +520,42 @@ struct seq_operations proc_projid_seq_operations = {
519 .show = projid_m_show, 520 .show = projid_m_show,
520}; 521};
521 522
523static bool mappings_overlap(struct uid_gid_map *new_map, struct uid_gid_extent *extent)
524{
525 u32 upper_first, lower_first, upper_last, lower_last;
526 unsigned idx;
527
528 upper_first = extent->first;
529 lower_first = extent->lower_first;
530 upper_last = upper_first + extent->count - 1;
531 lower_last = lower_first + extent->count - 1;
532
533 for (idx = 0; idx < new_map->nr_extents; idx++) {
534 u32 prev_upper_first, prev_lower_first;
535 u32 prev_upper_last, prev_lower_last;
536 struct uid_gid_extent *prev;
537
538 prev = &new_map->extent[idx];
539
540 prev_upper_first = prev->first;
541 prev_lower_first = prev->lower_first;
542 prev_upper_last = prev_upper_first + prev->count - 1;
543 prev_lower_last = prev_lower_first + prev->count - 1;
544
545 /* Does the upper range intersect a previous extent? */
546 if ((prev_upper_first <= upper_last) &&
547 (prev_upper_last >= upper_first))
548 return true;
549
550 /* Does the lower range intersect a previous extent? */
551 if ((prev_lower_first <= lower_last) &&
552 (prev_lower_last >= lower_first))
553 return true;
554 }
555 return false;
556}
557
558
522static DEFINE_MUTEX(id_map_mutex); 559static DEFINE_MUTEX(id_map_mutex);
523 560
524static ssize_t map_write(struct file *file, const char __user *buf, 561static ssize_t map_write(struct file *file, const char __user *buf,
@@ -531,7 +568,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
531 struct user_namespace *ns = seq->private; 568 struct user_namespace *ns = seq->private;
532 struct uid_gid_map new_map; 569 struct uid_gid_map new_map;
533 unsigned idx; 570 unsigned idx;
534 struct uid_gid_extent *extent, *last = NULL; 571 struct uid_gid_extent *extent = NULL;
535 unsigned long page = 0; 572 unsigned long page = 0;
536 char *kbuf, *pos, *next_line; 573 char *kbuf, *pos, *next_line;
537 ssize_t ret = -EINVAL; 574 ssize_t ret = -EINVAL;
@@ -634,14 +671,11 @@ static ssize_t map_write(struct file *file, const char __user *buf,
634 if ((extent->lower_first + extent->count) <= extent->lower_first) 671 if ((extent->lower_first + extent->count) <= extent->lower_first)
635 goto out; 672 goto out;
636 673
637 /* For now only accept extents that are strictly in order */ 674 /* Do the ranges in extent overlap any previous extents? */
638 if (last && 675 if (mappings_overlap(&new_map, extent))
639 (((last->first + last->count) > extent->first) ||
640 ((last->lower_first + last->count) > extent->lower_first)))
641 goto out; 676 goto out;
642 677
643 new_map.nr_extents++; 678 new_map.nr_extents++;
644 last = extent;
645 679
646 /* Fail if the file contains too many extents */ 680 /* Fail if the file contains too many extents */
647 if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) && 681 if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) &&