Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6835039d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull user-namespace fixes from Andy Lutomirski.

* 'userns-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/luto/linux:
  userns: Changing any namespace id mappings should require privileges
  userns: Check uid_map's opener's fsuid, not the current fsuid
  userns: Don't let unprivileged users trick privileged users into setting the id_map
parents a86d5266 41c21e35
Loading
Loading
Loading
Loading
+13 −9
Original line number Original line Diff line number Diff line
@@ -25,7 +25,8 @@


static struct kmem_cache *user_ns_cachep __read_mostly;
static struct kmem_cache *user_ns_cachep __read_mostly;


static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
static bool new_idmap_permitted(const struct file *file,
				struct user_namespace *ns, int cap_setid,
				struct uid_gid_map *map);
				struct uid_gid_map *map);


static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
@@ -612,10 +613,10 @@ static ssize_t map_write(struct file *file, const char __user *buf,
	if (map->nr_extents != 0)
	if (map->nr_extents != 0)
		goto out;
		goto out;


	/* Require the appropriate privilege CAP_SETUID or CAP_SETGID
	/*
	 * over the user namespace in order to set the id mapping.
	 * Adjusting namespace settings requires capabilities on the target.
	 */
	 */
	if (cap_valid(cap_setid) && !ns_capable(ns, cap_setid))
	if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
		goto out;
		goto out;


	/* Get a buffer */
	/* Get a buffer */
@@ -700,7 +701,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,


	ret = -EPERM;
	ret = -EPERM;
	/* Validate the user is allowed to use user id's mapped to. */
	/* Validate the user is allowed to use user id's mapped to. */
	if (!new_idmap_permitted(ns, cap_setid, &new_map))
	if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
		goto out;
		goto out;


	/* Map the lower ids from the parent user namespace to the
	/* Map the lower ids from the parent user namespace to the
@@ -787,7 +788,8 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t
			 &ns->projid_map, &ns->parent->projid_map);
			 &ns->projid_map, &ns->parent->projid_map);
}
}


static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
static bool new_idmap_permitted(const struct file *file, 
				struct user_namespace *ns, int cap_setid,
				struct uid_gid_map *new_map)
				struct uid_gid_map *new_map)
{
{
	/* Allow mapping to your own filesystem ids */
	/* Allow mapping to your own filesystem ids */
@@ -795,12 +797,12 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
		u32 id = new_map->extent[0].lower_first;
		u32 id = new_map->extent[0].lower_first;
		if (cap_setid == CAP_SETUID) {
		if (cap_setid == CAP_SETUID) {
			kuid_t uid = make_kuid(ns->parent, id);
			kuid_t uid = make_kuid(ns->parent, id);
			if (uid_eq(uid, current_fsuid()))
			if (uid_eq(uid, file->f_cred->fsuid))
				return true;
				return true;
		}
		}
		else if (cap_setid == CAP_SETGID) {
		else if (cap_setid == CAP_SETGID) {
			kgid_t gid = make_kgid(ns->parent, id);
			kgid_t gid = make_kgid(ns->parent, id);
			if (gid_eq(gid, current_fsgid()))
			if (gid_eq(gid, file->f_cred->fsgid))
				return true;
				return true;
		}
		}
	}
	}
@@ -811,8 +813,10 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,


	/* Allow the specified ids if we have the appropriate capability
	/* Allow the specified ids if we have the appropriate capability
	 * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
	 * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
	 * And the opener of the id file also had the approprpiate capability.
	 */
	 */
	if (ns_capable(ns->parent, cap_setid))
	if (ns_capable(ns->parent, cap_setid) &&
	    file_ns_capable(file, ns->parent, cap_setid))
		return true;
		return true;


	return false;
	return false;