aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/user_namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r--kernel/user_namespace.c62
1 files changed, 48 insertions, 14 deletions
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) &&