Blame view
kernel/groups.c
4.91 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
30639b6af groups: move code... |
2 3 4 5 |
/* * Supplementary group IDs */ #include <linux/cred.h> |
9984de1a5 kernel: Map most ... |
6 |
#include <linux/export.h> |
30639b6af groups: move code... |
7 8 |
#include <linux/slab.h> #include <linux/security.h> |
b7b2562f7 kernel/groups.c: ... |
9 |
#include <linux/sort.h> |
30639b6af groups: move code... |
10 |
#include <linux/syscalls.h> |
273d2c67c userns: Don't all... |
11 |
#include <linux/user_namespace.h> |
81243eacf cred: simpler, 1D... |
12 |
#include <linux/vmalloc.h> |
7c0f6ba68 Replace <asm/uacc... |
13 |
#include <linux/uaccess.h> |
30639b6af groups: move code... |
14 |
|
30639b6af groups: move code... |
15 16 |
struct group_info *groups_alloc(int gidsetsize) { |
81243eacf cred: simpler, 1D... |
17 18 19 20 21 22 |
struct group_info *gi; unsigned int len; len = sizeof(struct group_info) + sizeof(kgid_t) * gidsetsize; gi = kmalloc(len, GFP_KERNEL_ACCOUNT|__GFP_NOWARN|__GFP_NORETRY); if (!gi) |
88dca4ca5 mm: remove the pg... |
23 |
gi = __vmalloc(len, GFP_KERNEL_ACCOUNT); |
81243eacf cred: simpler, 1D... |
24 |
if (!gi) |
30639b6af groups: move code... |
25 |
return NULL; |
30639b6af groups: move code... |
26 |
|
81243eacf cred: simpler, 1D... |
27 28 29 |
atomic_set(&gi->usage, 1); gi->ngroups = gidsetsize; return gi; |
30639b6af groups: move code... |
30 31 32 33 34 35 |
} EXPORT_SYMBOL(groups_alloc); void groups_free(struct group_info *group_info) { |
81243eacf cred: simpler, 1D... |
36 |
kvfree(group_info); |
30639b6af groups: move code... |
37 38 39 40 41 42 43 44 |
} 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) { |
ae2975bc3 userns: Convert g... |
45 |
struct user_namespace *user_ns = current_user_ns(); |
30639b6af groups: move code... |
46 47 |
int i; unsigned int count = group_info->ngroups; |
ae2975bc3 userns: Convert g... |
48 49 |
for (i = 0; i < count; i++) { gid_t gid; |
81243eacf cred: simpler, 1D... |
50 |
gid = from_kgid_munged(user_ns, group_info->gid[i]); |
ae2975bc3 userns: Convert g... |
51 |
if (put_user(gid, grouplist+i)) |
30639b6af groups: move code... |
52 |
return -EFAULT; |
30639b6af groups: move code... |
53 54 55 56 57 58 59 60 |
} 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) { |
ae2975bc3 userns: Convert g... |
61 |
struct user_namespace *user_ns = current_user_ns(); |
30639b6af groups: move code... |
62 63 |
int i; unsigned int count = group_info->ngroups; |
ae2975bc3 userns: Convert g... |
64 65 66 67 |
for (i = 0; i < count; i++) { gid_t gid; kgid_t kgid; if (get_user(gid, grouplist+i)) |
30639b6af groups: move code... |
68 |
return -EFAULT; |
ae2975bc3 userns: Convert g... |
69 70 71 |
kgid = make_kgid(user_ns, gid); if (!gid_valid(kgid)) return -EINVAL; |
81243eacf cred: simpler, 1D... |
72 |
group_info->gid[i] = kgid; |
30639b6af groups: move code... |
73 74 75 |
} return 0; } |
b7b2562f7 kernel/groups.c: ... |
76 77 78 79 80 81 82 |
static int gid_cmp(const void *_a, const void *_b) { kgid_t a = *(kgid_t *)_a; kgid_t b = *(kgid_t *)_b; return gid_gt(a, b) - gid_lt(a, b); } |
bdcf0a423 kernel: make grou... |
83 |
void groups_sort(struct group_info *group_info) |
30639b6af groups: move code... |
84 |
{ |
b7b2562f7 kernel/groups.c: ... |
85 86 |
sort(group_info->gid, group_info->ngroups, sizeof(*group_info->gid), gid_cmp, NULL); |
30639b6af groups: move code... |
87 |
} |
bdcf0a423 kernel: make grou... |
88 |
EXPORT_SYMBOL(groups_sort); |
30639b6af groups: move code... |
89 90 |
/* a simple bsearch */ |
ae2975bc3 userns: Convert g... |
91 |
int groups_search(const struct group_info *group_info, kgid_t grp) |
30639b6af groups: move code... |
92 93 94 95 96 97 98 99 100 101 |
{ unsigned int left, right; if (!group_info) return 0; left = 0; right = group_info->ngroups; while (left < right) { unsigned int mid = (left+right)/2; |
81243eacf cred: simpler, 1D... |
102 |
if (gid_gt(grp, group_info->gid[mid])) |
30639b6af groups: move code... |
103 |
left = mid + 1; |
81243eacf cred: simpler, 1D... |
104 |
else if (gid_lt(grp, group_info->gid[mid])) |
30639b6af groups: move code... |
105 106 107 108 109 110 111 112 113 114 115 |
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 |
30639b6af groups: move code... |
116 |
*/ |
8f6c5ffc8 kernel/groups.c: ... |
117 |
void set_groups(struct cred *new, struct group_info *group_info) |
30639b6af groups: move code... |
118 |
{ |
30639b6af groups: move code... |
119 |
put_group_info(new->group_info); |
30639b6af groups: move code... |
120 121 |
get_group_info(group_info); new->group_info = group_info; |
30639b6af groups: move code... |
122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
} 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; |
30639b6af groups: move code... |
136 137 138 139 |
new = prepare_creds(); if (!new) return -ENOMEM; |
8f6c5ffc8 kernel/groups.c: ... |
140 |
set_groups(new, group_info); |
30639b6af groups: move code... |
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
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; } |
7ff4d90b4 groups: Consolida... |
169 170 171 |
bool may_setgroups(void) { struct user_namespace *user_ns = current_user_ns(); |
111767c1d LSM: Signal to Sa... |
172 |
return ns_capable_setid(user_ns, CAP_SETGID) && |
273d2c67c userns: Don't all... |
173 |
userns_may_setgroups(user_ns); |
7ff4d90b4 groups: Consolida... |
174 |
} |
30639b6af groups: move code... |
175 176 177 178 179 180 181 182 183 |
/* * 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; |
7ff4d90b4 groups: Consolida... |
184 |
if (!may_setgroups()) |
30639b6af groups: move code... |
185 186 187 188 189 190 191 192 193 194 195 196 |
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; } |
bdcf0a423 kernel: make grou... |
197 |
groups_sort(group_info); |
30639b6af groups: move code... |
198 199 200 201 202 203 204 205 206 |
retval = set_current_groups(group_info); put_group_info(group_info); return retval; } /* * Check whether we're fsgid/egid or in the supplemental group.. */ |
72cda3d1e userns: Convert i... |
207 |
int in_group_p(kgid_t grp) |
30639b6af groups: move code... |
208 209 210 |
{ const struct cred *cred = current_cred(); int retval = 1; |
72cda3d1e userns: Convert i... |
211 212 |
if (!gid_eq(grp, cred->fsgid)) retval = groups_search(cred->group_info, grp); |
30639b6af groups: move code... |
213 214 215 216 |
return retval; } EXPORT_SYMBOL(in_group_p); |
72cda3d1e userns: Convert i... |
217 |
int in_egroup_p(kgid_t grp) |
30639b6af groups: move code... |
218 219 220 |
{ const struct cred *cred = current_cred(); int retval = 1; |
72cda3d1e userns: Convert i... |
221 222 |
if (!gid_eq(grp, cred->egid)) retval = groups_search(cred->group_info, grp); |
30639b6af groups: move code... |
223 224 225 226 |
return retval; } EXPORT_SYMBOL(in_egroup_p); |