struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; 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++) { gid_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; } 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); } 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) { 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)) return -EFAULT; grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* 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) { 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)) return -EFAULT; grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; } /* 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; gid_t tmp = GROUP_AT(group_info, right); while (left >= 0 && 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; } } /* a simple bsearch */ int groups_search(const struct group_info *group_info, gid_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 - left)/2; if (grp > GROUP_AT(group_info, mid)) left = mid + 1; else if (grp < GROUP_AT(group_info, mid)) right = mid; else return 1; } return 0; } /** * 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 * * Validate a group subscription and, if valid, insert it into a set * of credentials. */ int 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; return 0; } 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; int ret; new = prepare_creds(); if (!new) return -ENOMEM; ret = set_groups(new, group_info); if (ret < 0) { abort_creds(new); return ret; } return commit_creds(new); } 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; } /* * 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 (!nsown_capable(CAP_SETGID)) 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(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred->fsgid) retval = groups_search(cred->group_info, grp); return retval; } EXPORT_SYMBOL(in_group_p); int in_egroup_p(gid_t grp) { const struct cred *cred = current_cred(); int retval = 1; if (grp != cred->egid) retval = groups_search(cred->group_info, grp); return retval;
Standard input is empty
prog.c:1:8: error: variable 'init_groups' has initializer but incomplete type
struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
^
prog.c:1:8: error: unknown field 'usage' specified in initializer
prog.c:1:8: warning: implicit declaration of function 'ATOMIC_INIT' [-Wimplicit-function-declaration]
prog.c:1:8: warning: excess elements in struct initializer
prog.c:1:8: warning: (near initialization for 'init_groups')
prog.c: In function 'groups_alloc':
prog.c:9:29: error: 'NGROUPS_PER_BLOCK' undeclared (first use in this function)
nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK;
^
prog.c:9:29: note: each undeclared identifier is reported only once for each function it appears in
prog.c:12:5: warning: implicit declaration of function 'kmalloc' [-Wimplicit-function-declaration]
group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
^
prog.c:12:33: error: dereferencing pointer to incomplete type
group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
^
prog.c:12:63: error: 'gid_t' undeclared (first use in this function)
group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
^
prog.c:12:70: error: expected expression before ')' token
group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
^
prog.c:12:73: error: 'GFP_USER' undeclared (first use in this function)
group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
^
prog.c:14:16: error: 'NULL' undeclared (first use in this function)
return NULL;
^
prog.c:16:15: error: dereferencing pointer to incomplete type
group_info->ngroups = gidsetsize;
^
prog.c:17:15: error: dereferencing pointer to incomplete type
group_info->nblocks = nblocks;
^
prog.c:18:5: warning: implicit declaration of function 'atomic_set' [-Wimplicit-function-declaration]
atomic_set(&group_info->usage, 1);
^
prog.c:18:27: error: dereferencing pointer to incomplete type
atomic_set(&group_info->usage, 1);
^
prog.c:20:23: error: 'NGROUPS_SMALL' undeclared (first use in this function)
if (gidsetsize <= NGROUPS_SMALL)
^
prog.c:21:19: error: dereferencing pointer to incomplete type
group_info->blocks[0] = group_info->small_block;
^
prog.c:21:43: error: dereferencing pointer to incomplete type
group_info->blocks[0] = group_info->small_block;
^
prog.c:24:20: error: 'b' undeclared (first use in this function)
gid_t *b;
^
prog.c:25:13: warning: implicit declaration of function '__get_free_page' [-Wimplicit-function-declaration]
b = (void *)__get_free_page(GFP_USER);
^
prog.c:28:23: error: dereferencing pointer to incomplete type
group_info->blocks[i] = b;
^
prog.c:38:9: warning: implicit declaration of function 'free_page' [-Wimplicit-function-declaration]
free_page((unsigned long)group_info->blocks[i]);
^
prog.c:38:44: error: dereferencing pointer to incomplete type
free_page((unsigned long)group_info->blocks[i]);
^
prog.c:42:5: warning: implicit declaration of function 'kfree' [-Wimplicit-function-declaration]
kfree(group_info);
^
prog.c: At top level:
prog.c:50:1: warning: data definition has no type or storage class
EXPORT_SYMBOL(groups_alloc);
^
prog.c:50:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:50:1: warning: parameter names (without types) in function declaration
prog.c: In function 'groups_free':
prog.c:58:19: error: dereferencing pointer to incomplete type
if (group_info->blocks[0] != group_info->small_block) {
^
prog.c:58:44: error: dereferencing pointer to incomplete type
if (group_info->blocks[0] != group_info->small_block) {
^
prog.c:62:35: error: dereferencing pointer to incomplete type
for (i = 0; i < group_info->nblocks; i++)
^
prog.c:64:48: error: dereferencing pointer to incomplete type
free_page((unsigned long)group_info->blocks[i]);
^
prog.c: At top level:
prog.c:74:1: warning: data definition has no type or storage class
EXPORT_SYMBOL(groups_free);
^
prog.c:74:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:74:1: warning: parameter names (without types) in function declaration
prog.c:80:27: error: unknown type name 'gid_t'
static int groups_to_user(gid_t __user *grouplist,
^
prog.c:122:5: error: unknown type name 'gid_t'
gid_t __user *grouplist)
^
prog.c: In function 'groups_sort':
prog.c:166:32: error: dereferencing pointer to incomplete type
int gidsetsize = group_info->ngroups;
^
prog.c:188:13: error: unknown type name 'gid_t'
gid_t tmp = GROUP_AT(group_info, right);
^
prog.c:188:13: warning: implicit declaration of function 'GROUP_AT' [-Wimplicit-function-declaration]
prog.c:194:45: error: lvalue required as left operand of assignment
GROUP_AT(group_info, right) =
^
prog.c:204:41: error: lvalue required as left operand of assignment
GROUP_AT(group_info, right) = tmp;
^
prog.c: At top level:
prog.c:218:56: error: unknown type name 'gid_t'
int groups_search(const struct group_info *group_info, gid_t grp)
^
prog.c:276:41: warning: 'struct cred' declared inside parameter list
int set_groups(struct cred *new, struct group_info *group_info)
^
prog.c:276:41: warning: its scope is only this definition or declaration, which is probably not what you want
prog.c: In function 'set_groups':
prog.c:280:5: warning: implicit declaration of function 'put_group_info' [-Wimplicit-function-declaration]
put_group_info(new->group_info);
^
prog.c:280:23: error: dereferencing pointer to incomplete type
put_group_info(new->group_info);
^
prog.c:284:5: warning: implicit declaration of function 'get_group_info' [-Wimplicit-function-declaration]
get_group_info(group_info);
^
prog.c:286:8: error: dereferencing pointer to incomplete type
new->group_info = group_info;
^
prog.c: At top level:
prog.c:294:1: warning: data definition has no type or storage class
EXPORT_SYMBOL(set_groups);
^
prog.c:294:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:294:1: warning: parameter names (without types) in function declaration
prog.c: In function 'set_current_groups':
prog.c:322:5: warning: implicit declaration of function 'prepare_creds' [-Wimplicit-function-declaration]
new = prepare_creds();
^
prog.c:322:9: warning: assignment makes pointer from integer without a cast
new = prepare_creds();
^
prog.c:326:17: error: 'ENOMEM' undeclared (first use in this function)
return -ENOMEM;
^
prog.c:330:22: warning: passing argument 1 of 'set_groups' from incompatible pointer type
ret = set_groups(new, group_info);
^
prog.c:276:5: note: expected 'struct cred *' but argument is of type 'struct cred *'
int set_groups(struct cred *new, struct group_info *group_info)
^
prog.c:334:9: warning: implicit declaration of function 'abort_creds' [-Wimplicit-function-declaration]
abort_creds(new);
^
prog.c:342:5: warning: implicit declaration of function 'commit_creds' [-Wimplicit-function-declaration]
return commit_creds(new);
^
prog.c: At top level:
prog.c:348:1: warning: data definition has no type or storage class
EXPORT_SYMBOL(set_current_groups);
^
prog.c:348:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:348:1: warning: parameter names (without types) in function declaration
prog.c:352:28: error: expected ')' before 'int'
SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist)
^
prog.c:410:28: error: expected ')' before 'int'
SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
^
prog.c:466:16: error: unknown type name 'gid_t'
int in_group_p(gid_t grp)
^
prog.c:486:1: warning: data definition has no type or storage class
EXPORT_SYMBOL(in_group_p);
^
prog.c:486:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:486:1: warning: parameter names (without types) in function declaration
prog.c:490:17: error: unknown type name 'gid_t'
int in_egroup_p(gid_t grp)
^
Standard output is empty