diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sys.c | 5 | ||||
-rw-r--r-- | kernel/user.c | 4 | ||||
-rw-r--r-- | kernel/user_namespace.c | 62 |
3 files changed, 52 insertions, 19 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 840cfdad7bfc..2e18d33ca775 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -434,11 +434,12 @@ static DEFINE_MUTEX(reboot_mutex); | |||
434 | SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, | 434 | SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, |
435 | void __user *, arg) | 435 | void __user *, arg) |
436 | { | 436 | { |
437 | struct pid_namespace *pid_ns = task_active_pid_ns(current); | ||
437 | char buffer[256]; | 438 | char buffer[256]; |
438 | int ret = 0; | 439 | int ret = 0; |
439 | 440 | ||
440 | /* We only trust the superuser with rebooting the system. */ | 441 | /* We only trust the superuser with rebooting the system. */ |
441 | if (!capable(CAP_SYS_BOOT)) | 442 | if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) |
442 | return -EPERM; | 443 | return -EPERM; |
443 | 444 | ||
444 | /* For safety, we require "magic" arguments. */ | 445 | /* For safety, we require "magic" arguments. */ |
@@ -454,7 +455,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, | |||
454 | * pid_namespace, the command is handled by reboot_pid_ns() which will | 455 | * pid_namespace, the command is handled by reboot_pid_ns() which will |
455 | * call do_exit(). | 456 | * call do_exit(). |
456 | */ | 457 | */ |
457 | ret = reboot_pid_ns(task_active_pid_ns(current), cmd); | 458 | ret = reboot_pid_ns(pid_ns, cmd); |
458 | if (ret) | 459 | if (ret) |
459 | return ret; | 460 | return ret; |
460 | 461 | ||
diff --git a/kernel/user.c b/kernel/user.c index 33acb5e53a5f..57ebfd42023c 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -47,9 +47,7 @@ struct user_namespace init_user_ns = { | |||
47 | .count = 4294967295U, | 47 | .count = 4294967295U, |
48 | }, | 48 | }, |
49 | }, | 49 | }, |
50 | .kref = { | 50 | .count = ATOMIC_INIT(3), |
51 | .refcount = ATOMIC_INIT(3), | ||
52 | }, | ||
53 | .owner = GLOBAL_ROOT_UID, | 51 | .owner = GLOBAL_ROOT_UID, |
54 | .group = GLOBAL_ROOT_GID, | 52 | .group = GLOBAL_ROOT_GID, |
55 | .proc_inum = PROC_USER_INIT_INO, | 53 | .proc_inum = PROC_USER_INIT_INO, |
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 | ||
107 | void free_user_ns(struct kref *kref) | 107 | void 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 | } |
117 | EXPORT_SYMBOL(free_user_ns); | 118 | EXPORT_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 | ||
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 | |||
522 | static DEFINE_MUTEX(id_map_mutex); | 559 | static DEFINE_MUTEX(id_map_mutex); |
523 | 560 | ||
524 | 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, |
@@ -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) && |