cregit-Linux how code gets into the kernel

Release 4.7 kernel/groups.c

Directory: kernel
/*
 * Supplementary group IDs
 */
#include <linux/cred.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/user_namespace.h>
#include <asm/uaccess.h>


struct group_info *groups_alloc(int gidsetsize) { struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info->ngroups = gidsetsize; group_info->nblocks = nblocks; atomic_set(&group_info->usage, 1); if (gidsetsize <= NGROUPS_SMALL) group_info->blocks[0] = group_info->small_block; else { for (i = 0; i < nblocks; i++) { kgid_t *b; b = (void *)__get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info->blocks[i] = b; } } return group_info; out_undo_partial_alloc: while (--i >= 0) { free_page((unsigned long)group_info->blocks[i]); } kfree(group_info); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan19499.49%150.00%
eric w. biedermaneric w. biederman10.51%150.00%
Total195100.00%2100.00%

EXPORT_SYMBOL(groups_alloc);
void groups_free(struct group_info *group_info) { if (group_info->blocks[0] != group_info->small_block) { int i; for (i = 0; i < group_info->nblocks; i++) free_page((unsigned long)group_info->blocks[i]); } kfree(group_info); }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan62100.00%1100.00%
Total62100.00%1100.00%

EXPORT_SYMBOL(groups_free); /* export the group_info to a user-space array */
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 < count; i++) { gid_t gid; gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i)); if (put_user(gid, grouplist+i)) return -EFAULT; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan6069.77%150.00%
eric w. biedermaneric w. biederman2630.23%150.00%
Total86100.00%2100.00%

/* fill a group_info from a user-space array - it must be allocated already */
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 < count; i++) { gid_t gid; kgid_t kgid; if (get_user(gid, grouplist+i)) return -EFAULT; kgid = make_kgid(user_ns, gid); if (!gid_valid(kgid)) return -EINVAL; GROUP_AT(group_info, i) = kgid; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan5956.73%150.00%
eric w. biedermaneric w. biederman4543.27%150.00%
Total104100.00%2100.00%

/* a simple Shell sort */
static void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize = group_info->ngroups; for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base < max; base++) { int left = base; int right = left + stride; kgid_t tmp = GROUP_AT(group_info, right); while (left >= 0 && gid_gt(GROUP_AT(group_info, left), tmp)) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride; } GROUP_AT(group_info, right) = tmp; } stride /= 3; } }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan14896.73%150.00%
eric w. biedermaneric w. biederman53.27%150.00%
Total153100.00%2100.00%

/* a simple bsearch */
int groups_search(const struct group_info *group_info, kgid_t grp) { unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info->ngroups; while (left < right) { unsigned int mid = (left+right)/2; if (gid_gt(grp, GROUP_AT(group_info, mid))) left = mid + 1; else if (gid_lt(grp, GROUP_AT(group_info, mid))) right = mid; else return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan8682.69%133.33%
eric w. biedermaneric w. biederman98.65%133.33%
jerome marchandjerome marchand98.65%133.33%
Total104100.00%3100.00%

/** * set_groups - Change a group subscription in a set of credentials * @new: The newly prepared set of credentials to alter * @group_info: The group list to install */
void set_groups(struct cred *new, struct group_info *group_info) { put_group_info(new->group_info); groups_sort(group_info); get_group_info(group_info); new->group_info = group_info; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan3797.37%150.00%
wang yanqingwang yanqing12.63%150.00%
Total38100.00%2100.00%

EXPORT_SYMBOL(set_groups); /** * set_current_groups - Change current's group subscription * @group_info: The group list to impose * * Validate a group subscription and, if valid, impose it upon current's task * security record. */
int set_current_groups(struct group_info *group_info) { struct cred *new; new = prepare_creds(); if (!new) return -ENOMEM; set_groups(new, group_info); return commit_creds(new); }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan42100.00%1100.00%
Total42100.00%1100.00%

EXPORT_SYMBOL(set_current_groups); SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist) { const struct cred *cred = current_cred(); int i; if (gidsetsize < 0) return -EINVAL; /* no need to grab task_lock here; it cannot change */ i = cred->group_info->ngroups; if (gidsetsize) { if (i > gidsetsize) { i = -EINVAL; goto out; } if (groups_to_user(grouplist, cred->group_info)) { i = -EFAULT; goto out; } } out: return i; }
bool may_setgroups(void) { struct user_namespace *user_ns = current_user_ns(); return ns_capable(user_ns, CAP_SETGID) && userns_may_setgroups(user_ns); }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman28100.00%2100.00%
Total28100.00%2100.00%

/* * SMP: Our groups are copy-on-write. We can set them safely * without another task interfering. */ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) { struct group_info *group_info; int retval; if (!may_setgroups()) return -EPERM; if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */
int in_group_p(kgid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (!gid_eq(grp, cred->fsgid)) retval = groups_search(cred->group_info, grp); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan4287.50%150.00%
eric w. biedermaneric w. biederman612.50%150.00%
Total48100.00%2100.00%

EXPORT_SYMBOL(in_group_p);
int in_egroup_p(kgid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (!gid_eq(grp, cred->egid)) retval = groups_search(cred->group_info, grp); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan4287.50%150.00%
eric w. biedermaneric w. biederman612.50%150.00%
Total48100.00%2100.00%

EXPORT_SYMBOL(in_egroup_p);

Overall Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan101787.67%111.11%
eric w. biedermaneric w. biederman13111.29%555.56%
jerome marchandjerome marchand90.78%111.11%
wang yanqingwang yanqing20.17%111.11%
paul gortmakerpaul gortmaker10.09%111.11%
Total1160100.00%9100.00%
Directory: kernel
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}