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.c66
1 files changed, 52 insertions, 14 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 2b042c42fbc4..b14f4d342043 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -21,6 +21,7 @@
21#include <linux/uaccess.h> 21#include <linux/uaccess.h>
22#include <linux/ctype.h> 22#include <linux/ctype.h>
23#include <linux/projid.h> 23#include <linux/projid.h>
24#include <linux/fs_struct.h>
24 25
25static struct kmem_cache *user_ns_cachep __read_mostly; 26static struct kmem_cache *user_ns_cachep __read_mostly;
26 27
@@ -78,7 +79,7 @@ int create_user_ns(struct cred *new)
78 return ret; 79 return ret;
79 } 80 }
80 81
81 kref_init(&ns->kref); 82 atomic_set(&ns->count, 1);
82 /* Leave the new->user_ns reference with the new user namespace. */ 83 /* Leave the new->user_ns reference with the new user namespace. */
83 ns->parent = parent_ns; 84 ns->parent = parent_ns;
84 ns->owner = owner; 85 ns->owner = owner;
@@ -104,15 +105,16 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
104 return create_user_ns(cred); 105 return create_user_ns(cred);
105} 106}
106 107
107void free_user_ns(struct kref *kref) 108void free_user_ns(struct user_namespace *ns)
108{ 109{
109 struct user_namespace *parent, *ns = 110 struct user_namespace *parent;
110 container_of(kref, struct user_namespace, kref);
111 111
112 parent = ns->parent; 112 do {
113 proc_free_inum(ns->proc_inum); 113 parent = ns->parent;
114 kmem_cache_free(user_ns_cachep, ns); 114 proc_free_inum(ns->proc_inum);
115 put_user_ns(parent); 115 kmem_cache_free(user_ns_cachep, ns);
116 ns = parent;
117 } while (atomic_dec_and_test(&parent->count));
116} 118}
117EXPORT_SYMBOL(free_user_ns); 119EXPORT_SYMBOL(free_user_ns);
118 120
@@ -519,6 +521,42 @@ struct seq_operations proc_projid_seq_operations = {
519 .show = projid_m_show, 521 .show = projid_m_show,
520}; 522};
521 523
524static bool mappings_overlap(struct uid_gid_map *new_map, struct uid_gid_extent *extent)
525{
526 u32 upper_first, lower_first, upper_last, lower_last;
527 unsigned idx;
528
529 upper_first = extent->first;
530 lower_first = extent->lower_first;
531 upper_last = upper_first + extent->count - 1;
532 lower_last = lower_first + extent->count - 1;
533
534 for (idx = 0; idx < new_map->nr_extents; idx++) {
535 u32 prev_upper_first, prev_lower_first;
536 u32 prev_upper_last, prev_lower_last;
537 struct uid_gid_extent *prev;
538
539 prev = &new_map->extent[idx];
540
541 prev_upper_first = prev->first;
542 prev_lower_first = prev->lower_first;
543 prev_upper_last = prev_upper_first + prev->count - 1;
544 prev_lower_last = prev_lower_first + prev->count - 1;
545
546 /* Does the upper range intersect a previous extent? */
547 if ((prev_upper_first <= upper_last) &&
548 (prev_upper_last >= upper_first))
549 return true;
550
551 /* Does the lower range intersect a previous extent? */
552 if ((prev_lower_first <= lower_last) &&
553 (prev_lower_last >= lower_first))
554 return true;
555 }
556 return false;
557}
558
559
522static DEFINE_MUTEX(id_map_mutex); 560static DEFINE_MUTEX(id_map_mutex);
523 561
524static ssize_t map_write(struct file *file, const char __user *buf, 562static ssize_t map_write(struct file *file, const char __user *buf,
@@ -531,7 +569,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
531 struct user_namespace *ns = seq->private; 569 struct user_namespace *ns = seq->private;
532 struct uid_gid_map new_map; 570 struct uid_gid_map new_map;
533 unsigned idx; 571 unsigned idx;
534 struct uid_gid_extent *extent, *last = NULL; 572 struct uid_gid_extent *extent = NULL;
535 unsigned long page = 0; 573 unsigned long page = 0;
536 char *kbuf, *pos, *next_line; 574 char *kbuf, *pos, *next_line;
537 ssize_t ret = -EINVAL; 575 ssize_t ret = -EINVAL;
@@ -634,14 +672,11 @@ static ssize_t map_write(struct file *file, const char __user *buf,
634 if ((extent->lower_first + extent->count) <= extent->lower_first) 672 if ((extent->lower_first + extent->count) <= extent->lower_first)
635 goto out; 673 goto out;
636 674
637 /* For now only accept extents that are strictly in order */ 675 /* Do the ranges in extent overlap any previous extents? */
638 if (last && 676 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; 677 goto out;
642 678
643 new_map.nr_extents++; 679 new_map.nr_extents++;
644 last = extent;
645 680
646 /* Fail if the file contains too many extents */ 681 /* Fail if the file contains too many extents */
647 if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) && 682 if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) &&
@@ -803,6 +838,9 @@ static int userns_install(struct nsproxy *nsproxy, void *ns)
803 if (atomic_read(&current->mm->mm_users) > 1) 838 if (atomic_read(&current->mm->mm_users) > 1)
804 return -EINVAL; 839 return -EINVAL;
805 840
841 if (current->fs->users != 1)
842 return -EINVAL;
843
806 if (!ns_capable(user_ns, CAP_SYS_ADMIN)) 844 if (!ns_capable(user_ns, CAP_SYS_ADMIN))
807 return -EPERM; 845 return -EPERM;
808 846