aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-25 19:00:49 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-25 19:00:49 -0500
commit94f2f14234178f118545a0be60a6371ddeb229b7 (patch)
tree313af6e9e255e9060fc24c836cd71ce712502b17 /kernel
parent8d168f71551ec2a6528d01d0389b7a73c091e3e7 (diff)
parent139321c65c0584cd65c4c87a5eb3fdb4fdbd0e19 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull user namespace and namespace infrastructure changes from Eric W Biederman: "This set of changes starts with a few small enhnacements to the user namespace. reboot support, allowing more arbitrary mappings, and support for mounting devpts, ramfs, tmpfs, and mqueuefs as just the user namespace root. I do my best to document that if you care about limiting your unprivileged users that when you have the user namespace support enabled you will need to enable memory control groups. There is a minor bug fix to prevent overflowing the stack if someone creates way too many user namespaces. The bulk of the changes are a continuation of the kuid/kgid push down work through the filesystems. These changes make using uids and gids typesafe which ensures that these filesystems are safe to use when multiple user namespaces are in use. The filesystems converted for 3.9 are ceph, 9p, afs, ocfs2, gfs2, ncpfs, nfs, nfsd, and cifs. The changes for these filesystems were a little more involved so I split the changes into smaller hopefully obviously correct changes. XFS is the only filesystem that remains. I was hoping I could get that in this release so that user namespace support would be enabled with an allyesconfig or an allmodconfig but it looks like the xfs changes need another couple of days before it they are ready." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (93 commits) cifs: Enable building with user namespaces enabled. cifs: Convert struct cifs_ses to use a kuid_t and a kgid_t cifs: Convert struct cifs_sb_info to use kuids and kgids cifs: Modify struct smb_vol to use kuids and kgids cifs: Convert struct cifsFileInfo to use a kuid cifs: Convert struct cifs_fattr to use kuid and kgids cifs: Convert struct tcon_link to use a kuid. cifs: Modify struct cifs_unix_set_info_args to hold a kuid_t and a kgid_t cifs: Convert from a kuid before printing current_fsuid cifs: Use kuids and kgids SID to uid/gid mapping cifs: Pass GLOBAL_ROOT_UID and GLOBAL_ROOT_GID to keyring_alloc cifs: Use BUILD_BUG_ON to validate uids and gids are the same size cifs: Override unmappable incoming uids and gids nfsd: Enable building with user namespaces enabled. nfsd: Properly compare and initialize kuids and kgids nfsd: Store ex_anon_uid and ex_anon_gid as kuids and kgids nfsd: Modify nfsd4_cb_sec to use kuids and kgids nfsd: Handle kuids and kgids in the nfs4acl to posix_acl conversion nfsd: Convert nfsxdr to use kuids and kgids nfsd: Convert nfs3xdr to use kuids and kgids ...
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sys.c5
-rw-r--r--kernel/user.c4
-rw-r--r--kernel/user_namespace.c62
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);
434SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, 434SYSCALL_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
107void free_user_ns(struct kref *kref) 107void 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}
117EXPORT_SYMBOL(free_user_ns); 118EXPORT_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
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
522static DEFINE_MUTEX(id_map_mutex); 559static DEFINE_MUTEX(id_map_mutex);
523 560
524static ssize_t map_write(struct file *file, const char __user *buf, 561static 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) &&