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

Commit ae2975bc authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

userns: Convert group_info values from gid_t to kgid_t.



As a first step to converting struct cred to be all kuid_t and kgid_t
values convert the group values stored in group_info to always be
kgid_t values.   Unless user namespaces are used this change should
have no effect.

Acked-by: default avatarSerge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
parent 22d917d8
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -173,11 +173,14 @@ asmlinkage long sys32_setfsgid16(u16 gid)

static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
{
	struct user_namespace *user_ns = current_user_ns();
	int i;
	u16 group;
	kgid_t kgid;

	for (i = 0; i < group_info->ngroups; i++) {
		group = (u16)GROUP_AT(group_info, i);
		kgid = GROUP_AT(group_info, i);
		group = (u16)from_kgid_munged(user_ns, kgid);
		if (put_user(group, grouplist+i))
			return -EFAULT;
	}
@@ -187,13 +190,20 @@ static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info

static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
{
	struct user_namespace *user_ns = current_user_ns();
	int i;
	u16 group;
	kgid_t kgid;

	for (i = 0; i < group_info->ngroups; i++) {
		if (get_user(group, grouplist+i))
			return  -EFAULT;
		GROUP_AT(group_info, i) = (gid_t)group;

		kgid = make_kgid(user_ns, (gid_t)group);
		if (!gid_valid(kgid))
			return -EINVAL;

		GROUP_AT(group_info, i) = kgid;
	}

	return 0;
+3 −2
Original line number Diff line number Diff line
/* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */

#include <linux/sched.h>
#include <linux/user_namespace.h>
#include "nfsd.h"
#include "auth.h"

@@ -56,8 +57,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
			goto oom;

		for (i = 0; i < rqgi->ngroups; i++) {
			if (!GROUP_AT(rqgi, i))
				GROUP_AT(gi, i) = exp->ex_anon_gid;
			if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i)))
				GROUP_AT(gi, i) = make_kgid(&init_user_ns, exp->ex_anon_gid);
			else
				GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
		}
+4 −1
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@
#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/tracehook.h>
#include <linux/user_namespace.h>

#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -161,6 +162,7 @@ static inline const char *get_task_state(struct task_struct *tsk)
static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
				struct pid *pid, struct task_struct *p)
{
	struct user_namespace *user_ns = current_user_ns();
	struct group_info *group_info;
	int g;
	struct fdtable *fdt = NULL;
@@ -205,7 +207,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
	task_unlock(p);

	for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
		seq_printf(m, "%d ", GROUP_AT(group_info, g));
		seq_printf(m, "%d ",
			   from_kgid_munged(user_ns, GROUP_AT(group_info, g)));
	put_cred(cred);

	seq_putc(m, '\n');
+5 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/key.h>
#include <linux/selinux.h>
#include <linux/atomic.h>
#include <linux/uidgid.h>

struct user_struct;
struct cred;
@@ -26,14 +27,14 @@ struct inode;
 * COW Supplementary groups list
 */
#define NGROUPS_SMALL		32
#define NGROUPS_PER_BLOCK	((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
#define NGROUPS_PER_BLOCK	((unsigned int)(PAGE_SIZE / sizeof(kgid_t)))

struct group_info {
	atomic_t	usage;
	int		ngroups;
	int		nblocks;
	gid_t		small_block[NGROUPS_SMALL];
	gid_t		*blocks[0];
	kgid_t		small_block[NGROUPS_SMALL];
	kgid_t		*blocks[0];
};

/**
@@ -66,7 +67,7 @@ extern struct group_info init_groups;
extern void groups_free(struct group_info *);
extern int set_current_groups(struct group_info *);
extern int set_groups(struct cred *, struct group_info *);
extern int groups_search(const struct group_info *, gid_t);
extern int groups_search(const struct group_info *, kgid_t);

/* access the groups "array" with this macro */
#define GROUP_AT(gi, i) \
+25 −23
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ struct group_info *groups_alloc(int gidsetsize)
		group_info->blocks[0] = group_info->small_block;
	else {
		for (i = 0; i < nblocks; i++) {
			gid_t *b;
			kgid_t *b;
			b = (void *)__get_free_page(GFP_USER);
			if (!b)
				goto out_undo_partial_alloc;
@@ -66,18 +66,15 @@ EXPORT_SYMBOL(groups_free);
static int groups_to_user(gid_t __user *grouplist,
			  const struct group_info *group_info)
{
	struct user_namespace *user_ns = current_user_ns();
	int i;
	unsigned int count = group_info->ngroups;

	for (i = 0; i < group_info->nblocks; i++) {
		unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
		unsigned int len = cp_count * sizeof(*grouplist);

		if (copy_to_user(grouplist, group_info->blocks[i], len))
	for (i = 0; i < count; i++) {
		gid_t gid;
		gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i));
		if (put_user(gid, grouplist+i))
			return -EFAULT;

		grouplist += NGROUPS_PER_BLOCK;
		count -= cp_count;
	}
	return 0;
}
@@ -86,18 +83,21 @@ static int groups_to_user(gid_t __user *grouplist,
static int groups_from_user(struct group_info *group_info,
    gid_t __user *grouplist)
{
	struct user_namespace *user_ns = current_user_ns();
	int i;
	unsigned int count = group_info->ngroups;

	for (i = 0; i < group_info->nblocks; i++) {
		unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
		unsigned int len = cp_count * sizeof(*grouplist);

		if (copy_from_user(group_info->blocks[i], grouplist, len))
	for (i = 0; i < count; i++) {
		gid_t gid;
		kgid_t kgid;
		if (get_user(gid, grouplist+i))
			return -EFAULT;

		grouplist += NGROUPS_PER_BLOCK;
		count -= cp_count;
		kgid = make_kgid(user_ns, gid);
		if (!gid_valid(kgid))
			return -EINVAL;

		GROUP_AT(group_info, i) = kgid;
	}
	return 0;
}
@@ -117,9 +117,9 @@ static void groups_sort(struct group_info *group_info)
		for (base = 0; base < max; base++) {
			int left = base;
			int right = left + stride;
			gid_t tmp = GROUP_AT(group_info, right);
			kgid_t tmp = GROUP_AT(group_info, right);

			while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
			while (left >= 0 && gid_gt(GROUP_AT(group_info, left), tmp)) {
				GROUP_AT(group_info, right) =
				    GROUP_AT(group_info, left);
				right = left;
@@ -132,7 +132,7 @@ static void groups_sort(struct group_info *group_info)
}

/* a simple bsearch */
int groups_search(const struct group_info *group_info, gid_t grp)
int groups_search(const struct group_info *group_info, kgid_t grp)
{
	unsigned int left, right;

@@ -143,9 +143,9 @@ int groups_search(const struct group_info *group_info, gid_t grp)
	right = group_info->ngroups;
	while (left < right) {
		unsigned int mid = (left+right)/2;
		if (grp > GROUP_AT(group_info, mid))
		if (gid_gt(grp, GROUP_AT(group_info, mid)))
			left = mid + 1;
		else if (grp < GROUP_AT(group_info, mid))
		else if (gid_lt(grp, GROUP_AT(group_info, mid)))
			right = mid;
		else
			return 1;
@@ -262,7 +262,8 @@ int in_group_p(gid_t grp)
	int retval = 1;

	if (grp != cred->fsgid)
		retval = groups_search(cred->group_info, grp);
		retval = groups_search(cred->group_info,
				       make_kgid(cred->user_ns, grp));
	return retval;
}

@@ -274,7 +275,8 @@ int in_egroup_p(gid_t grp)
	int retval = 1;

	if (grp != cred->egid)
		retval = groups_search(cred->group_info, grp);
		retval = groups_search(cred->group_info,
				       make_kgid(cred->user_ns, grp));
	return retval;
}

Loading