aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/user_namespace.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2012-12-28 01:27:29 -0500
committerEric W. Biederman <ebiederm@xmission.com>2013-01-27 01:12:04 -0500
commit0bd14b4fd72afd5df41e9fd59f356740f22fceba (patch)
treebf1bc8dfa507ca40970927efb2dd87b4f5bdd416 /kernel/user_namespace.c
parentc61a2810a2161986353705b44d9503e6bb079f4f (diff)
userns: Allow any uid or gid mappings that don't overlap.
When I initially wrote the code for /proc/<pid>/uid_map. I was lazy and avoided duplicate mappings by the simple expedient of ensuring the first number in a new extent was greater than any number in the previous extent. Unfortunately that precludes a number of valid mappings, and someone noticed and complained. So use a simple check to ensure that ranges in the mapping extents don't overlap. Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r--kernel/user_namespace.c45
1 files changed, 39 insertions, 6 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 24f8ec3b64d8..8b650837083e 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -520,6 +520,42 @@ struct seq_operations proc_projid_seq_operations = {
520 .show = projid_m_show, 520 .show = projid_m_show,
521}; 521};
522 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
523static DEFINE_MUTEX(id_map_mutex); 559static DEFINE_MUTEX(id_map_mutex);
524 560
525static ssize_t map_write(struct file *file, const char __user *buf, 561static ssize_t map_write(struct file *file, const char __user *buf,
@@ -532,7 +568,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
532 struct user_namespace *ns = seq->private; 568 struct user_namespace *ns = seq->private;
533 struct uid_gid_map new_map; 569 struct uid_gid_map new_map;
534 unsigned idx; 570 unsigned idx;
535 struct uid_gid_extent *extent, *last = NULL; 571 struct uid_gid_extent *extent = NULL;
536 unsigned long page = 0; 572 unsigned long page = 0;
537 char *kbuf, *pos, *next_line; 573 char *kbuf, *pos, *next_line;
538 ssize_t ret = -EINVAL; 574 ssize_t ret = -EINVAL;
@@ -635,14 +671,11 @@ static ssize_t map_write(struct file *file, const char __user *buf,
635 if ((extent->lower_first + extent->count) <= extent->lower_first) 671 if ((extent->lower_first + extent->count) <= extent->lower_first)
636 goto out; 672 goto out;
637 673
638 /* For now only accept extents that are strictly in order */ 674 /* Do the ranges in extent overlap any previous extents? */
639 if (last && 675 if (mappings_overlap(&new_map, extent))
640 (((last->first + last->count) > extent->first) ||
641 ((last->lower_first + last->count) > extent->lower_first)))
642 goto out; 676 goto out;
643 677
644 new_map.nr_extents++; 678 new_map.nr_extents++;
645 last = extent;
646 679
647 /* Fail if the file contains too many extents */ 680 /* Fail if the file contains too many extents */
648 if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) && 681 if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) &&