diff options
Diffstat (limited to 'kernel/user_namespace.c')
| -rw-r--r-- | kernel/user_namespace.c | 349 |
1 files changed, 291 insertions, 58 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index d32b45662fb6..246d4d4ce5c7 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
| 24 | #include <linux/projid.h> | 24 | #include <linux/projid.h> |
| 25 | #include <linux/fs_struct.h> | 25 | #include <linux/fs_struct.h> |
| 26 | #include <linux/bsearch.h> | ||
| 27 | #include <linux/sort.h> | ||
| 26 | 28 | ||
| 27 | static struct kmem_cache *user_ns_cachep __read_mostly; | 29 | static struct kmem_cache *user_ns_cachep __read_mostly; |
| 28 | static DEFINE_MUTEX(userns_state_mutex); | 30 | static DEFINE_MUTEX(userns_state_mutex); |
| @@ -181,6 +183,18 @@ static void free_user_ns(struct work_struct *work) | |||
| 181 | do { | 183 | do { |
| 182 | struct ucounts *ucounts = ns->ucounts; | 184 | struct ucounts *ucounts = ns->ucounts; |
| 183 | parent = ns->parent; | 185 | parent = ns->parent; |
| 186 | if (ns->gid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) { | ||
| 187 | kfree(ns->gid_map.forward); | ||
| 188 | kfree(ns->gid_map.reverse); | ||
| 189 | } | ||
| 190 | if (ns->uid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) { | ||
| 191 | kfree(ns->uid_map.forward); | ||
| 192 | kfree(ns->uid_map.reverse); | ||
| 193 | } | ||
| 194 | if (ns->projid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) { | ||
| 195 | kfree(ns->projid_map.forward); | ||
| 196 | kfree(ns->projid_map.reverse); | ||
| 197 | } | ||
| 184 | retire_userns_sysctls(ns); | 198 | retire_userns_sysctls(ns); |
| 185 | #ifdef CONFIG_PERSISTENT_KEYRINGS | 199 | #ifdef CONFIG_PERSISTENT_KEYRINGS |
| 186 | key_put(ns->persistent_keyring_register); | 200 | key_put(ns->persistent_keyring_register); |
| @@ -198,26 +212,101 @@ void __put_user_ns(struct user_namespace *ns) | |||
| 198 | } | 212 | } |
| 199 | EXPORT_SYMBOL(__put_user_ns); | 213 | EXPORT_SYMBOL(__put_user_ns); |
| 200 | 214 | ||
| 201 | static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count) | 215 | /** |
| 216 | * idmap_key struct holds the information necessary to find an idmapping in a | ||
| 217 | * sorted idmap array. It is passed to cmp_map_id() as first argument. | ||
| 218 | */ | ||
| 219 | struct idmap_key { | ||
| 220 | bool map_up; /* true -> id from kid; false -> kid from id */ | ||
| 221 | u32 id; /* id to find */ | ||
| 222 | u32 count; /* == 0 unless used with map_id_range_down() */ | ||
| 223 | }; | ||
| 224 | |||
| 225 | /** | ||
| 226 | * cmp_map_id - Function to be passed to bsearch() to find the requested | ||
| 227 | * idmapping. Expects struct idmap_key to be passed via @k. | ||
| 228 | */ | ||
| 229 | static int cmp_map_id(const void *k, const void *e) | ||
| 202 | { | 230 | { |
| 203 | unsigned idx, extents; | 231 | u32 first, last, id2; |
| 232 | const struct idmap_key *key = k; | ||
| 233 | const struct uid_gid_extent *el = e; | ||
| 234 | |||
| 235 | id2 = key->id + key->count - 1; | ||
| 236 | |||
| 237 | /* handle map_id_{down,up}() */ | ||
| 238 | if (key->map_up) | ||
| 239 | first = el->lower_first; | ||
| 240 | else | ||
| 241 | first = el->first; | ||
| 242 | |||
| 243 | last = first + el->count - 1; | ||
| 244 | |||
| 245 | if (key->id >= first && key->id <= last && | ||
| 246 | (id2 >= first && id2 <= last)) | ||
| 247 | return 0; | ||
| 248 | |||
| 249 | if (key->id < first || id2 < first) | ||
| 250 | return -1; | ||
| 251 | |||
| 252 | return 1; | ||
| 253 | } | ||
| 254 | |||
| 255 | /** | ||
| 256 | * map_id_range_down_max - Find idmap via binary search in ordered idmap array. | ||
| 257 | * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS. | ||
| 258 | */ | ||
| 259 | static struct uid_gid_extent * | ||
| 260 | map_id_range_down_max(unsigned extents, struct uid_gid_map *map, u32 id, u32 count) | ||
| 261 | { | ||
| 262 | struct idmap_key key; | ||
| 263 | |||
| 264 | key.map_up = false; | ||
| 265 | key.count = count; | ||
| 266 | key.id = id; | ||
| 267 | |||
| 268 | return bsearch(&key, map->forward, extents, | ||
| 269 | sizeof(struct uid_gid_extent), cmp_map_id); | ||
| 270 | } | ||
| 271 | |||
| 272 | /** | ||
| 273 | * map_id_range_down_base - Find idmap via binary search in static extent array. | ||
| 274 | * Can only be called if number of mappings is equal or less than | ||
| 275 | * UID_GID_MAP_MAX_BASE_EXTENTS. | ||
| 276 | */ | ||
| 277 | static struct uid_gid_extent * | ||
| 278 | map_id_range_down_base(unsigned extents, struct uid_gid_map *map, u32 id, u32 count) | ||
| 279 | { | ||
| 280 | unsigned idx; | ||
| 204 | u32 first, last, id2; | 281 | u32 first, last, id2; |
| 205 | 282 | ||
| 206 | id2 = id + count - 1; | 283 | id2 = id + count - 1; |
| 207 | 284 | ||
| 208 | /* Find the matching extent */ | 285 | /* Find the matching extent */ |
| 209 | extents = map->nr_extents; | ||
| 210 | smp_rmb(); | ||
| 211 | for (idx = 0; idx < extents; idx++) { | 286 | for (idx = 0; idx < extents; idx++) { |
| 212 | first = map->extent[idx].first; | 287 | first = map->extent[idx].first; |
| 213 | last = first + map->extent[idx].count - 1; | 288 | last = first + map->extent[idx].count - 1; |
| 214 | if (id >= first && id <= last && | 289 | if (id >= first && id <= last && |
| 215 | (id2 >= first && id2 <= last)) | 290 | (id2 >= first && id2 <= last)) |
| 216 | break; | 291 | return &map->extent[idx]; |
| 217 | } | 292 | } |
| 293 | return NULL; | ||
| 294 | } | ||
| 295 | |||
| 296 | static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count) | ||
| 297 | { | ||
| 298 | struct uid_gid_extent *extent; | ||
| 299 | unsigned extents = map->nr_extents; | ||
| 300 | smp_rmb(); | ||
| 301 | |||
| 302 | if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS) | ||
| 303 | extent = map_id_range_down_base(extents, map, id, count); | ||
| 304 | else | ||
| 305 | extent = map_id_range_down_max(extents, map, id, count); | ||
| 306 | |||
| 218 | /* Map the id or note failure */ | 307 | /* Map the id or note failure */ |
| 219 | if (idx < extents) | 308 | if (extent) |
| 220 | id = (id - first) + map->extent[idx].lower_first; | 309 | id = (id - extent->first) + extent->lower_first; |
| 221 | else | 310 | else |
| 222 | id = (u32) -1; | 311 | id = (u32) -1; |
| 223 | 312 | ||
| @@ -226,44 +315,61 @@ static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count) | |||
| 226 | 315 | ||
| 227 | static u32 map_id_down(struct uid_gid_map *map, u32 id) | 316 | static u32 map_id_down(struct uid_gid_map *map, u32 id) |
| 228 | { | 317 | { |
| 229 | unsigned idx, extents; | 318 | return map_id_range_down(map, id, 1); |
| 319 | } | ||
| 320 | |||
| 321 | /** | ||
| 322 | * map_id_up_base - Find idmap via binary search in static extent array. | ||
| 323 | * Can only be called if number of mappings is equal or less than | ||
| 324 | * UID_GID_MAP_MAX_BASE_EXTENTS. | ||
| 325 | */ | ||
| 326 | static struct uid_gid_extent * | ||
| 327 | map_id_up_base(unsigned extents, struct uid_gid_map *map, u32 id) | ||
| 328 | { | ||
| 329 | unsigned idx; | ||
| 230 | u32 first, last; | 330 | u32 first, last; |
| 231 | 331 | ||
| 232 | /* Find the matching extent */ | 332 | /* Find the matching extent */ |
| 233 | extents = map->nr_extents; | ||
| 234 | smp_rmb(); | ||
| 235 | for (idx = 0; idx < extents; idx++) { | 333 | for (idx = 0; idx < extents; idx++) { |
| 236 | first = map->extent[idx].first; | 334 | first = map->extent[idx].lower_first; |
| 237 | last = first + map->extent[idx].count - 1; | 335 | last = first + map->extent[idx].count - 1; |
| 238 | if (id >= first && id <= last) | 336 | if (id >= first && id <= last) |
| 239 | break; | 337 | return &map->extent[idx]; |
| 240 | } | 338 | } |
| 241 | /* Map the id or note failure */ | 339 | return NULL; |
| 242 | if (idx < extents) | 340 | } |
| 243 | id = (id - first) + map->extent[idx].lower_first; | ||
| 244 | else | ||
| 245 | id = (u32) -1; | ||
| 246 | 341 | ||
| 247 | return id; | 342 | /** |
| 343 | * map_id_up_max - Find idmap via binary search in ordered idmap array. | ||
| 344 | * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS. | ||
| 345 | */ | ||
| 346 | static struct uid_gid_extent * | ||
| 347 | map_id_up_max(unsigned extents, struct uid_gid_map *map, u32 id) | ||
| 348 | { | ||
| 349 | struct idmap_key key; | ||
| 350 | |||
| 351 | key.map_up = true; | ||
| 352 | key.count = 1; | ||
| 353 | key.id = id; | ||
| 354 | |||
| 355 | return bsearch(&key, map->reverse, extents, | ||
| 356 | sizeof(struct uid_gid_extent), cmp_map_id); | ||
| 248 | } | 357 | } |
| 249 | 358 | ||
| 250 | static u32 map_id_up(struct uid_gid_map *map, u32 id) | 359 | static u32 map_id_up(struct uid_gid_map *map, u32 id) |
| 251 | { | 360 | { |
| 252 | unsigned idx, extents; | 361 | struct uid_gid_extent *extent; |
| 253 | u32 first, last; | 362 | unsigned extents = map->nr_extents; |
| 254 | |||
| 255 | /* Find the matching extent */ | ||
| 256 | extents = map->nr_extents; | ||
| 257 | smp_rmb(); | 363 | smp_rmb(); |
| 258 | for (idx = 0; idx < extents; idx++) { | 364 | |
| 259 | first = map->extent[idx].lower_first; | 365 | if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS) |
| 260 | last = first + map->extent[idx].count - 1; | 366 | extent = map_id_up_base(extents, map, id); |
| 261 | if (id >= first && id <= last) | 367 | else |
| 262 | break; | 368 | extent = map_id_up_max(extents, map, id); |
| 263 | } | 369 | |
| 264 | /* Map the id or note failure */ | 370 | /* Map the id or note failure */ |
| 265 | if (idx < extents) | 371 | if (extent) |
| 266 | id = (id - first) + map->extent[idx].first; | 372 | id = (id - extent->lower_first) + extent->first; |
| 267 | else | 373 | else |
| 268 | id = (u32) -1; | 374 | id = (u32) -1; |
| 269 | 375 | ||
| @@ -540,13 +646,17 @@ static int projid_m_show(struct seq_file *seq, void *v) | |||
| 540 | static void *m_start(struct seq_file *seq, loff_t *ppos, | 646 | static void *m_start(struct seq_file *seq, loff_t *ppos, |
| 541 | struct uid_gid_map *map) | 647 | struct uid_gid_map *map) |
| 542 | { | 648 | { |
| 543 | struct uid_gid_extent *extent = NULL; | ||
| 544 | loff_t pos = *ppos; | 649 | loff_t pos = *ppos; |
| 650 | unsigned extents = map->nr_extents; | ||
| 651 | smp_rmb(); | ||
| 545 | 652 | ||
| 546 | if (pos < map->nr_extents) | 653 | if (pos >= extents) |
| 547 | extent = &map->extent[pos]; | 654 | return NULL; |
| 548 | 655 | ||
| 549 | return extent; | 656 | if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS) |
| 657 | return &map->extent[pos]; | ||
| 658 | |||
| 659 | return &map->forward[pos]; | ||
| 550 | } | 660 | } |
| 551 | 661 | ||
| 552 | static void *uid_m_start(struct seq_file *seq, loff_t *ppos) | 662 | static void *uid_m_start(struct seq_file *seq, loff_t *ppos) |
| @@ -618,7 +728,10 @@ static bool mappings_overlap(struct uid_gid_map *new_map, | |||
| 618 | u32 prev_upper_last, prev_lower_last; | 728 | u32 prev_upper_last, prev_lower_last; |
| 619 | struct uid_gid_extent *prev; | 729 | struct uid_gid_extent *prev; |
| 620 | 730 | ||
| 621 | prev = &new_map->extent[idx]; | 731 | if (new_map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) |
| 732 | prev = &new_map->extent[idx]; | ||
| 733 | else | ||
| 734 | prev = &new_map->forward[idx]; | ||
| 622 | 735 | ||
| 623 | prev_upper_first = prev->first; | 736 | prev_upper_first = prev->first; |
| 624 | prev_lower_first = prev->lower_first; | 737 | prev_lower_first = prev->lower_first; |
| @@ -638,6 +751,101 @@ static bool mappings_overlap(struct uid_gid_map *new_map, | |||
| 638 | return false; | 751 | return false; |
| 639 | } | 752 | } |
| 640 | 753 | ||
| 754 | /** | ||
| 755 | * insert_extent - Safely insert a new idmap extent into struct uid_gid_map. | ||
| 756 | * Takes care to allocate a 4K block of memory if the number of mappings exceeds | ||
| 757 | * UID_GID_MAP_MAX_BASE_EXTENTS. | ||
| 758 | */ | ||
| 759 | static int insert_extent(struct uid_gid_map *map, struct uid_gid_extent *extent) | ||
| 760 | { | ||
| 761 | struct uid_gid_extent *dest; | ||
| 762 | |||
| 763 | if (map->nr_extents == UID_GID_MAP_MAX_BASE_EXTENTS) { | ||
| 764 | struct uid_gid_extent *forward; | ||
| 765 | |||
| 766 | /* Allocate memory for 340 mappings. */ | ||
| 767 | forward = kmalloc(sizeof(struct uid_gid_extent) * | ||
| 768 | UID_GID_MAP_MAX_EXTENTS, GFP_KERNEL); | ||
| 769 | if (!forward) | ||
| 770 | return -ENOMEM; | ||
| 771 | |||
| 772 | /* Copy over memory. Only set up memory for the forward pointer. | ||
| 773 | * Defer the memory setup for the reverse pointer. | ||
| 774 | */ | ||
| 775 | memcpy(forward, map->extent, | ||
| 776 | map->nr_extents * sizeof(map->extent[0])); | ||
| 777 | |||
| 778 | map->forward = forward; | ||
| 779 | map->reverse = NULL; | ||
| 780 | } | ||
| 781 | |||
| 782 | if (map->nr_extents < UID_GID_MAP_MAX_BASE_EXTENTS) | ||
| 783 | dest = &map->extent[map->nr_extents]; | ||
| 784 | else | ||
| 785 | dest = &map->forward[map->nr_extents]; | ||
| 786 | |||
| 787 | *dest = *extent; | ||
| 788 | map->nr_extents++; | ||
| 789 | return 0; | ||
| 790 | } | ||
| 791 | |||
| 792 | /* cmp function to sort() forward mappings */ | ||
| 793 | static int cmp_extents_forward(const void *a, const void *b) | ||
| 794 | { | ||
| 795 | const struct uid_gid_extent *e1 = a; | ||
| 796 | const struct uid_gid_extent *e2 = b; | ||
| 797 | |||
| 798 | if (e1->first < e2->first) | ||
| 799 | return -1; | ||
| 800 | |||
| 801 | if (e1->first > e2->first) | ||
| 802 | return 1; | ||
| 803 | |||
| 804 | return 0; | ||
| 805 | } | ||
| 806 | |||
| 807 | /* cmp function to sort() reverse mappings */ | ||
| 808 | static int cmp_extents_reverse(const void *a, const void *b) | ||
| 809 | { | ||
| 810 | const struct uid_gid_extent *e1 = a; | ||
| 811 | const struct uid_gid_extent *e2 = b; | ||
| 812 | |||
| 813 | if (e1->lower_first < e2->lower_first) | ||
| 814 | return -1; | ||
| 815 | |||
| 816 | if (e1->lower_first > e2->lower_first) | ||
| 817 | return 1; | ||
| 818 | |||
| 819 | return 0; | ||
| 820 | } | ||
| 821 | |||
| 822 | /** | ||
| 823 | * sort_idmaps - Sorts an array of idmap entries. | ||
| 824 | * Can only be called if number of mappings exceeds UID_GID_MAP_MAX_BASE_EXTENTS. | ||
| 825 | */ | ||
| 826 | static int sort_idmaps(struct uid_gid_map *map) | ||
| 827 | { | ||
| 828 | if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) | ||
| 829 | return 0; | ||
| 830 | |||
| 831 | /* Sort forward array. */ | ||
| 832 | sort(map->forward, map->nr_extents, sizeof(struct uid_gid_extent), | ||
| 833 | cmp_extents_forward, NULL); | ||
| 834 | |||
| 835 | /* Only copy the memory from forward we actually need. */ | ||
| 836 | map->reverse = kmemdup(map->forward, | ||
| 837 | map->nr_extents * sizeof(struct uid_gid_extent), | ||
| 838 | GFP_KERNEL); | ||
| 839 | if (!map->reverse) | ||
| 840 | return -ENOMEM; | ||
| 841 | |||
| 842 | /* Sort reverse array. */ | ||
| 843 | sort(map->reverse, map->nr_extents, sizeof(struct uid_gid_extent), | ||
| 844 | cmp_extents_reverse, NULL); | ||
| 845 | |||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 641 | static ssize_t map_write(struct file *file, const char __user *buf, | 849 | static ssize_t map_write(struct file *file, const char __user *buf, |
| 642 | size_t count, loff_t *ppos, | 850 | size_t count, loff_t *ppos, |
| 643 | int cap_setid, | 851 | int cap_setid, |
| @@ -648,7 +856,7 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
| 648 | struct user_namespace *ns = seq->private; | 856 | struct user_namespace *ns = seq->private; |
| 649 | struct uid_gid_map new_map; | 857 | struct uid_gid_map new_map; |
| 650 | unsigned idx; | 858 | unsigned idx; |
| 651 | struct uid_gid_extent *extent = NULL; | 859 | struct uid_gid_extent extent; |
| 652 | char *kbuf = NULL, *pos, *next_line; | 860 | char *kbuf = NULL, *pos, *next_line; |
| 653 | ssize_t ret = -EINVAL; | 861 | ssize_t ret = -EINVAL; |
| 654 | 862 | ||
| @@ -673,6 +881,8 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
| 673 | */ | 881 | */ |
| 674 | mutex_lock(&userns_state_mutex); | 882 | mutex_lock(&userns_state_mutex); |
| 675 | 883 | ||
| 884 | memset(&new_map, 0, sizeof(struct uid_gid_map)); | ||
| 885 | |||
| 676 | ret = -EPERM; | 886 | ret = -EPERM; |
| 677 | /* Only allow one successful write to the map */ | 887 | /* Only allow one successful write to the map */ |
| 678 | if (map->nr_extents != 0) | 888 | if (map->nr_extents != 0) |
| @@ -700,9 +910,7 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
| 700 | /* Parse the user data */ | 910 | /* Parse the user data */ |
| 701 | ret = -EINVAL; | 911 | ret = -EINVAL; |
| 702 | pos = kbuf; | 912 | pos = kbuf; |
| 703 | new_map.nr_extents = 0; | ||
| 704 | for (; pos; pos = next_line) { | 913 | for (; pos; pos = next_line) { |
| 705 | extent = &new_map.extent[new_map.nr_extents]; | ||
| 706 | 914 | ||
| 707 | /* Find the end of line and ensure I don't look past it */ | 915 | /* Find the end of line and ensure I don't look past it */ |
| 708 | next_line = strchr(pos, '\n'); | 916 | next_line = strchr(pos, '\n'); |
| @@ -714,17 +922,17 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
| 714 | } | 922 | } |
| 715 | 923 | ||
| 716 | pos = skip_spaces(pos); | 924 | pos = skip_spaces(pos); |
| 717 | extent->first = simple_strtoul(pos, &pos, 10); | 925 | extent.first = simple_strtoul(pos, &pos, 10); |
| 718 | if (!isspace(*pos)) | 926 | if (!isspace(*pos)) |
| 719 | goto out; | 927 | goto out; |
| 720 | 928 | ||
| 721 | pos = skip_spaces(pos); | 929 | pos = skip_spaces(pos); |
| 722 | extent->lower_first = simple_strtoul(pos, &pos, 10); | 930 | extent.lower_first = simple_strtoul(pos, &pos, 10); |
| 723 | if (!isspace(*pos)) | 931 | if (!isspace(*pos)) |
| 724 | goto out; | 932 | goto out; |
| 725 | 933 | ||
| 726 | pos = skip_spaces(pos); | 934 | pos = skip_spaces(pos); |
| 727 | extent->count = simple_strtoul(pos, &pos, 10); | 935 | extent.count = simple_strtoul(pos, &pos, 10); |
| 728 | if (*pos && !isspace(*pos)) | 936 | if (*pos && !isspace(*pos)) |
| 729 | goto out; | 937 | goto out; |
| 730 | 938 | ||
| @@ -734,29 +942,31 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
| 734 | goto out; | 942 | goto out; |
| 735 | 943 | ||
| 736 | /* Verify we have been given valid starting values */ | 944 | /* Verify we have been given valid starting values */ |
| 737 | if ((extent->first == (u32) -1) || | 945 | if ((extent.first == (u32) -1) || |
| 738 | (extent->lower_first == (u32) -1)) | 946 | (extent.lower_first == (u32) -1)) |
| 739 | goto out; | 947 | goto out; |
| 740 | 948 | ||
| 741 | /* Verify count is not zero and does not cause the | 949 | /* Verify count is not zero and does not cause the |
| 742 | * extent to wrap | 950 | * extent to wrap |
| 743 | */ | 951 | */ |
| 744 | if ((extent->first + extent->count) <= extent->first) | 952 | if ((extent.first + extent.count) <= extent.first) |
| 745 | goto out; | 953 | goto out; |
| 746 | if ((extent->lower_first + extent->count) <= | 954 | if ((extent.lower_first + extent.count) <= |
| 747 | extent->lower_first) | 955 | extent.lower_first) |
| 748 | goto out; | 956 | goto out; |
| 749 | 957 | ||
| 750 | /* Do the ranges in extent overlap any previous extents? */ | 958 | /* Do the ranges in extent overlap any previous extents? */ |
| 751 | if (mappings_overlap(&new_map, extent)) | 959 | if (mappings_overlap(&new_map, &extent)) |
| 752 | goto out; | 960 | goto out; |
| 753 | 961 | ||
| 754 | new_map.nr_extents++; | 962 | if ((new_map.nr_extents + 1) == UID_GID_MAP_MAX_EXTENTS && |
| 755 | |||
| 756 | /* Fail if the file contains too many extents */ | ||
| 757 | if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) && | ||
| 758 | (next_line != NULL)) | 963 | (next_line != NULL)) |
| 759 | goto out; | 964 | goto out; |
| 965 | |||
| 966 | ret = insert_extent(&new_map, &extent); | ||
| 967 | if (ret < 0) | ||
| 968 | goto out; | ||
| 969 | ret = -EINVAL; | ||
| 760 | } | 970 | } |
| 761 | /* Be very certaint the new map actually exists */ | 971 | /* Be very certaint the new map actually exists */ |
| 762 | if (new_map.nr_extents == 0) | 972 | if (new_map.nr_extents == 0) |
| @@ -767,16 +977,26 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
| 767 | if (!new_idmap_permitted(file, ns, cap_setid, &new_map)) | 977 | if (!new_idmap_permitted(file, ns, cap_setid, &new_map)) |
| 768 | goto out; | 978 | goto out; |
| 769 | 979 | ||
| 980 | ret = sort_idmaps(&new_map); | ||
| 981 | if (ret < 0) | ||
| 982 | goto out; | ||
| 983 | |||
| 984 | ret = -EPERM; | ||
| 770 | /* Map the lower ids from the parent user namespace to the | 985 | /* Map the lower ids from the parent user namespace to the |
| 771 | * kernel global id space. | 986 | * kernel global id space. |
| 772 | */ | 987 | */ |
| 773 | for (idx = 0; idx < new_map.nr_extents; idx++) { | 988 | for (idx = 0; idx < new_map.nr_extents; idx++) { |
| 989 | struct uid_gid_extent *e; | ||
| 774 | u32 lower_first; | 990 | u32 lower_first; |
| 775 | extent = &new_map.extent[idx]; | 991 | |
| 992 | if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) | ||
| 993 | e = &new_map.extent[idx]; | ||
| 994 | else | ||
| 995 | e = &new_map.forward[idx]; | ||
| 776 | 996 | ||
| 777 | lower_first = map_id_range_down(parent_map, | 997 | lower_first = map_id_range_down(parent_map, |
| 778 | extent->lower_first, | 998 | e->lower_first, |
| 779 | extent->count); | 999 | e->count); |
| 780 | 1000 | ||
| 781 | /* Fail if we can not map the specified extent to | 1001 | /* Fail if we can not map the specified extent to |
| 782 | * the kernel global id space. | 1002 | * the kernel global id space. |
| @@ -784,18 +1004,31 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
| 784 | if (lower_first == (u32) -1) | 1004 | if (lower_first == (u32) -1) |
| 785 | goto out; | 1005 | goto out; |
| 786 | 1006 | ||
| 787 | extent->lower_first = lower_first; | 1007 | e->lower_first = lower_first; |
| 788 | } | 1008 | } |
| 789 | 1009 | ||
| 790 | /* Install the map */ | 1010 | /* Install the map */ |
| 791 | memcpy(map->extent, new_map.extent, | 1011 | if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) { |
| 792 | new_map.nr_extents*sizeof(new_map.extent[0])); | 1012 | memcpy(map->extent, new_map.extent, |
| 1013 | new_map.nr_extents * sizeof(new_map.extent[0])); | ||
| 1014 | } else { | ||
| 1015 | map->forward = new_map.forward; | ||
| 1016 | map->reverse = new_map.reverse; | ||
| 1017 | } | ||
| 793 | smp_wmb(); | 1018 | smp_wmb(); |
| 794 | map->nr_extents = new_map.nr_extents; | 1019 | map->nr_extents = new_map.nr_extents; |
| 795 | 1020 | ||
| 796 | *ppos = count; | 1021 | *ppos = count; |
| 797 | ret = count; | 1022 | ret = count; |
| 798 | out: | 1023 | out: |
| 1024 | if (ret < 0 && new_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) { | ||
| 1025 | kfree(new_map.forward); | ||
| 1026 | kfree(new_map.reverse); | ||
| 1027 | map->forward = NULL; | ||
| 1028 | map->reverse = NULL; | ||
| 1029 | map->nr_extents = 0; | ||
| 1030 | } | ||
| 1031 | |||
| 799 | mutex_unlock(&userns_state_mutex); | 1032 | mutex_unlock(&userns_state_mutex); |
| 800 | kfree(kbuf); | 1033 | kfree(kbuf); |
| 801 | return ret; | 1034 | return ret; |
