diff options
Diffstat (limited to 'kernel/groups.c')
| -rw-r--r-- | kernel/groups.c | 50 |
1 files changed, 25 insertions, 25 deletions
diff --git a/kernel/groups.c b/kernel/groups.c index 99b53d1eb7ea..6b2588dd04ff 100644 --- a/kernel/groups.c +++ b/kernel/groups.c | |||
| @@ -31,7 +31,7 @@ struct group_info *groups_alloc(int gidsetsize) | |||
| 31 | group_info->blocks[0] = group_info->small_block; | 31 | group_info->blocks[0] = group_info->small_block; |
| 32 | else { | 32 | else { |
| 33 | for (i = 0; i < nblocks; i++) { | 33 | for (i = 0; i < nblocks; i++) { |
| 34 | gid_t *b; | 34 | kgid_t *b; |
| 35 | b = (void *)__get_free_page(GFP_USER); | 35 | b = (void *)__get_free_page(GFP_USER); |
| 36 | if (!b) | 36 | if (!b) |
| 37 | goto out_undo_partial_alloc; | 37 | goto out_undo_partial_alloc; |
| @@ -66,18 +66,15 @@ EXPORT_SYMBOL(groups_free); | |||
| 66 | static int groups_to_user(gid_t __user *grouplist, | 66 | static int groups_to_user(gid_t __user *grouplist, |
| 67 | const struct group_info *group_info) | 67 | const struct group_info *group_info) |
| 68 | { | 68 | { |
| 69 | struct user_namespace *user_ns = current_user_ns(); | ||
| 69 | int i; | 70 | int i; |
| 70 | unsigned int count = group_info->ngroups; | 71 | unsigned int count = group_info->ngroups; |
| 71 | 72 | ||
| 72 | for (i = 0; i < group_info->nblocks; i++) { | 73 | for (i = 0; i < count; i++) { |
| 73 | unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); | 74 | gid_t gid; |
| 74 | unsigned int len = cp_count * sizeof(*grouplist); | 75 | gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i)); |
| 75 | 76 | if (put_user(gid, grouplist+i)) | |
| 76 | if (copy_to_user(grouplist, group_info->blocks[i], len)) | ||
| 77 | return -EFAULT; | 77 | return -EFAULT; |
| 78 | |||
| 79 | grouplist += NGROUPS_PER_BLOCK; | ||
| 80 | count -= cp_count; | ||
| 81 | } | 78 | } |
| 82 | return 0; | 79 | return 0; |
| 83 | } | 80 | } |
| @@ -86,18 +83,21 @@ static int groups_to_user(gid_t __user *grouplist, | |||
| 86 | static int groups_from_user(struct group_info *group_info, | 83 | static int groups_from_user(struct group_info *group_info, |
| 87 | gid_t __user *grouplist) | 84 | gid_t __user *grouplist) |
| 88 | { | 85 | { |
| 86 | struct user_namespace *user_ns = current_user_ns(); | ||
| 89 | int i; | 87 | int i; |
| 90 | unsigned int count = group_info->ngroups; | 88 | unsigned int count = group_info->ngroups; |
| 91 | 89 | ||
| 92 | for (i = 0; i < group_info->nblocks; i++) { | 90 | for (i = 0; i < count; i++) { |
| 93 | unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); | 91 | gid_t gid; |
| 94 | unsigned int len = cp_count * sizeof(*grouplist); | 92 | kgid_t kgid; |
| 95 | 93 | if (get_user(gid, grouplist+i)) | |
| 96 | if (copy_from_user(group_info->blocks[i], grouplist, len)) | ||
| 97 | return -EFAULT; | 94 | return -EFAULT; |
| 98 | 95 | ||
| 99 | grouplist += NGROUPS_PER_BLOCK; | 96 | kgid = make_kgid(user_ns, gid); |
| 100 | count -= cp_count; | 97 | if (!gid_valid(kgid)) |
| 98 | return -EINVAL; | ||
| 99 | |||
| 100 | GROUP_AT(group_info, i) = kgid; | ||
| 101 | } | 101 | } |
| 102 | return 0; | 102 | return 0; |
| 103 | } | 103 | } |
| @@ -117,9 +117,9 @@ static void groups_sort(struct group_info *group_info) | |||
| 117 | for (base = 0; base < max; base++) { | 117 | for (base = 0; base < max; base++) { |
| 118 | int left = base; | 118 | int left = base; |
| 119 | int right = left + stride; | 119 | int right = left + stride; |
| 120 | gid_t tmp = GROUP_AT(group_info, right); | 120 | kgid_t tmp = GROUP_AT(group_info, right); |
| 121 | 121 | ||
| 122 | while (left >= 0 && GROUP_AT(group_info, left) > tmp) { | 122 | while (left >= 0 && gid_gt(GROUP_AT(group_info, left), tmp)) { |
| 123 | GROUP_AT(group_info, right) = | 123 | GROUP_AT(group_info, right) = |
| 124 | GROUP_AT(group_info, left); | 124 | GROUP_AT(group_info, left); |
| 125 | right = left; | 125 | right = left; |
| @@ -132,7 +132,7 @@ static void groups_sort(struct group_info *group_info) | |||
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | /* a simple bsearch */ | 134 | /* a simple bsearch */ |
| 135 | int groups_search(const struct group_info *group_info, gid_t grp) | 135 | int groups_search(const struct group_info *group_info, kgid_t grp) |
| 136 | { | 136 | { |
| 137 | unsigned int left, right; | 137 | unsigned int left, right; |
| 138 | 138 | ||
| @@ -143,9 +143,9 @@ int groups_search(const struct group_info *group_info, gid_t grp) | |||
| 143 | right = group_info->ngroups; | 143 | right = group_info->ngroups; |
| 144 | while (left < right) { | 144 | while (left < right) { |
| 145 | unsigned int mid = (left+right)/2; | 145 | unsigned int mid = (left+right)/2; |
| 146 | if (grp > GROUP_AT(group_info, mid)) | 146 | if (gid_gt(grp, GROUP_AT(group_info, mid))) |
| 147 | left = mid + 1; | 147 | left = mid + 1; |
| 148 | else if (grp < GROUP_AT(group_info, mid)) | 148 | else if (gid_lt(grp, GROUP_AT(group_info, mid))) |
| 149 | right = mid; | 149 | right = mid; |
| 150 | else | 150 | else |
| 151 | return 1; | 151 | return 1; |
| @@ -256,24 +256,24 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) | |||
| 256 | /* | 256 | /* |
| 257 | * Check whether we're fsgid/egid or in the supplemental group.. | 257 | * Check whether we're fsgid/egid or in the supplemental group.. |
| 258 | */ | 258 | */ |
| 259 | int in_group_p(gid_t grp) | 259 | int in_group_p(kgid_t grp) |
| 260 | { | 260 | { |
| 261 | const struct cred *cred = current_cred(); | 261 | const struct cred *cred = current_cred(); |
| 262 | int retval = 1; | 262 | int retval = 1; |
| 263 | 263 | ||
| 264 | if (grp != cred->fsgid) | 264 | if (!gid_eq(grp, cred->fsgid)) |
| 265 | retval = groups_search(cred->group_info, grp); | 265 | retval = groups_search(cred->group_info, grp); |
| 266 | return retval; | 266 | return retval; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | EXPORT_SYMBOL(in_group_p); | 269 | EXPORT_SYMBOL(in_group_p); |
| 270 | 270 | ||
| 271 | int in_egroup_p(gid_t grp) | 271 | int in_egroup_p(kgid_t grp) |
| 272 | { | 272 | { |
| 273 | const struct cred *cred = current_cred(); | 273 | const struct cred *cred = current_cred(); |
| 274 | int retval = 1; | 274 | int retval = 1; |
| 275 | 275 | ||
| 276 | if (grp != cred->egid) | 276 | if (!gid_eq(grp, cred->egid)) |
| 277 | retval = groups_search(cred->group_info, grp); | 277 | retval = groups_search(cred->group_info, grp); |
| 278 | return retval; | 278 | return retval; |
| 279 | } | 279 | } |
