diff options
| author | Eric W. Biederman <ebiederm@xmission.com> | 2012-12-28 01:27:29 -0500 |
|---|---|---|
| committer | Eric W. Biederman <ebiederm@xmission.com> | 2013-01-27 01:12:04 -0500 |
| commit | 0bd14b4fd72afd5df41e9fd59f356740f22fceba (patch) | |
| tree | bf1bc8dfa507ca40970927efb2dd87b4f5bdd416 /kernel | |
| parent | c61a2810a2161986353705b44d9503e6bb079f4f (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')
| -rw-r--r-- | kernel/user_namespace.c | 45 |
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 | ||
| 523 | static 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 | |||
| 523 | static DEFINE_MUTEX(id_map_mutex); | 559 | static DEFINE_MUTEX(id_map_mutex); |
| 524 | 560 | ||
| 525 | static ssize_t map_write(struct file *file, const char __user *buf, | 561 | static 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) && |
